{"spec_id":"heatmap-polar","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nheatmap-polar: Polar Heatmap for Cyclic Two-Dimensional Data\nLibrary: letsplot 4.9.0 | Python 3.13.13\nQuality: 87/100 | Created: 2026-05-13\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    coord_polar,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_tile,\n    ggplot,\n    ggsize,\n    labs,\n    scale_fill_viridis,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\n\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# Data — website traffic by hour of day (angular) and day of week (radial)\nnp.random.seed(42)\n\ndays = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\n\nrecords = []\nfor d_idx, day in enumerate(days):\n    for h in range(24):\n        is_weekend = d_idx >= 5\n        if not is_weekend:\n            if 9 <= h <= 17:\n                base = 750\n            elif (6 <= h <= 8) or (18 <= h <= 21):\n                base = 380\n            else:\n                base = 80\n        else:\n            if 11 <= h <= 20:\n                base = 550\n            elif (21 <= h <= 23) or h == 0:\n                base = 260\n            else:\n                base = 60\n        visits = max(10, int(base + np.random.normal(0, base * 0.10)))\n        records.append({\"day\": day, \"day_num\": d_idx + 1, \"hour_mid\": h + 0.5, \"visits\": visits})\n\ndf = pd.DataFrame(records)\n\n# Theme\nanyplot_theme = theme(\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=PAGE_BG),\n    panel_grid_major=element_blank(),\n    panel_grid_minor=element_blank(),\n    axis_title=element_text(color=INK, size=20),\n    axis_text=element_text(color=INK_SOFT, size=14),\n    axis_ticks=element_blank(),\n    axis_line=element_blank(),\n    plot_title=element_text(color=INK, size=22, face=\"bold\"),\n    legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n    legend_text=element_text(color=INK_SOFT, size=14),\n    legend_title=element_text(color=INK, size=16),\n)\n\n# Plot — polar heatmap: x=hour (angular), y=day_num (radial), fill=visits\nplot = (\n    ggplot(df, aes(x=\"hour_mid\", y=\"day_num\", fill=\"visits\"))\n    + geom_tile(color=PAGE_BG, size=0.5)\n    + coord_polar(theta=\"x\")\n    + scale_fill_viridis(name=\"Hourly\\nVisits\")\n    + scale_x_continuous(\n        breaks=[0.5, 6.5, 12.5, 18.5], labels=[\"12am\", \"6am\", \"12pm\", \"6pm\"], limits=[0, 24], expand=[0, 0]\n    )\n    + scale_y_continuous(breaks=list(range(1, 8)), labels=days, limits=[0, 7.5], expand=[0, 0])\n    + labs(title=\"Website Traffic · heatmap-polar · letsplot · anyplot.ai\", x=\"Hour of Day\", y=\"Day of Week\")\n    + anyplot_theme\n    + ggsize(900, 900)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}