{"spec_id":"band-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nband-basic: Basic Band Plot\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-29\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    arrow,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_hline,\n    geom_line,\n    geom_ribbon,\n    geom_segment,\n    geom_text,\n    ggplot,\n    ggsave,\n    ggsize,\n    labs,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\n\n\nLetsPlot.setup_html()\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\nBAND_FILL = IMPRINT_PALETTE[0]  # brand green — Imprint position 1\nLINE_COLOR = IMPRINT_PALETTE[2]  # blue — Imprint position 3\n\n# Data — battery capacity exponential decay over charge cycles (95% tolerance band)\ncycles = np.linspace(0, 500, 100)\ncapacity_mean = 100 * np.exp(-0.002 * cycles)\ntolerance = 2.5 + 0.008 * cycles\ncapacity_lower = capacity_mean - 1.96 * tolerance\ncapacity_upper = capacity_mean + 1.96 * tolerance\n\ndf = pd.DataFrame({\"cycles\": cycles, \"mean\": capacity_mean, \"lower\": capacity_lower, \"upper\": capacity_upper})\n\n# Annotation — arrow pointing to widening lower band edge at cycle ~450\nidx_450 = np.argmin(np.abs(cycles - 450))\nannot_df = pd.DataFrame({\"x\": [285], \"y\": [18.5], \"label\": [\"Widening tolerance band\"]})\narrow_df = pd.DataFrame({\"x\": [375], \"y\": [20.5], \"xend\": [450], \"yend\": [float(capacity_lower[idx_450]) + 0.5]})\n\ntitle = \"band-basic · python · letsplot · anyplot.ai\"\n\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_x=element_blank(),\n    panel_grid_major_y=element_line(color=INK_MUTED, size=0.3),\n    panel_grid_minor=element_blank(),\n    axis_title=element_text(size=12, color=INK),\n    axis_text=element_text(size=10, color=INK_SOFT),\n    axis_line_x=element_line(color=INK_SOFT),\n    axis_line_y=element_blank(),\n    plot_title=element_text(size=16, color=INK),\n    legend_background=element_rect(fill=ELEVATED_BG),\n    legend_text=element_text(size=10, color=INK_SOFT),\n)\n\nplot = (\n    ggplot(df, aes(x=\"cycles\"))\n    + geom_hline(yintercept=80, color=INK_MUTED, size=0.8, linetype=\"dashed\", tooltips=\"none\")\n    + geom_text(x=512, y=83, label=\"80% capacity threshold\", size=4.5, color=INK_MUTED, hjust=1, tooltips=\"none\")\n    + geom_ribbon(aes(ymin=\"lower\", ymax=\"upper\"), fill=BAND_FILL, alpha=0.25, size=0)\n    + geom_line(aes(y=\"mean\"), color=LINE_COLOR, size=1.5)\n    + geom_segment(\n        aes(x=\"x\", y=\"y\", xend=\"xend\", yend=\"yend\"),\n        data=arrow_df,\n        color=INK_SOFT,\n        size=0.7,\n        arrow=arrow(length=8, type=\"open\"),\n        tooltips=\"none\",\n    )\n    + geom_text(aes(x=\"x\", y=\"y\", label=\"label\"), data=annot_df, size=6, color=INK_SOFT)\n    + labs(x=\"Charge Cycles\", y=\"Capacity (%)\", title=title)\n    + scale_x_continuous(limits=[-15, 520])\n    + scale_y_continuous(limits=[10, 110])\n    + theme_minimal()\n    + anyplot_theme\n    + ggsize(800, 450)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}