{"spec_id":"stem-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nstem-basic: Basic Stem Plot\nLibrary: letsplot 4.11.0 | Python 3.13.14\nQuality: 94/100 | Updated: 2026-07-25\n\"\"\"\n# ruff: noqa: F405\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import *\n\n\nLetsPlot.setup_html()\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\"\nMUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nRULE = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint palette — first series is always #009E73\nBRAND = \"#009E73\"\n\n# Data - discrete samples of a damped oscillation (impulse response)\nnp.random.seed(42)\nn = 30\nx = np.arange(n)\nenvelope = np.exp(-x / 10)\ny = envelope * np.cos(x * 0.8) + np.random.randn(n) * 0.05\n# Fade the stems once the envelope decays past ~0.1 to sharpen the visual hierarchy\nalpha = np.where(envelope >= 0.1, 1.0, 0.4)\n\ndf = pd.DataFrame({\"x\": x, \"y\": y, \"y_base\": 0.0, \"alpha\": alpha})\nenvelope_df = pd.DataFrame({\"x\": x, \"upper\": envelope, \"lower\": -envelope})\n\nplot = (\n    ggplot(df)\n    + geom_line(aes(x=\"x\", y=\"upper\"), data=envelope_df, color=MUTED, size=1.0, linetype=\"dashed\", alpha=0.7)\n    + geom_line(aes(x=\"x\", y=\"lower\"), data=envelope_df, color=MUTED, size=1.0, linetype=\"dashed\", alpha=0.7)\n    + geom_hline(yintercept=0, color=INK_SOFT, size=0.5)\n    + geom_segment(aes(x=\"x\", y=\"y_base\", xend=\"x\", yend=\"y\", alpha=\"alpha\"), color=BRAND, size=1.2)\n    + geom_point(\n        aes(x=\"x\", y=\"y\", alpha=\"alpha\"),\n        color=BRAND,\n        fill=BRAND,\n        size=3.5,\n        stroke=1.2,\n        shape=21,\n        tooltips=layer_tooltips().title(\"Sample @x\").line(\"Amplitude|@y\"),\n    )\n    + scale_alpha_identity()\n    + labs(x=\"Sample Index\", y=\"Amplitude (a.u.)\", title=\"stem-basic · python · letsplot · anyplot.ai\")\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_border=element_blank(),\n        panel_grid_major=element_line(color=RULE, 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_ticks=element_line(color=INK_SOFT),\n        axis_line_x=element_line(color=INK_SOFT, size=0.4),\n        axis_line_y=element_line(color=INK_SOFT, size=0.4),\n        plot_title=element_text(size=16, color=INK),\n    )\n    + ggsize(800, 450)\n)\n\n# Save PNG (scale 4x for 3200 x 1800 px)\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\n\n# Save HTML\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}