{"spec_id":"span-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nspan-basic: Basic Span Plot (Highlighted Region)\nLibrary: pygal 3.1.3 | Python 3.13.14\nQuality: 88/100 | Created: 2026-07-25\n\"\"\"\n\nimport os\nimport sys\n\nimport numpy as np\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\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_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Span fill opacity stays within the spec's 0.2-0.3 range on both themes\nSPAN_OPACITY = \".3\" if THEME == \"dark\" else \".25\"\n\n# Semantic colors (style guide's semantic-exception rule): the recession span is a\n# negative economic event (matte red), the risk zone is a warning threshold (amber),\n# freeing brand green for the primary stock-price line rather than a secondary span\nRECESSION_COLOR = \"#AE3030\"  # Imprint position 5 - loss / bad-event anchor\nRISK_COLOR = \"#DDCC77\"  # amber semantic anchor - warning / caution\nPRICE_COLOR = \"#009E73\"  # brand green - primary data series\n\n# Data - Stock prices with highlighted events\nnp.random.seed(42)\ndates = np.arange(2006, 2016, 0.1)\nprice = 100 + np.cumsum(np.random.randn(len(dates)) * 2)\nrecession_mask = (dates >= 2008) & (dates < 2010)\nprice[recession_mask] -= np.linspace(0, 30, recession_mask.sum())\nprice[dates >= 2010] -= 30\nprice = price + np.abs(price.min()) + 50\n\n# Tight range around the actual price floor/ceiling (~141-204) to avoid dead canvas space\ny_min = float(price.min()) - 20\ny_max = float(price.max()) + 15\n\n# Risk Zone sits inside the observed price range (not below it) so it visibly\n# intersects the line near the recession trough and the post-2010 plateau\nrisk_low, risk_high = 140.0, 160.0\n\n# Style\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=(RECESSION_COLOR, RISK_COLOR, PRICE_COLOR),\n    opacity=SPAN_OPACITY,\n    opacity_hover=\".5\",\n    title_font_size=66,\n    label_font_size=56,\n    major_label_font_size=44,\n    legend_font_size=44,\n    value_font_size=36,\n    stroke_width=2.5,\n)\n\n# Plot — x-guides disabled for a cleaner grid; human_readable for polished tooltips;\n# truncate_legend=-1 keeps \"Recession Period\" from being clipped in the legend;\n# spacing (pygal's uniform title/legend/axis padding knob) is raised from the\n# native 10px default so the legend isn't flush against the canvas edge; the\n# inline css softens pygal's default solid axis box lines to match the subtle\n# gridline treatment (opacity ~0.25) instead of a hard foreground_strong outline\nchart = pygal.XY(\n    style=custom_style,\n    width=3200,\n    height=1800,\n    title=\"span-basic · pygal · anyplot.ai\",\n    x_title=\"Year\",\n    y_title=\"Price ($)\",\n    show_dots=False,\n    show_x_guides=False,\n    show_y_guides=True,\n    range=(y_min, y_max),\n    xrange=(2005.5, 2016.5),\n    fill=True,\n    stroke=True,\n    truncate_legend=-1,\n    human_readable=True,\n    spacing=28,\n    css=(\"file://style.css\", \"file://graph.css\", \"inline:.axis .line { stroke-opacity: .25; }\"),\n)\n\n# Vertical span: Recession Period (2008-2009) — closed polygon\nrecession_span = [(2008, y_min), (2008, y_max), (2009, y_max), (2009, y_min), (2008, y_min)]\nchart.add(\"Recession Period\", recession_span)\n\n# Horizontal span: Risk Zone (price 140-160) — closed polygon\nrisk_span = [(2005.5, risk_low), (2005.5, risk_high), (2016.5, risk_high), (2016.5, risk_low), (2005.5, risk_low)]\nchart.add(\"Risk Zone\", risk_span)\n\n# Main line — dict format enables per-point custom tooltip labels (pygal interactive feature)\nmain_data = [{\"value\": (float(x), float(y)), \"label\": f\"${y:.0f}\"} for x, y in zip(dates, price, strict=True)]\nchart.add(\"Stock Price\", main_data, fill=False, stroke=True)\n\n# Save\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}