{"spec_id":"lollipop-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nlollipop-basic: Basic Lollipop Chart\nLibrary: letsplot 4.11.0 | Python 3.13.14\nQuality: 83/100 | Updated: 2026-07-01\n\"\"\"\n\nimport os\n\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_point,\n    geom_segment,\n    geom_text,\n    ggplot,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\nfrom lets_plot.export import ggsave\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 = \"#D6D3C7\" if THEME == \"light\" else \"#3A3A34\"\nBRAND = \"#009E73\"\n\n# Data — Product sales by category, sorted ascending\ncategories = [\"Electronics\", \"Clothing\", \"Home/Garden\", \"Sports\", \"Books\", \"Toys\", \"Grocery\", \"Beauty\"]\nvalues = [45200, 32800, 28500, 21300, 18900, 15600, 12400, 9800]\n\ndf = pd.DataFrame({\"category\": categories, \"value\": values})\ndf = df.sort_values(\"value\", ascending=True).reset_index(drop=True)\ndf[\"x_pos\"] = range(len(df))\ndf[\"y_start\"] = 0\ndf[\"value_label\"] = df[\"value\"].apply(lambda v: f\"${v:,.0f}\")\ndf[\"label_y\"] = df[\"value\"] + max(values) * 0.028\n\ny_ceiling = max(values) * 1.20\n\n# Plot — stems + stroked dots + value labels with interactive tooltips\nplot = (\n    ggplot(df)\n    + geom_segment(mapping=aes(x=\"x_pos\", xend=\"x_pos\", y=\"y_start\", yend=\"value\"), size=1.5, color=BRAND)\n    + geom_point(\n        mapping=aes(x=\"x_pos\", y=\"value\"),\n        shape=21,\n        size=10,\n        fill=BRAND,\n        color=INK_SOFT,\n        stroke=0.8,\n        tooltips=layer_tooltips().line(\"@category\").line(\"Sales|@value_label\"),\n    )\n    + geom_text(mapping=aes(x=\"x_pos\", y=\"label_y\", label=\"value_label\"), color=INK_SOFT, size=3.5, hjust=0.5)\n    + scale_x_continuous(breaks=df[\"x_pos\"].tolist(), labels=df[\"category\"].tolist())\n    + scale_y_continuous(limits=[0, y_ceiling])\n    + labs(x=\"Product Category\", y=\"Sales ($)\", title=\"lollipop-basic · python · letsplot · anyplot.ai\")\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_y=element_line(color=RULE, size=0.3),\n        panel_grid_minor=element_blank(),\n        panel_grid_major_x=element_blank(),\n        axis_line_y=element_line(color=INK_SOFT, size=0.4),\n        axis_line_x=element_blank(),\n        axis_ticks=element_line(color=INK_SOFT),\n        axis_title=element_text(size=12, color=INK),\n        axis_text_x=element_text(size=10, color=INK_SOFT, angle=45, hjust=1),\n        axis_text_y=element_text(size=10, color=INK_SOFT),\n        plot_title=element_text(size=16, color=INK, hjust=0.5),\n        plot_margin=[20, 20, 30, 10],\n    )\n)\n\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}