{"spec_id":"heatmap-polar","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nheatmap-polar: Polar Heatmap for Cyclic Two-Dimensional Data\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 89/100 | Created: 2026-05-13\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\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\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Data: website page views by hour of day (angular) and day of week (radial)\nnp.random.seed(42)\ndays = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\nn_days = 7\nn_hours = 24\n\ntraffic = np.zeros((n_days, n_hours))\nfor d in range(n_days):\n    for h in range(n_hours):\n        morning_peak = np.exp(-0.5 * ((h - 9) / 1.5) ** 2)\n        evening_peak = np.exp(-0.5 * ((h - 20) / 2.0) ** 2)\n        lunch_peak = 0.4 * np.exp(-0.5 * ((h - 13) / 1.0) ** 2)\n        if d >= 5:  # weekend: single midday peak\n            traffic[d, h] = 3500 * np.exp(-0.5 * ((h - 13) / 3.5) ** 2) + np.random.normal(0, 80)\n        else:  # weekday: morning + lunch + evening peaks\n            traffic[d, h] = 5500 * (morning_peak + 0.8 * evening_peak + lunch_peak) + np.random.normal(0, 150)\n\ntraffic = np.clip(traffic, 0, None)\nvmin, vmax = traffic.min(), traffic.max()\n\n# Angular layout: 24 hours each occupying 15°, starting at top (midnight), clockwise\nhour_angles = [h * (360.0 / n_hours) for h in range(n_hours)]\nbar_width = 360.0 / n_hours\n\n# Plot\nfig = go.Figure()\n\nfor d, day in enumerate(days):\n    hourly = traffic[d].tolist()\n    fig.add_trace(\n        go.Barpolar(\n            r=[1.0] * n_hours,\n            base=[d] * n_hours,\n            theta=hour_angles,\n            width=[bar_width] * n_hours,\n            marker={\"color\": hourly, \"coloraxis\": \"coloraxis\", \"line\": {\"color\": PAGE_BG, \"width\": 0.5}},\n            name=day,\n            showlegend=False,\n            customdata=np.column_stack([list(range(n_hours)), hourly]),\n            hovertemplate=(\n                f\"<b>{day}</b><br>Hour: %{{customdata[0]:.0f}}:00<br>Page Views: %{{customdata[1]:,.0f}}<extra></extra>\"\n            ),\n        )\n    )\n\n# Style\nangular_tickvals = [h * 15 for h in [0, 3, 6, 9, 12, 15, 18, 21]]\nangular_ticktext = [\"12am\", \"3am\", \"6am\", \"9am\", \"12pm\", \"3pm\", \"6pm\", \"9pm\"]\n\nfig.update_layout(\n    title={\n        \"text\": \"Website Traffic · heatmap-polar · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.44,\n        \"y\": 0.98,\n        \"xanchor\": \"center\",\n        \"yanchor\": \"top\",\n    },\n    polar={\n        \"bgcolor\": PAGE_BG,\n        \"domain\": {\"x\": [0, 0.82], \"y\": [0.02, 0.98]},\n        \"angularaxis\": {\n            \"direction\": \"clockwise\",\n            \"rotation\": 90,\n            \"tickvals\": angular_tickvals,\n            \"ticktext\": angular_ticktext,\n            \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n            \"linecolor\": INK_SOFT,\n            \"gridcolor\": GRID,\n            \"gridwidth\": 1,\n        },\n        \"radialaxis\": {\n            \"range\": [0, n_days],\n            \"tickvals\": [d + 0.5 for d in range(n_days)],\n            \"ticktext\": days,\n            \"tickfont\": {\"size\": 16, \"color\": INK_SOFT},\n            \"gridcolor\": GRID,\n            \"showgrid\": True,\n            \"showline\": False,\n            \"angle\": 45,\n            \"tickangle\": 0,\n        },\n    },\n    coloraxis={\n        \"colorscale\": \"viridis\",\n        \"cmin\": vmin,\n        \"cmax\": vmax,\n        \"colorbar\": {\n            \"title\": {\"text\": \"Page Views\", \"font\": {\"size\": 18, \"color\": INK}},\n            \"tickfont\": {\"size\": 14, \"color\": INK_SOFT},\n            \"bgcolor\": ELEVATED_BG,\n            \"bordercolor\": INK_SOFT,\n            \"borderwidth\": 1,\n            \"thickness\": 25,\n            \"len\": 0.55,\n            \"x\": 0.88,\n            \"y\": 0.5,\n            \"yanchor\": \"middle\",\n        },\n    },\n    paper_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    margin={\"l\": 40, \"r\": 80, \"t\": 60, \"b\": 40},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=1200, height=1200, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}