{"spec_id":"lollipop-grouped","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nlollipop-grouped: Grouped Lollipop Chart\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\nimport sys\n\n\n# Work around import shadowing from sibling library files in same directory\n_script_dir = os.path.dirname(os.path.abspath(__file__))\nif _script_dir in sys.path:\n    sys.path.remove(_script_dir)\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_point,\n    geom_segment,\n    ggplot,\n    labs,\n    position_dodge,\n    scale_color_manual,\n    theme,\n)\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\"\n\n# Okabe-Ito palette (positions 1, 2, 3)\nCOLORS = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Data - Quarterly revenue by product line across regions\nnp.random.seed(42)\n\ncategories = [\"North America\", \"Europe\", \"Asia Pacific\", \"Latin America\"]\nseries = [\"Software\", \"Hardware\", \"Services\"]\n\ndata = []\nfor cat in categories:\n    for ser in series:\n        base = {\"Software\": 85, \"Hardware\": 65, \"Services\": 50}[ser]\n        region_factor = {\"North America\": 1.2, \"Europe\": 1.0, \"Asia Pacific\": 0.9, \"Latin America\": 0.7}[cat]\n        value = base * region_factor + np.random.uniform(-8, 8)\n        data.append({\"Category\": cat, \"Series\": ser, \"Revenue\": value})\n\ndf = pd.DataFrame(data)\n\n# Reorder series by median value (descending) for legend order\nseries_order = df.groupby(\"Series\")[\"Revenue\"].median().sort_values(ascending=False).index.tolist()\ndf[\"Series\"] = pd.Categorical(df[\"Series\"], categories=series_order, ordered=True)\ndf = df.sort_values(\"Series\")\n\n# Create grouped lollipop chart\nplot = (\n    ggplot(df, aes(x=\"Category\", y=\"Revenue\", color=\"Series\"))\n    # Stems (segments from 0 to value)\n    + geom_segment(\n        aes(x=\"Category\", xend=\"Category\", y=0, yend=\"Revenue\"), position=position_dodge(width=0.6), size=1.5\n    )\n    # Markers (dots at the top)\n    + geom_point(position=position_dodge(width=0.6), size=6)\n    # Okabe-Ito colors\n    + scale_color_manual(values=COLORS)\n    # Labels\n    + labs(\n        title=\"lollipop-grouped · Python · plotnine · anyplot.ai\",\n        x=\"Region\",\n        y=\"Revenue (Million USD)\",\n        color=\"Product Line\",\n    )\n    # Theme\n    + theme(\n        figure_size=(16, 9),\n        text=element_text(size=14, color=INK),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        axis_text_x=element_text(size=16, color=INK_SOFT),\n        plot_title=element_text(size=24, color=INK),\n        legend_title=element_text(size=18, color=INK),\n        legend_text=element_text(size=16, color=INK_SOFT),\n        legend_position=\"right\",\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=INK, size=0.3, alpha=0.10),\n        panel_grid_major_x=element_blank(),\n        panel_grid_minor=element_blank(),\n        panel_border=element_rect(color=INK_SOFT, fill=None, size=0.5),\n        axis_line=element_line(color=INK_SOFT, size=0.5),\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=300, verbose=False)\n"}