{"spec_id":"lollipop-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nlollipop-basic: Basic Lollipop Chart\nLibrary: plotly 6.8.0 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-07-01\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\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\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\nBRAND = \"#009E73\"  # Imprint palette position 1 — ALWAYS first series\nACCENT = \"#C475FD\"  # Imprint palette position 2 — focal point for top performer\n\n# Data — streaming platform monthly watch hours by genre (thousands of hours, sorted descending)\ngenres = [\n    \"Drama\",\n    \"Comedy\",\n    \"Thriller\",\n    \"Action\",\n    \"Documentary\",\n    \"Animation\",\n    \"Romance\",\n    \"Horror\",\n    \"Reality TV\",\n    \"Sci-Fi\",\n]\nwatch_hours = [3840, 2970, 2450, 2180, 1820, 1540, 1280, 990, 820, 650]\n\n# Plot\nfig = go.Figure()\n\n# Accent stem first — anchors Drama as the leftmost category on the x-axis\nfig.add_trace(\n    go.Scatter(\n        x=[genres[0], genres[0], None],\n        y=[0, watch_hours[0], None],\n        mode=\"lines\",\n        line={\"color\": ACCENT, \"width\": 3},\n        showlegend=False,\n        hoverinfo=\"skip\",\n    )\n)\n\n# Standard stems — brand color for positions 1–9 via None-separator trick\nstem_x, stem_y = [], []\nfor genre, hours in zip(genres[1:], watch_hours[1:], strict=True):\n    stem_x.extend([genre, genre, None])\n    stem_y.extend([0, hours, None])\n\nfig.add_trace(\n    go.Scatter(x=stem_x, y=stem_y, mode=\"lines\", line={\"color\": BRAND, \"width\": 3}, showlegend=False, hoverinfo=\"skip\")\n)\n\n# Markers — top performer in accent, rest in brand green\nmarker_colors = [ACCENT] + [BRAND] * (len(genres) - 1)\nfig.add_trace(\n    go.Scatter(\n        x=genres,\n        y=watch_hours,\n        mode=\"markers\",\n        marker={\"color\": marker_colors, \"size\": 22, \"line\": {\"color\": PAGE_BG, \"width\": 2.5}, \"symbol\": \"circle\"},\n        showlegend=False,\n        hovertemplate=\"<b>%{x}</b><br>%{y:,.0f}k hours/month<extra></extra>\",\n        cliponaxis=False,\n    )\n)\n\n# Title fontsize scaled for length (plotly default 16px, floor 11px)\ntitle_text = \"Streaming Hours by Genre · lollipop-basic · python · plotly · anyplot.ai\"\ntitle_fontsize = max(11, round(16 * 67 / len(title_text)))\n\n# Style\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": title_text,\n        \"font\": {\"size\": title_fontsize, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n        \"y\": 0.97,\n    },\n    xaxis={\n        \"title\": {\"text\": \"Content Genre\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"tickangle\": -35,\n        \"showgrid\": False,\n        \"showline\": True,\n        \"mirror\": False,\n        \"linecolor\": INK_SOFT,\n        \"ticks\": \"outside\",\n        \"tickcolor\": INK_SOFT,\n        \"ticklen\": 6,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Watch Hours (thousands/month)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"tickformat\": \",.0f\",\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": True,\n        \"zerolinecolor\": INK_SOFT,\n        \"zerolinewidth\": 1.5,\n        \"showline\": True,\n        \"mirror\": False,\n        \"linecolor\": INK_SOFT,\n        \"range\": [0, max(watch_hours) * 1.12],\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK, \"family\": \"Inter, system-ui, sans-serif\"},\n    margin={\"l\": 110, \"r\": 60, \"t\": 80, \"b\": 140},\n    showlegend=False,\n    hoverlabel={\"bgcolor\": ELEVATED_BG, \"bordercolor\": INK_SOFT, \"font\": {\"color\": INK, \"size\": 14}},\n)\n\n# Save — canonical 3200×1800 landscape canvas\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}