Bar Chart with Error Bars — Bokeh

A bar chart with error bars displays categorical data as rectangular bars with vertical (or horizontal) lines extending from each bar to indicate uncertainty or variability. Error bars typically represent standard deviation, standard error, confidence intervals, or min/max ranges. This visualization is essential for comparing group means while communicating the reliability and precision of each measurement.

Bar Chart with Error Bars rendered with Bokeh

Renders

Python source (Bokeh)

""" anyplot.ai
bar-error: Bar Chart with Error Bars
Library: bokeh 3.9.0 | Python 3.13.13
Quality: 84/100 | Updated: 2026-05-10
"""

import os
import time
from pathlib import Path

import numpy as np
from bokeh.io import output_file, save
from bokeh.models import ColumnDataSource, TeeHead, Whisker
from bokeh.plotting import figure
from selenium import webdriver
from selenium.webdriver.chrome.options import Options


# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
BRAND = "#009E73"  # Okabe-Ito position 1

# Data - Quarterly revenue by product line with standard deviation
np.random.seed(42)
categories = ["Electronics", "Clothing", "Home & Garden", "Sports", "Books"]
values = np.array([85.2, 62.8, 48.5, 71.3, 35.7])
errors = np.array([8.5, 5.2, 6.8, 9.1, 4.2])

# Calculate upper and lower bounds
upper = values + errors
lower = values - errors

# Create ColumnDataSource
source = ColumnDataSource(data={"categories": categories, "values": values, "upper": upper, "lower": lower})

# Create figure
p = figure(
    x_range=categories,
    width=4800,
    height=2700,
    title="bar-error · bokeh · anyplot.ai",
    x_axis_label="Product Category",
    y_axis_label="Quarterly Revenue ($ millions)",
    toolbar_location=None,
)

# Draw bars
p.vbar(
    x="categories",
    top="values",
    width=0.6,
    source=source,
    fill_color=BRAND,
    line_color=BRAND,
    line_width=3,
    fill_alpha=0.85,
)

# Add error bars with whiskers and caps
whisker = Whisker(
    source=source,
    base="categories",
    upper="upper",
    lower="lower",
    line_color=INK_SOFT,
    line_width=5,
    upper_head=TeeHead(size=40, line_color=INK_SOFT, line_width=5),
    lower_head=TeeHead(size=40, line_color=INK_SOFT, line_width=5),
)
p.add_layout(whisker)

# Style
p.title.text_font_size = "28pt"
p.title.text_color = INK
p.xaxis.axis_label_text_font_size = "22pt"
p.yaxis.axis_label_text_font_size = "22pt"
p.xaxis.major_label_text_font_size = "18pt"
p.yaxis.major_label_text_font_size = "18pt"
p.xaxis.axis_label_text_color = INK
p.yaxis.axis_label_text_color = INK
p.xaxis.major_label_text_color = INK_SOFT
p.yaxis.major_label_text_color = INK_SOFT

# Axis styling
p.xaxis.axis_line_color = INK_SOFT
p.yaxis.axis_line_color = INK_SOFT
p.xaxis.axis_line_width = 2
p.yaxis.axis_line_width = 2
p.xaxis.major_tick_line_color = INK_SOFT
p.yaxis.major_tick_line_color = INK_SOFT
p.xaxis.major_tick_line_width = 2
p.yaxis.major_tick_line_width = 2

# Grid
p.xgrid.visible = False
p.ygrid.grid_line_color = INK_SOFT
p.ygrid.grid_line_alpha = 0.10
p.ygrid.grid_line_width = 1

# Background
p.background_fill_color = PAGE_BG
p.border_fill_color = PAGE_BG
p.outline_line_color = INK_SOFT

# Y-axis range
p.y_range.start = 0
p.y_range.end = max(upper) + 15

# Save HTML
output_file(f"plot-{THEME}.html")
save(p)

# Screenshot with headless Chrome
W, H = 4800, 2700
opts = Options()
for arg in (
    "--headless=new",
    "--no-sandbox",
    "--disable-dev-shm-usage",
    "--disable-gpu",
    f"--window-size={W},{H}",
    "--hide-scrollbars",
):
    opts.add_argument(arg)
driver = webdriver.Chrome(options=opts)
driver.set_window_size(W, H)
driver.get(f"file://{Path(f'plot-{THEME}.html').resolve()}")
time.sleep(3)
driver.save_screenshot(f"plot-{THEME}.png")
driver.quit()

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/bar-error/bokeh/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "bar-error",
  "language": "python",
  "library": "bokeh",
  "page": "https://anyplot.ai/bar-error/python/bokeh",
  "hub": "https://anyplot.ai/bar-error",
  "code_json": "https://api.anyplot.ai/specs/bar-error/bokeh/code",
  "spec_json": "https://api.anyplot.ai/specs/bar-error",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/bar-error/python/bokeh/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/bar-error/python/bokeh/plot-dark.png",
  "interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/bar-error/python/bokeh/plot-light.html",
  "interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/bar-error/python/bokeh/plot-dark.html",
  "quality_score": 84.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Bar Chart with Error Bars on anyplot.ai.

Other implementations