{"spec_id":"frequency-polygon-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nfrequency-polygon-basic: Frequency Polygon for Distribution Comparison\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Background\" + \"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.2)\" if THEME == \"light\" else \"rgba(240, 239, 232, 0.2)\"\n\n# Okabe-Ito palette\nBRAND = \"#009E73\"  # Okabe-Ito position 1 — ALWAYS first series\nOKABE_VERMILLION = \"#C475FD\"  # Okabe-Ito position 2\nOKABE_BLUE = \"#4467A3\"  # Okabe-Ito position 3\n\n# Data - Reaction times (ms) for three experimental conditions\nnp.random.seed(42)\n\n# Control group - normal distribution centered around 350ms\ncontrol = np.random.normal(loc=350, scale=60, size=200)\n\n# Caffeine group - faster reactions, centered around 280ms\ncaffeine = np.random.normal(loc=280, scale=50, size=200)\n\n# Sleep deprived group - slower and more variable reactions\nsleep_deprived = np.random.normal(loc=450, scale=90, size=200)\n\n# Define consistent bins for all groups\nbin_edges = np.linspace(100, 700, 31)\nbin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2\n\n# Calculate frequency for each group\ncontrol_freq, _ = np.histogram(control, bins=bin_edges)\ncaffeine_freq, _ = np.histogram(caffeine, bins=bin_edges)\nsleep_deprived_freq, _ = np.histogram(sleep_deprived, bins=bin_edges)\n\n# Extend to zero at both ends to close polygon\nextended_centers = np.concatenate([[bin_edges[0]], bin_centers, [bin_edges[-1]]])\ncontrol_extended = np.concatenate([[0], control_freq, [0]])\ncaffeine_extended = np.concatenate([[0], caffeine_freq, [0]])\nsleep_deprived_extended = np.concatenate([[0], sleep_deprived_freq, [0]])\n\n# Create figure\nfig = go.Figure()\n\n# Add frequency polygons with semi-transparent fill\nfig.add_trace(\n    go.Scatter(\n        x=extended_centers,\n        y=control_extended,\n        mode=\"lines+markers\",\n        name=\"Control\",\n        line={\"color\": BRAND, \"width\": 4},\n        marker={\"size\": 10, \"color\": BRAND},\n        fill=\"tozeroy\",\n        fillcolor=\"rgba(0, 158, 115, 0.2)\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=extended_centers,\n        y=caffeine_extended,\n        mode=\"lines+markers\",\n        name=\"Caffeine\",\n        line={\"color\": OKABE_VERMILLION, \"width\": 4},\n        marker={\"size\": 10, \"color\": OKABE_VERMILLION},\n        fill=\"tozeroy\",\n        fillcolor=\"rgba(196, 117, 253, 0.2)\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=extended_centers,\n        y=sleep_deprived_extended,\n        mode=\"lines+markers\",\n        name=\"Sleep Deprived\",\n        line={\"color\": OKABE_BLUE, \"width\": 4, \"dash\": \"dash\"},\n        marker={\"size\": 10, \"color\": OKABE_BLUE},\n        fill=\"tozeroy\",\n        fillcolor=\"rgba(68, 103, 163, 0.2)\",\n    )\n)\n\n# Update layout with theme-adaptive colors\nfig.update_layout(\n    title={\n        \"text\": \"frequency-polygon-basic · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Reaction Time (ms)\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n        \"range\": [80, 720],\n    },\n    yaxis={\n        \"title\": {\"text\": \"Frequency\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n    },\n    legend={\n        \"font\": {\"size\": 16, \"color\": INK_SOFT},\n        \"x\": 0.98,\n        \"y\": 0.98,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"top\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    margin={\"l\": 80, \"r\": 60, \"t\": 100, \"b\": 80},\n)\n\n# Save as PNG and HTML with theme suffix\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}