{"spec_id":"step-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nstep-basic: Basic Step Plot\nLibrary: letsplot 4.11.0 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-07-25\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_area,\n    geom_point,\n    geom_step,\n    geom_text,\n    ggplot,\n    ggsave,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_x_continuous,\n    theme,\n    theme_minimal,\n)\n\n\nLetsPlot.setup_html()\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\"\nRULE = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\nBRAND = \"#009E73\"  # Okabe-Ito position 1 — always first series\n\n# Data - Monthly cumulative sales figures (in thousands)\nnp.random.seed(42)\nmonths = np.arange(1, 13)\nmonthly_sales = np.array([45, 52, 48, 61, 55, 72, 68, 75, 82, 78, 91, 95])\ncumulative_sales = np.cumsum(monthly_sales)\n\ndf = pd.DataFrame({\"month\": months, \"cumulative_sales\": cumulative_sales})\n\n# Step-interpolated points (matching geom_step's direction=\"hv\") so the area\n# fill hugs the stair shape instead of cutting a straight diagonal across it\nstep_months = [months[0]]\nstep_sales = [cumulative_sales[0]]\nfor m, s in zip(months[1:], cumulative_sales[1:], strict=True):\n    step_months += [m, m]\n    step_sales += [step_sales[-1], s]\narea_df = pd.DataFrame({\"month\": step_months, \"cumulative_sales\": step_sales})\n\n# Annotation: label the year-end total near the final data point\ntotal = int(cumulative_sales[-1])\nlabel_df = pd.DataFrame({\"month\": [11.4], \"cumulative_sales\": [total + 52], \"label\": [f\"Year-end total: ${total}K\"]})\n\n# Tooltip shown in the interactive HTML export — a lets-plot-distinctive feature\npoint_tooltips = layer_tooltips().line(\"Month|@month\").line(\"Cumulative sales|$@cumulative_sales K\").anchor(\"top_right\")\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"month\", y=\"cumulative_sales\"))\n    + geom_area(data=area_df, fill=BRAND, color=\"transparent\", alpha=0.15)\n    + geom_step(color=BRAND, size=2, direction=\"hv\")\n    + geom_point(color=BRAND, size=6, alpha=0.9, tooltips=point_tooltips)\n    + geom_text(\n        data=label_df, mapping=aes(x=\"month\", y=\"cumulative_sales\", label=\"label\"), color=INK_SOFT, size=4.5, hjust=1\n    )\n    + labs(x=\"Month\", y=\"Cumulative Sales ($K)\", title=\"step-basic · letsplot · anyplot.ai\")\n    + scale_x_continuous(breaks=list(range(1, 13)))\n    + ggsize(800, 450)\n    + theme_minimal()\n    + theme(\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_grid_major_x=element_blank(),\n        panel_grid_major_y=element_line(color=RULE, size=0.3),\n        panel_grid_minor=element_blank(),\n        panel_border=element_blank(),\n        axis_title=element_text(color=INK, size=12),\n        axis_text=element_text(color=INK_SOFT, size=10),\n        axis_line_x=element_line(color=INK_SOFT),\n        axis_line_y=element_line(color=INK_SOFT),\n        plot_title=element_text(color=INK, size=16),\n    )\n)\n\n# Save PNG (scale 4x to get 3200 x 1800 px)\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\n\n# Save HTML for interactive version\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}