{"spec_id":"network-hierarchical","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nnetwork-hierarchical: Hierarchical Network Graph with Tree Layout\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Okabe-Ito palette - first series is always #009E73\nIMPRINT = [\n    \"#009E73\",  # bluish green (brand)\n    \"#C475FD\",  # vermillion\n    \"#4467A3\",  # blue\n    \"#BD8233\",  # reddish purple\n    \"#AE3030\",  # orange\n]\n\n# Apply seaborn theme\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n    },\n)\n\n# Data: File system directory structure\n# Root: /project with subdirectories for src, config, tests, docs, build\nnodes = [\n    # Level 0 - Root\n    {\"id\": 0, \"label\": \"project/\", \"level\": 0, \"type\": \"dir\"},\n    # Level 1 - Main directories\n    {\"id\": 1, \"label\": \"src/\", \"level\": 1, \"type\": \"dir\"},\n    {\"id\": 2, \"label\": \"config/\", \"level\": 1, \"type\": \"dir\"},\n    {\"id\": 3, \"label\": \"tests/\", \"level\": 1, \"type\": \"dir\"},\n    {\"id\": 4, \"label\": \"docs/\", \"level\": 1, \"type\": \"dir\"},\n    {\"id\": 5, \"label\": \"build/\", \"level\": 1, \"type\": \"dir\"},\n    # Level 2 - Source subdirectories\n    {\"id\": 6, \"label\": \"components/\", \"level\": 2, \"type\": \"dir\"},\n    {\"id\": 7, \"label\": \"utils/\", \"level\": 2, \"type\": \"dir\"},\n    {\"id\": 8, \"label\": \"models/\", \"level\": 2, \"type\": \"dir\"},\n    # Level 2 - Config files\n    {\"id\": 9, \"label\": \"settings.yaml\", \"level\": 2, \"type\": \"file\"},\n    {\"id\": 10, \"label\": \"env.json\", \"level\": 2, \"type\": \"file\"},\n    # Level 2 - Test subdirectories\n    {\"id\": 11, \"label\": \"unit/\", \"level\": 2, \"type\": \"dir\"},\n    {\"id\": 12, \"label\": \"integration/\", \"level\": 2, \"type\": \"dir\"},\n    # Level 2 - Docs files\n    {\"id\": 13, \"label\": \"api/\", \"level\": 2, \"type\": \"dir\"},\n    {\"id\": 14, \"label\": \"guide.md\", \"level\": 2, \"type\": \"file\"},\n    # Level 3 - Component files\n    {\"id\": 15, \"label\": \"button.py\", \"level\": 3, \"type\": \"file\"},\n    {\"id\": 16, \"label\": \"input.py\", \"level\": 3, \"type\": \"file\"},\n    {\"id\": 17, \"label\": \"form.py\", \"level\": 3, \"type\": \"file\"},\n    # Level 3 - Utility files\n    {\"id\": 18, \"label\": \"helpers.py\", \"level\": 3, \"type\": \"file\"},\n    {\"id\": 19, \"label\": \"validators.py\", \"level\": 3, \"type\": \"file\"},\n    # Level 3 - Model files\n    {\"id\": 20, \"label\": \"user.py\", \"level\": 3, \"type\": \"file\"},\n    {\"id\": 21, \"label\": \"data.py\", \"level\": 3, \"type\": \"file\"},\n]\n\nedges = [\n    # Root to Level 1\n    (0, 1),\n    (0, 2),\n    (0, 3),\n    (0, 4),\n    (0, 5),\n    # src to subdirectories\n    (1, 6),\n    (1, 7),\n    (1, 8),\n    # config to files\n    (2, 9),\n    (2, 10),\n    # tests to subdirectories\n    (3, 11),\n    (3, 12),\n    # docs to contents\n    (4, 13),\n    (4, 14),\n    # components to files\n    (6, 15),\n    (6, 16),\n    (6, 17),\n    # utils to files\n    (7, 18),\n    (7, 19),\n    # models to files\n    (8, 20),\n    (8, 21),\n]\n\n# Compute hierarchical layout positions\nlevels = {}\nfor node in nodes:\n    lvl = node[\"level\"]\n    if lvl not in levels:\n        levels[lvl] = []\n    levels[lvl].append(node)\n\n# Calculate positions: levels spread vertically, nodes at each level spread horizontally\npositions = {}\ny_spacing = 2.0\nfor lvl in sorted(levels.keys()):\n    nodes_at_level = levels[lvl]\n    n = len(nodes_at_level)\n    spread = max(n * 1.5, 6)\n    x_positions = np.linspace(-spread / 2, spread / 2, n)\n    y_pos = -lvl * y_spacing\n    for i, node in enumerate(nodes_at_level):\n        positions[node[\"id\"]] = (x_positions[i], y_pos)\n\n# Prepare data for plotting\nnode_x = [positions[n[\"id\"]][0] for n in nodes]\nnode_y = [positions[n[\"id\"]][1] for n in nodes]\nnode_labels = [n[\"label\"] for n in nodes]\nnode_levels = [n[\"level\"] for n in nodes]\nnode_types = [n[\"type\"] for n in nodes]\n\n# Color mapping: directories vs files\ncolors_by_type = {\n    \"dir\": IMPRINT[0],  # Brand green for directories\n    \"file\": IMPRINT[1],  # Vermillion for files\n}\nnode_colors = [colors_by_type[nt] for nt in node_types]\n\n# Node sizes based on level\nsize_map = {0: 1200, 1: 900, 2: 600, 3: 450}\nnode_sizes = [size_map[lvl] for lvl in node_levels]\n\n# Create figure\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Draw edges first (underneath nodes)\nfor parent, child in edges:\n    x0, y0 = positions[parent]\n    x1, y1 = positions[child]\n    ax.plot([x0, x1], [y0, y1], color=INK_SOFT, linewidth=2.0, alpha=0.4, zorder=1)\n\n# Draw all nodes as a single scatter plot with colors\nax.scatter(node_x, node_y, s=node_sizes, c=node_colors, edgecolors=INK_SOFT, linewidth=2.0, alpha=0.85, zorder=2)\n\n# Add node labels\nfor node in nodes:\n    x, y = positions[node[\"id\"]]\n    lvl = node[\"level\"]\n    fontsize = 18 if lvl == 0 else 16 if lvl == 1 else 13 if lvl == 2 else 11\n    fontweight = \"bold\" if lvl == 0 else \"normal\"\n    ax.annotate(\n        node[\"label\"],\n        (x, y),\n        textcoords=\"offset points\",\n        xytext=(0, -28),\n        ha=\"center\",\n        va=\"top\",\n        fontsize=fontsize,\n        fontweight=fontweight,\n        color=INK,\n    )\n\n# Style the plot\nax.set_title(\"network-hierarchical · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK, pad=20)\n\n# Set axis properties\nax.set_xlabel(\"Directory/File Distribution\", fontsize=20, color=INK)\nax.set_ylabel(\"Directory Depth (Level)\", fontsize=20, color=INK)\nax.set_xticks([])\nax.set_yticks([])\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Set axis limits with padding\nx_padding = 1.5\ny_padding = 1.0\nax.set_xlim(min(node_x) - x_padding, max(node_x) + x_padding)\nax.set_ylim(min(node_y) - y_padding, max(node_y) + y_padding)\n\n# Remove spines for cleaner network visualization\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\n# Disable grid for network visualization\nax.grid(False)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}