{"spec_id":"errorbar-asymmetric","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nerrorbar-asymmetric: Asymmetric Error Bars Plot\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-13\n\"\"\"\n\nimport os\nimport sys\n\n\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != script_dir and p != \"\"]\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\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\"\n\nnp.random.seed(42)\nproducts = [\"Product A\", \"Product B\", \"Product C\", \"Product D\", \"Product E\", \"Product F\"]\ncentral_values = np.array([85.2, 72.8, 91.5, 68.3, 78.9, 82.1])\nerror_lower = np.array([5.2, 8.1, 3.8, 9.5, 6.3, 4.9])\nerror_upper = np.array([8.7, 4.3, 6.2, 5.8, 10.1, 7.6])\n\ndf = pd.DataFrame(\n    {\n        \"Product\": products,\n        \"Quality Score\": central_values,\n        \"Lower\": central_values - error_lower,\n        \"Upper\": central_values + error_upper,\n    }\n)\n\nerror_bars = (\n    alt.Chart(df)\n    .mark_rule(strokeWidth=3, color=BRAND)\n    .encode(\n        x=alt.X(\"Product:N\", title=\"Product\", axis=alt.Axis(labelFontSize=18, titleFontSize=22, labelAngle=0)),\n        y=alt.Y(\n            \"Lower:Q\",\n            title=\"Quality Score (10th–90th Percentile)\",\n            scale=alt.Scale(domain=[50, 105]),\n            axis=alt.Axis(labelFontSize=18, titleFontSize=22),\n        ),\n        y2=alt.Y2(\"Upper:Q\"),\n    )\n)\n\nlower_caps = alt.Chart(df).mark_tick(size=30, thickness=3, color=BRAND).encode(x=alt.X(\"Product:N\"), y=alt.Y(\"Lower:Q\"))\n\nupper_caps = alt.Chart(df).mark_tick(size=30, thickness=3, color=BRAND).encode(x=alt.X(\"Product:N\"), y=alt.Y(\"Upper:Q\"))\n\npoints = (\n    alt.Chart(df)\n    .mark_point(size=300, filled=True, color=BRAND, stroke=INK_SOFT, strokeWidth=2)\n    .encode(\n        x=alt.X(\"Product:N\"),\n        y=alt.Y(\"Quality Score:Q\"),\n        tooltip=[\n            alt.Tooltip(\"Product:N\", title=\"Product\"),\n            alt.Tooltip(\"Quality Score:Q\", title=\"Quality Score\", format=\".1f\"),\n            alt.Tooltip(\"Lower:Q\", title=\"10th Percentile\", format=\".1f\"),\n            alt.Tooltip(\"Upper:Q\", title=\"90th Percentile\", format=\".1f\"),\n        ],\n    )\n)\n\nannotation = (\n    alt.Chart(pd.DataFrame({\"x\": [\"Product F\"], \"y\": [53], \"text\": [\"Error bars show 10th–90th percentile range\"]}))\n    .mark_text(fontSize=16, fontStyle=\"italic\", color=INK_MUTED, align=\"right\")\n    .encode(x=alt.X(\"x:N\"), y=alt.Y(\"y:Q\"), text=\"text:N\")\n)\n\nchart = (\n    alt.layer(error_bars, lower_caps, upper_caps, points, annotation)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(\"errorbar-asymmetric · altair · anyplot.ai\", fontSize=28, anchor=\"middle\", color=INK),\n    )\n    .configure_axis(\n        labelFontSize=18,\n        titleFontSize=22,\n        grid=True,\n        gridOpacity=0.1,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        domainColor=INK_SOFT,\n        gridColor=INK_SOFT,\n    )\n    .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=0)\n    .configure_title(color=INK)\n)\n\nchart.save(f\"plot-{THEME}.png\", scale_factor=3.0)\nchart.save(f\"plot-{THEME}.html\")\n"}