{"spec_id":"genome-track-multi","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\ngenome-track-multi: Genome Track Viewer\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-06-02\n\"\"\"\n\nimport os\n\nimport matplotlib.lines as mlines\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens (Imprint palette)\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# Imprint categorical palette — canonical order\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\nBRAND = IMPRINT_PALETTE[0]  # #009E73 — always first series\n\n# Seaborn theme with Imprint chrome tokens\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\nnp.random.seed(42)\n\n# Genomic region: chr7, 50 kb window around a kinase gene cluster\nchrom = \"chr7\"\nregion_start = 55_000\nregion_end = 105_000\n\n# Gene track — two protein-coding genes on opposite strands\ngenes = [\n    {\n        \"name\": \"GENEA\",\n        \"strand\": \"+\",\n        \"start\": 58_000,\n        \"end\": 82_000,\n        \"exons\": [(58_000, 60_500), (64_000, 66_000), (70_000, 72_500), (78_000, 82_000)],\n    },\n    {\n        \"name\": \"GENEB\",\n        \"strand\": \"-\",\n        \"start\": 86_000,\n        \"end\": 101_000,\n        \"exons\": [(86_000, 88_500), (92_000, 94_000), (98_000, 101_000)],\n    },\n]\n\n# Coverage track — read depth with exon-correlated peaks (RNA-seq)\npositions = np.arange(region_start, region_end, 100)\nbase_coverage = np.random.poisson(25, len(positions)).astype(float)\nfor gene in genes:\n    for exon_start, exon_end in gene[\"exons\"]:\n        mask = (positions >= exon_start) & (positions <= exon_end)\n        base_coverage[mask] += np.random.poisson(40, mask.sum())\ncoverage = np.convolve(base_coverage, np.ones(5) / 5, mode=\"same\")\ncoverage_df = pd.DataFrame({\"position\": positions, \"depth\": coverage})\n\n# Variant track — SNPs and indels with GATK quality scores\nvariant_df = pd.DataFrame(\n    {\n        \"position\": [59_200, 65_300, 71_800, 79_500, 87_600, 93_200, 99_400, 61_000, 75_000, 95_500],\n        \"type\": [\"SNP\", \"SNP\", \"SNP\", \"SNP\", \"SNP\", \"SNP\", \"SNP\", \"Indel\", \"Indel\", \"Indel\"],\n        \"quality\": [95, 78, 88, 42, 91, 65, 85, 72, 55, 80],\n    }\n)\n\n# Regulatory track — promoters and enhancers from ChIP-seq peaks\nregulatory = [\n    {\"type\": \"Promoter\", \"start\": 56_000, \"end\": 58_000},\n    {\"type\": \"Enhancer\", \"start\": 67_000, \"end\": 69_500},\n    {\"type\": \"Promoter\", \"start\": 84_000, \"end\": 86_000},\n    {\"type\": \"Enhancer\", \"start\": 94_500, \"end\": 97_500},\n]\n\n# Track colors from Imprint palette\ngene_color = BRAND  # #009E73 — first series\nsnp_color = IMPRINT_PALETTE[1]  # #C475FD\nindel_color = IMPRINT_PALETTE[2]  # #4467A3\npromoter_color = IMPRINT_PALETTE[4]  # #AE3030\nenhancer_color = IMPRINT_PALETTE[5]  # #2ABCCD\n\n# Plot — landscape 3200×1800, 4 stacked tracks\nfig, axes = plt.subplots(4, 1, figsize=(8, 4.5), dpi=400, height_ratios=[2.5, 3, 2, 1.8], facecolor=PAGE_BG)\nfig.subplots_adjust(hspace=0.06, left=0.14, right=0.97, top=0.92, bottom=0.10)\n\ntitle = \"genome-track-multi · python · seaborn · anyplot.ai\"\nn = len(title)\ntitle_fs = round(12 * 67 / n) if n > 67 else 12\nfig.suptitle(title, fontsize=title_fs, fontweight=\"medium\", color=INK, y=0.97)\n\n# -- Track 1: Gene annotations --\nax_gene = axes[0]\nax_gene.set_facecolor(PAGE_BG)\nax_gene.set_ylim(-1.5, 2.5)\nax_gene.set_xlim(region_start - 1_000, region_end + 1_000)\n\nfor i, gene in enumerate(genes):\n    y_center = 1.2 * i\n    ax_gene.plot(\n        [gene[\"start\"], gene[\"end\"]], [y_center, y_center], color=gene_color, linewidth=1.5, solid_capstyle=\"butt\"\n    )\n    for exon_start, exon_end in gene[\"exons\"]:\n        rect = mpatches.Rectangle(\n            (exon_start, y_center - 0.35),\n            exon_end - exon_start,\n            0.7,\n            facecolor=gene_color,\n            edgecolor=PAGE_BG,\n            linewidth=0.8,\n        )\n        ax_gene.add_patch(rect)\n    arrow_x = gene[\"end\"] + 800 if gene[\"strand\"] == \"+\" else gene[\"start\"] - 800\n    arrow_dx = 1_200 if gene[\"strand\"] == \"+\" else -1_200\n    ax_gene.annotate(\n        \"\",\n        xy=(arrow_x + arrow_dx, y_center),\n        xytext=(arrow_x, y_center),\n        arrowprops={\"arrowstyle\": \"->\", \"color\": gene_color, \"lw\": 1.5},\n    )\n    label_x = gene[\"end\"] + 2_500 if gene[\"strand\"] == \"+\" else gene[\"start\"] - 2_500\n    ha = \"left\" if gene[\"strand\"] == \"+\" else \"right\"\n    ax_gene.text(\n        label_x,\n        y_center,\n        f\"{gene['name']} ({gene['strand']})\",\n        fontsize=8,\n        fontweight=\"bold\",\n        color=gene_color,\n        va=\"center\",\n        ha=ha,\n    )\n\nax_gene.set_ylabel(\"Genes\", fontsize=10, fontweight=\"medium\", color=INK)\nax_gene.set_yticks([])\nax_gene.set_xticks([])\nsns.despine(ax=ax_gene, left=True, bottom=True)\n\n# -- Track 2: Coverage (seaborn lineplot with filled area) --\nax_cov = axes[1]\nax_cov.set_facecolor(ELEVATED_BG)\nsns.lineplot(data=coverage_df, x=\"position\", y=\"depth\", color=gene_color, linewidth=1.2, ax=ax_cov)\nax_cov.fill_between(coverage_df[\"position\"], coverage_df[\"depth\"], alpha=0.3, color=gene_color)\nax_cov.set_xlim(region_start - 1_000, region_end + 1_000)\nax_cov.set_ylabel(\"Coverage\\n(read depth)\", fontsize=10, fontweight=\"medium\", color=INK)\nax_cov.set_ylim(0, coverage.max() * 1.15)\nax_cov.set_xlabel(\"\")\nax_cov.set_xticks([])\nax_cov.tick_params(axis=\"y\", labelsize=8, colors=INK_SOFT)\nax_cov.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nsns.despine(ax=ax_cov, bottom=True)\n\n# -- Track 3: Variants — seaborn scatterplot with hue, style, and size encoding --\nax_var = axes[2]\nax_var.set_facecolor(PAGE_BG)\nfor _, row in variant_df.iterrows():\n    clr = snp_color if row[\"type\"] == \"SNP\" else indel_color\n    ax_var.plot([row[\"position\"], row[\"position\"]], [0, row[\"quality\"]], color=clr, linewidth=1.2, alpha=0.6)\n# size=\"quality\" encodes confidence as marker area — a distinctive seaborn feature\nsns.scatterplot(\n    data=variant_df,\n    x=\"position\",\n    y=\"quality\",\n    hue=\"type\",\n    style=\"type\",\n    size=\"quality\",\n    sizes=(60, 200),\n    markers={\"SNP\": \"o\", \"Indel\": \"D\"},\n    palette={\"SNP\": snp_color, \"Indel\": indel_color},\n    edgecolor=PAGE_BG,\n    linewidth=0.8,\n    zorder=3,\n    ax=ax_var,\n    legend=False,\n)\nsnp_handle = mlines.Line2D(\n    [], [], color=snp_color, marker=\"o\", markersize=6, linewidth=0, markeredgecolor=PAGE_BG, label=\"SNP\"\n)\nindel_handle = mlines.Line2D(\n    [], [], color=indel_color, marker=\"D\", markersize=6, linewidth=0, markeredgecolor=PAGE_BG, label=\"Indel\"\n)\nax_var.legend(\n    handles=[snp_handle, indel_handle],\n    fontsize=8,\n    loc=\"upper right\",\n    framealpha=0.85,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n)\nax_var.set_xlim(region_start - 1_000, region_end + 1_000)\nax_var.set_ylabel(\"Variants\\n(quality)\", fontsize=10, fontweight=\"medium\", color=INK)\nax_var.set_ylim(0, 115)\nax_var.set_xlabel(\"\")\nax_var.set_xticks([])\nax_var.tick_params(axis=\"y\", labelsize=8, colors=INK_SOFT)\nax_var.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nsns.despine(ax=ax_var, bottom=True)\n\n# -- Track 4: Regulatory elements --\nax_reg = axes[3]\nax_reg.set_facecolor(ELEVATED_BG)\nax_reg.set_ylim(-0.5, 1.5)\nfor reg in regulatory:\n    clr = promoter_color if reg[\"type\"] == \"Promoter\" else enhancer_color\n    rect = mpatches.Rectangle(\n        (reg[\"start\"], 0.15), reg[\"end\"] - reg[\"start\"], 0.7, facecolor=clr, edgecolor=PAGE_BG, linewidth=0.8, alpha=0.9\n    )\n    ax_reg.add_patch(rect)\nprom_handle = mpatches.Patch(color=promoter_color, label=\"Promoter\")\nenh_handle = mpatches.Patch(color=enhancer_color, label=\"Enhancer\")\nax_reg.legend(\n    handles=[prom_handle, enh_handle],\n    fontsize=8,\n    loc=\"upper right\",\n    framealpha=0.85,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n)\nax_reg.set_xlim(region_start - 1_000, region_end + 1_000)\nax_reg.set_ylabel(\"Regulatory\", fontsize=10, fontweight=\"medium\", color=INK)\nax_reg.set_yticks([])\nsns.despine(ax=ax_reg, left=True)\n\n# Shared x-axis — shown on bottom track only\nax_reg.set_xlabel(f\"Genomic Position ({chrom})\", fontsize=10, color=INK)\nax_reg.tick_params(axis=\"x\", labelsize=8, colors=INK_SOFT)\nax_reg.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f\"{x / 1000:.0f}kb\"))\n\n# Save — bbox_inches must stay default (None) to preserve exact 3200×1800\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}