{"spec_id":"arc-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\narc-basic: Basic Arc Diagram\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.colors import LinearSegmentedColormap\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint sequential colormap for 5 arc weight levels (weak=light, strong=dark)\nimprint_seq = LinearSegmentedColormap.from_list(\"imprint_seq\", [\"#009E73\", \"#4467A3\"])\npalette = [imprint_seq(v) for v in [0.1, 0.3, 0.5, 0.7, 0.9]]\n\n# Apply seaborn theme with theme-adaptive chrome\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        \"grid.color\": INK,\n        \"grid.alpha\": 0.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data: Character interactions in a story (12 characters)\nnodes = [\"Alice\", \"Bob\", \"Carol\", \"Dave\", \"Eve\", \"Frank\", \"Grace\", \"Henry\", \"Ivy\", \"Jack\", \"Kate\", \"Leo\"]\nn_nodes = len(nodes)\n\n# Edges: (source_index, target_index, interaction_weight)\nedges = [\n    (0, 1, 5),  # Alice – Bob\n    (0, 3, 2),  # Alice – Dave\n    (1, 2, 4),  # Bob – Carol\n    (1, 4, 3),  # Bob – Eve\n    (2, 5, 2),  # Carol – Frank\n    (3, 4, 5),  # Dave – Eve\n    (3, 6, 3),  # Dave – Grace\n    (4, 7, 4),  # Eve – Henry\n    (5, 6, 2),  # Frank – Grace\n    (0, 11, 1),  # Alice – Leo (long-range)\n    (2, 6, 3),  # Carol – Grace\n    (1, 5, 2),  # Bob – Frank\n    (7, 8, 4),  # Henry – Ivy\n    (8, 9, 3),  # Ivy – Jack\n    (9, 10, 5),  # Jack – Kate\n    (10, 11, 2),  # Kate – Leo\n    (6, 9, 2),  # Grace – Jack\n    (5, 10, 1),  # Frank – Kate (long-range)\n]\n\nx_positions = np.arange(n_nodes)\n\n# Build long-form DataFrame of arc coordinates for seaborn lineplot\narc_rows = []\nn_pts = 80\nfor eid, (src, tgt, w) in enumerate(edges):\n    x1, x2 = x_positions[src], x_positions[tgt]\n    dist = abs(x2 - x1)\n    h = dist * 0.4\n    t = np.linspace(0, np.pi, n_pts)\n    cx, rx = (x1 + x2) / 2, dist / 2\n    arc_x = cx + rx * np.cos(np.pi - t)\n    arc_y = h * np.sin(t)\n    for xi, yi in zip(arc_x, arc_y, strict=True):\n        arc_rows.append({\"x\": xi, \"y\": yi, \"weight\": w, \"edge_id\": eid})\n\narc_df = pd.DataFrame(arc_rows)\n\n# Categorize weights for seaborn hue encoding\nstrength_names = {1: \"1 · Weak\", 2: \"2 · Light\", 3: \"3 · Moderate\", 4: \"4 · Strong\", 5: \"5 · Intense\"}\ncat_order = [strength_names[k] for k in sorted(strength_names)]\narc_df[\"strength\"] = pd.Categorical(arc_df[\"weight\"].map(strength_names), categories=cat_order, ordered=True)\n\n# Canvas — exactly 3200×1800 px (landscape 16:9)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Draw arcs via seaborn lineplot (hue=color by strength, size=thickness by weight)\nsns.lineplot(\n    data=arc_df,\n    x=\"x\",\n    y=\"y\",\n    hue=\"strength\",\n    size=\"weight\",\n    units=\"edge_id\",\n    estimator=None,\n    palette=palette,\n    sizes=(2.0, 5.5),\n    alpha=0.75,\n    ax=ax,\n    sort=False,\n)\n\n# Keep only color legend entries (remove redundant size entries)\nhandles, labels_list = ax.get_legend_handles_labels()\ncat_set = set(cat_order)\nfiltered = [(h, lab) for h, lab in zip(handles, labels_list, strict=True) if lab in cat_set]\nax.legend(\n    [h for h, _ in filtered],\n    [lab for _, lab in filtered],\n    title=\"Interaction Strength\",\n    title_fontsize=8,\n    fontsize=8,\n    loc=\"upper right\",\n    frameon=True,\n    fancybox=False,\n    framealpha=0.9,\n    edgecolor=INK_SOFT,\n    borderpad=1.2,\n)\n\n# Degree-based node sizing — more-connected nodes appear larger for visual hierarchy\ndegree = [0] * n_nodes\nfor src, tgt, _ in edges:\n    degree[src] += 1\n    degree[tgt] += 1\nnode_sizes = [120 + d * 75 for d in degree]\n\n# Draw nodes — Imprint blue (#4467A3) as structural anchors\nnode_df = pd.DataFrame({\"x\": x_positions, \"y\": np.zeros(n_nodes), \"size\": node_sizes})\nsns.scatterplot(\n    data=node_df,\n    x=\"x\",\n    y=\"y\",\n    size=\"size\",\n    sizes=(min(node_sizes), max(node_sizes)),\n    color=\"#4467A3\",\n    zorder=5,\n    ax=ax,\n    legend=False,\n    edgecolor=PAGE_BG,\n    linewidth=1.5,\n)\n\n# Node labels below the baseline\nfor i, name in enumerate(nodes):\n    ax.text(x_positions[i], -0.22, name, ha=\"center\", va=\"top\", fontsize=9, fontweight=\"medium\", color=INK)\n\n# Annotations: contrast between arc distance and weight\nax.annotate(\n    \"Weakest link, longest reach\",\n    xy=(5.5, 4.2),\n    fontsize=8,\n    fontstyle=\"italic\",\n    color=INK_MUTED,\n    ha=\"center\",\n    xytext=(2.0, 4.9),\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_MUTED, \"lw\": 1.0},\n)\nax.annotate(\n    \"Strongest local bonds\",\n    xy=(3.5, 0.42),\n    fontsize=8,\n    fontstyle=\"italic\",\n    color=INK_MUTED,\n    ha=\"center\",\n    xytext=(6.0, 2.0),\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_MUTED, \"lw\": 1.0},\n)\n\n# Axis styling\nax.set_xlim(-0.8, n_nodes - 0.2)\nax.set_ylim(-0.45, 5.6)\nax.set_title(\"arc-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK, pad=12)\nax.set_xlabel(\"\")\nax.set_ylabel(\"\")\nsns.despine(ax=ax, left=True, bottom=True)\nax.set_xticks([])\nax.set_yticks([])\n\n# Subtle horizontal baseline\nax.axhline(y=0, color=INK_SOFT, linewidth=1.5, alpha=0.3, zorder=1)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}