{"spec_id":"slope-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nslope-basic: Basic Slope Chart (Slopegraph)\nLibrary: pygal 3.1.3 | Python 3.13.14\nQuality: 85/100 | Updated: 2026-07-25\n\"\"\"\n\nimport os\nimport sys\n\n\n# Pop script dir so this file (pygal.py) doesn't shadow the installed pygal package\n_script_dir = sys.path.pop(0)\nimport pygal\nfrom pygal.style import Style\n\n\nsys.path.insert(0, _script_dir)\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nCOLOR_INCREASE = \"#009E73\"  # Imprint palette position 1 — upward change\nCOLOR_DECREASE = \"#AE3030\"  # Imprint palette position 5 — semantic anchor for downward change\n\n# Realistic product category data — Q1 vs Q4 sales comparison.\n# Values are spread with even 7/8-unit gaps within each quarter so the\n# endpoint category-name labels never crowd or overlap each other.\ncategories = [\n    \"Electronics\",\n    \"Apparel\",\n    \"Furniture\",\n    \"Automotive\",\n    \"Food & Bev\",\n    \"Sporting Goods\",\n    \"Home Decor\",\n    \"Office Supplies\",\n    \"Beauty\",\n    \"Toys\",\n]\nq1_sales = [75, 82, 103, 40, 68, 47, 89, 61, 96, 54]\nq4_sales = [90, 58, 114, 74, 66, 82, 98, 42, 106, 50]\n\nincreasing = [(c, q1_sales[i], q4_sales[i]) for i, c in enumerate(categories) if q4_sales[i] >= q1_sales[i]]\ndecreasing = [(c, q1_sales[i], q4_sales[i]) for i, c in enumerate(categories) if q4_sales[i] < q1_sales[i]]\n\nseries_colors = tuple([COLOR_INCREASE] * len(increasing) + [COLOR_DECREASE] * len(decreasing))\n\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=series_colors,\n    title_font_size=66,\n    label_font_size=56,\n    major_label_font_size=44,\n    value_label_font_size=44,\n    # value_font_size drives pygal's dot-to-label offset (x/y = dot + value_font_size),\n    # not just the (unused, print_values=False) value text itself — raised well past\n    # the default 16 so category labels clear the y-axis line at the Q1 column.\n    value_font_size=40,\n    stroke_width=6,\n)\n\n# Slope chart: Line chart with only 2 x-axis time points.\n# The legend is omitted — each line already carries its category name at\n# both endpoints (print_labels), and the up/down direction is self-evident\n# from the slope itself, so a color legend would only duplicate that info.\nchart = pygal.Line(\n    width=3200,\n    height=1800,\n    title=\"slope-basic · python · pygal · anyplot.ai\",\n    x_title=\"Time Period\",\n    y_title=\"Sales (thousands of units)\",\n    style=custom_style,\n    show_dots=True,\n    dots_size=18,\n    show_y_guides=True,\n    show_x_guides=False,\n    show_legend=False,\n    interpolate=None,\n    margin=140,\n    print_values=False,\n    print_labels=True,\n    range=(30, 120),\n    margin_right=480,\n)\n\nchart.x_labels = [\"Q1 2024\", \"Q4 2024\"]\n\n# Increasing categories — Imprint brand green\nfor c, start, end in increasing:\n    chart.add(c, [{\"value\": start, \"label\": c}, {\"value\": end, \"label\": c}])\n\n# Decreasing categories — Imprint matte red\nfor c, start, end in decreasing:\n    chart.add(c, [{\"value\": start, \"label\": c}, {\"value\": end, \"label\": c}])\n\n# Save PNG and interactive HTML\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}