{"spec_id":"heatmap-polar","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nheatmap-polar: Polar Heatmap for Cyclic Two-Dimensional Data\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 86/100 | Created: 2026-05-13\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent current directory from shadowing the plotnine package\nsys.path = [p for p in sys.path if not p.endswith(\"implementations\") and not p.endswith(\"python\")]\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    annotate,\n    coord_equal,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_polygon,\n    geom_text,\n    ggplot,\n    labs,\n    scale_fill_cmap,\n    theme,\n)\n\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: hourly website traffic by day of week\nnp.random.seed(42)\ndays = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\n\ntraffic_matrix = np.zeros((7, 24))\nfor d_idx in range(7):\n    is_weekend = d_idx >= 5\n    for h in range(24):\n        if is_weekend:\n            traffic = 140 + np.exp(-0.5 * ((h - 12) / 3.5) ** 2) * 320\n        else:\n            traffic = (\n                180\n                + np.exp(-0.5 * ((h - 9) / 1.5) ** 2) * 520\n                + np.exp(-0.5 * ((h - 13) / 1.8) ** 2) * 360\n                + np.exp(-0.5 * ((h - 20) / 2.0) ** 2) * 290\n            )\n        traffic_matrix[d_idx, h] = max(0.0, traffic + np.random.normal(0, 20))\n\n# Build polygon vertices for each cell as a wedge in Cartesian space.\n# Clockwise layout: 12am at top (θ = π/2), hours increase clockwise.\nN_ARC = 10\npoly_rows = []\ncell_id = 0\n\nfor d_idx in range(7):\n    r_in = float(d_idx + 1)\n    r_out = float(d_idx + 2)\n    for h in range(24):\n        val = traffic_matrix[d_idx, h]\n        t0 = np.pi / 2 - h * (2 * np.pi / 24)\n        t1 = np.pi / 2 - (h + 1) * (2 * np.pi / 24)\n        # inner arc (clockwise = decreasing θ)\n        for t in np.linspace(t0, t1, N_ARC):\n            poly_rows.append({\"px\": r_in * np.cos(t), \"py\": r_in * np.sin(t), \"g\": cell_id, \"v\": val})\n        # outer arc (counter-clockwise back = increasing θ)\n        for t in np.linspace(t1, t0, N_ARC):\n            poly_rows.append({\"px\": r_out * np.cos(t), \"py\": r_out * np.sin(t), \"g\": cell_id, \"v\": val})\n        cell_id += 1\n\ndf_poly = pd.DataFrame(poly_rows)\n\n# Day labels centered on 12am axis at each ring's radial midpoint\ndf_day = pd.DataFrame({\"px\": [0] * 7, \"py\": [d + 1.5 for d in range(7)], \"label\": days})\n\n# Outer boundary radius for annotation placement\nR_OUT = 8.0\n\n# Peak annotation position: 9:30am direction, just outside the outermost ring\nh_ann = 9.5\ntheta_ann = np.pi / 2 - h_ann * (2 * np.pi / 24)\nr_ann = R_OUT + 0.6\nx_ann = r_ann * np.cos(theta_ann)\ny_ann = r_ann * np.sin(theta_ann)\n\nplot = (\n    ggplot(df_poly, aes(x=\"px\", y=\"py\", group=\"g\", fill=\"v\"))\n    + geom_polygon(color=ELEVATED_BG, size=0.15)\n    + geom_text(\n        data=df_day,\n        mapping=aes(x=\"px\", y=\"py\", label=\"label\"),\n        inherit_aes=False,\n        color=INK,\n        size=14,\n        ha=\"center\",\n        va=\"center\",\n    )\n    + annotate(\"text\", x=0, y=R_OUT + 0.7, label=\"12am\", color=INK_SOFT, size=16, ha=\"center\", va=\"bottom\")\n    + annotate(\"text\", x=R_OUT + 0.7, y=0, label=\"6am\", color=INK_SOFT, size=16, ha=\"left\", va=\"center\")\n    + annotate(\"text\", x=0, y=-(R_OUT + 0.7), label=\"12pm\", color=INK_SOFT, size=16, ha=\"center\", va=\"top\")\n    + annotate(\"text\", x=-(R_OUT + 0.7), y=0, label=\"6pm\", color=INK_SOFT, size=16, ha=\"right\", va=\"center\")\n    + annotate(\"text\", x=x_ann, y=y_ann, label=\"Peak 9am–1pm\\nweekdays\", color=INK_SOFT, size=12, ha=\"left\", va=\"top\")\n    + coord_equal()\n    + scale_fill_cmap(cmap_name=\"viridis\", name=\"Visits/hr\")\n    + labs(title=\"Website Traffic · heatmap-polar · plotnine · anyplot.ai\", x=\"\", y=\"\")\n    + theme(\n        figure_size=(12, 12),\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        panel_border=element_blank(),\n        axis_title=element_blank(),\n        axis_text=element_blank(),\n        axis_line=element_blank(),\n        plot_title=element_text(color=INK, size=24, ha=\"center\"),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_text=element_text(color=INK_SOFT, size=16),\n        legend_title=element_text(color=INK, size=16),\n    )\n)\n\nplot.save(f\"plot-{THEME}.png\", dpi=300)\n"}