{"spec_id":"errorbar-asymmetric","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nerrorbar-asymmetric: Asymmetric Error Bars Plot\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-05-13\n\"\"\"\n\nimport os\n\nimport pygal\nfrom pygal.style import Style\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nBRAND = \"#009E73\"  # Okabe-Ito position 1\n\n# Data - Material strength testing (MPa) with asymmetric confidence intervals\nmaterials = [\"Steel\", \"Aluminum\", \"Titanium\", \"Copper\", \"Brass\", \"Bronze\"]\ny_values = [250, 150, 450, 200, 180, 220]\nerror_lower = [35, 12, 20, 25, 8, 18]\nerror_upper = [20, 28, 50, 15, 22, 30]\n\n# Cap width for error bar ends\ncap_width = 0.35\n\n# Custom style with theme-adaptive colors and appropriate font sizes\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=(BRAND, BRAND, BRAND, BRAND, BRAND, BRAND, BRAND),\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\n# Create XY chart for error bar visualization\nchart = pygal.XY(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"errorbar-asymmetric · pygal · anyplot.ai\",\n    x_title=\"Material\",\n    y_title=\"Tensile Strength (MPa)\",\n    show_legend=True,\n    legend_at_bottom=False,\n    show_y_guides=True,\n    show_x_guides=False,\n    print_values=False,\n    margin=80,\n    stroke=True,\n    dots_size=12,\n    range=(80, 550),\n    xrange=(0, 7),\n    x_labels=[\"\", \"Steel\", \"Aluminum\", \"Titanium\", \"Copper\", \"Brass\", \"Bronze\"],\n    x_labels_major_every=1,\n    show_minor_x_labels=False,\n)\n\n# Add central points as main series with legend\ncentral_data = [(i + 1, y_values[i]) for i in range(len(materials))]\nchart.add(\"Median (10th-90th percentile)\", central_data, stroke=False, dots_size=16)\n\n# Add error bars and caps for each material\nfor i in range(len(materials)):\n    x_pos = i + 1\n    y_center = y_values[i]\n    y_low = y_center - error_lower[i]\n    y_high = y_center + error_upper[i]\n\n    # Vertical error bar segment\n    bar_data = [(x_pos, y_low), (x_pos, y_high)]\n\n    # Bottom cap (horizontal line)\n    bottom_cap = [(x_pos - cap_width, y_low), (x_pos + cap_width, y_low)]\n\n    # Top cap (horizontal line)\n    top_cap = [(x_pos - cap_width, y_high), (x_pos + cap_width, y_high)]\n\n    # Add error bar (no legend entry)\n    chart.add(None, bar_data, stroke=True, show_dots=False, stroke_style={\"width\": 3})\n\n    # Add caps with thicker stroke for prominence\n    chart.add(None, bottom_cap, stroke=True, show_dots=False, stroke_style={\"width\": 5})\n    chart.add(None, top_cap, stroke=True, show_dots=False, stroke_style={\"width\": 5})\n\n# Render to files\nchart.render_to_file(f\"plot-{THEME}.html\")\nchart.render_to_png(f\"plot-{THEME}.png\")\n"}