{"spec_id":"bar-heart-rate-zones","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nbar-heart-rate-zones: Time in Heart Rate Zones Bar Chart\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 89/100 | Created: 2026-06-14\n\"\"\"\n\nimport os\nimport sys\n\n\ncurrent_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != current_dir]\n\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Zone colors — semantic mapping to Imprint palette\n# Z1 recovery→grey(muted), Z2 endurance→blue, Z3 aerobic→green(brand),\n# Z4 threshold→ochre, Z5 maximum→matte-red\nZONE_COLORS = (\n    INK_MUTED,  # Z1 Recovery\n    \"#4467A3\",  # Z2 Endurance\n    \"#009E73\",  # Z3 Aerobic (Imprint brand green)\n    \"#BD8233\",  # Z4 Threshold\n    \"#AE3030\",  # Z5 Maximum\n)\n\n# Data: 90-minute polarized endurance cycling session\nzone_names = [\"Z1 Recovery\", \"Z2 Endurance\", \"Z3 Aerobic\", \"Z4 Threshold\", \"Z5 Maximum\"]\nhr_ranges = [\"< 120 bpm\", \"120–141 bpm\", \"141–157 bpm\", \"157–170 bpm\", \"> 170 bpm\"]\nminutes = [12, 45, 20, 10, 3]\ntotal_min = sum(minutes)\n\n# X-axis labels combining zone name and HR range\nx_labels = [f\"{zone_names[i]}  {hr_ranges[i]}\" for i in range(5)]\n\n# Title with length-aware font size\ntitle = \"Heart Rate Zones · bar-heart-rate-zones · python · pygal · anyplot.ai\"\nn = len(title)\ntitle_font_size = round(66 * (67 / n)) if n > 67 else 66\n\n# Style\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=ZONE_COLORS,\n    title_font_size=title_font_size,\n    label_font_size=40,\n    major_label_font_size=44,\n    legend_font_size=44,\n    value_font_size=44,\n    stroke_width=2.5,\n)\n\n# Chart — total session duration embedded in y_title for storytelling context\nchart = pygal.Bar(\n    width=3200,\n    height=1800,\n    title=title,\n    y_title=f\"Time (minutes)  ·  {total_min} min total\",\n    style=custom_style,\n    show_legend=False,\n    show_x_guides=False,\n    show_y_guides=True,\n    truncate_label=-1,\n    x_label_rotation=45,\n    print_values=True,\n    print_values_position=\"top\",\n    value_formatter=lambda x: f\"{int(x)} min\",\n    rounded_bars=10,\n    margin_bottom=100,\n)\n\nchart.x_labels = x_labels\n\n# Single series with per-bar color dicts — each zone gets its Imprint-mapped color\nchart.add(\"Time (min)\", [{\"value\": minutes[i], \"color\": ZONE_COLORS[i]} for i in range(5)])\n\n# Save PNG and interactive HTML\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}