{"spec_id":"heatmap-calendar","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nheatmap-calendar: Basic Calendar Heatmap\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-07-23\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent this file from shadowing the installed plotly package\n_here = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != _here]\ndel _here\n\nimport numpy as np\nimport pandas as pd\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\"\n\n# Data - GitHub-style activity over one year\nnp.random.seed(42)\nstart_date = pd.Timestamp(\"2024-01-01\")\nend_date = pd.Timestamp(\"2024-12-31\")\ndates = pd.date_range(start=start_date, end=end_date, freq=\"D\")\n\n# Realistic activity with weekly patterns and occasional bursts\nbase_activity = np.random.poisson(lam=3, size=len(dates))\nweekend_mask = dates.dayofweek >= 5\nbase_activity[weekend_mask] = np.random.poisson(lam=1, size=weekend_mask.sum())\nburst_days = np.random.choice(len(dates), size=20, replace=False)\nbase_activity[burst_days] = np.random.randint(10, 20, size=20)\nzero_days = np.random.choice(len(dates), size=50, replace=False)\nbase_activity[zero_days] = 0\n\ndf = pd.DataFrame({\"date\": dates, \"value\": base_activity})\ndf[\"dayofweek\"] = df[\"date\"].dt.dayofweek\ndf[\"month\"] = df[\"date\"].dt.month\ndf[\"week_of_year\"] = (df[\"date\"] - start_date).dt.days // 7\n\n# Build heatmap matrix: 7 rows (days) × n_weeks columns\nn_weeks = df[\"week_of_year\"].max() + 1\nheatmap_raw = np.full((7, n_weeks), np.nan)\nhover_custom = np.empty((7, n_weeks, 2), dtype=object)\n\nfor _, row in df.iterrows():\n    w, d = row[\"week_of_year\"], row[\"dayofweek\"]\n    heatmap_raw[d, w] = row[\"value\"]\n    hover_custom[d, w, 0] = row[\"date\"].strftime(\"%b %d, %Y\")\n    hover_custom[d, w, 1] = int(row[\"value\"])\n\n# Sqrt-transform for color mapping only — spreads out the common 0-5 range\n# (a 2-stop linear scale compresses low counts into near-identical greens)\n# while raw counts stay intact for the hover tooltip and colorbar ticks.\nheatmap_color = np.sqrt(heatmap_raw)\n\nday_labels = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\nmonth_starts = df.groupby(\"month\")[\"week_of_year\"].min()\nmonth_labels = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\n# Imprint sequential colorscale (single-polarity: commit count intensity)\nimprint_seq = [[0.0, \"#009E73\"], [1.0, \"#4467A3\"]]\n\n# Colorbar ticks in raw-commit units, positioned at their sqrt-transformed location\nraw_max = np.nanmax(heatmap_raw)\ntick_raw_vals = list(range(0, int(np.ceil(raw_max / 5)) * 5 + 1, 5))\ntick_positions = [np.sqrt(v) for v in tick_raw_vals]\n\npeak_row = df.loc[df[\"value\"].idxmax()]\npeak_w, peak_d = int(peak_row[\"week_of_year\"]), int(peak_row[\"dayofweek\"])\n\n# Plot\nfig = go.Figure()\n\nfig.add_trace(\n    go.Heatmap(\n        z=heatmap_color,\n        x=list(range(n_weeks)),\n        y=day_labels,\n        customdata=hover_custom,\n        colorscale=imprint_seq,\n        showscale=True,\n        colorbar={\n            \"title\": {\"text\": \"Daily commits\", \"font\": {\"size\": 12, \"color\": INK}},\n            \"tickmode\": \"array\",\n            \"tickvals\": tick_positions,\n            \"ticktext\": [str(v) for v in tick_raw_vals],\n            \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n            \"thickness\": 13,\n            \"len\": 0.6,\n            \"bgcolor\": ELEVATED_BG,\n            \"bordercolor\": INK_SOFT,\n            \"borderwidth\": 1,\n        },\n        hoverongaps=False,\n        hovertemplate=\"%{customdata[0]}<br>Commits: %{customdata[1]}<extra></extra>\",\n        xgap=2,\n        ygap=2,\n        zmin=0,\n    )\n)\n\n# Callout on the single busiest day — an authored focal point rather than\n# relying on the color scale alone to surface the burst.\nfig.add_annotation(\n    x=peak_w,\n    y=day_labels[peak_d],\n    text=f\"Peak: {int(peak_row['value'])} commits<br>{peak_row['date'].strftime('%b %d')}\",\n    showarrow=True,\n    arrowhead=2,\n    arrowwidth=1,\n    arrowcolor=INK_SOFT,\n    ax=-40 if peak_w > n_weeks / 2 else 40,\n    ay=40 if peak_d <= 1 else -40,\n    font={\"size\": 11, \"color\": INK},\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=4,\n)\n\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"heatmap-calendar · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"tickmode\": \"array\",\n        \"tickvals\": list(month_starts.values),\n        \"ticktext\": month_labels,\n        \"tickfont\": {\"size\": 11, \"color\": INK_SOFT},\n        \"side\": \"top\",\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"ticks\": \"\",\n    },\n    yaxis={\n        \"tickfont\": {\"size\": 11, \"color\": INK_SOFT},\n        \"autorange\": \"reversed\",\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"ticks\": \"\",\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    margin={\"l\": 40, \"r\": 70, \"t\": 60, \"b\": 30},\n)\n\n# Save — hard target: 3200 x 1800 (landscape)\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}