Errorbar Examples

publiplots.errorbarplot() is a publication-ready scatter plot that draws x and/or y uncertainty bars at each point. Unlike publiplots.pointplot() (which is categorical-x only and y-error only), pp.errorbarplot accepts continuous x, two-axis errors, and asymmetric bounds via tuple-of-columns. Marker rendering is delegated to publiplots.scatterplot(), so categorical and continuous hue=, palette=, the publiplots double-layer alpha convention, and the opaque background-marker for occlusion all work out of the box. Stems match their marker color: categorical hue= groups stems by level, continuous numeric hue= colors each stem from the cmap, and no hue= falls back to the neutral rcParams['edgecolor'].

import numpy as np
import pandas as pd

import publiplots as pp

Basic Y-Errorbars

The most common case: a measurement with a standard error of the mean (or any symmetric uncertainty) on the y-axis. Pass the column name as yerr=.

rng = np.random.default_rng(0)
doses = np.array([0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0])
n = len(doses)
basic_df = pd.DataFrame({
    "dose": doses,
    "response": 1.0 - np.exp(-doses / 2.0) + 0.05 * rng.normal(size=n),
    "sem": 0.05 + 0.04 * rng.uniform(size=n),
})

pp.errorbarplot(
    data=basic_df,
    x="dose",
    y="response",
    yerr="sem",
    capsize=2,
    title="Y errorbars",
    xlabel="dose (mg)",
    ylabel="response",
)
pp.show()
Y errorbars

2D Errorbars (X and Y)

When both axes carry uncertainty (e.g. a calibration curve where the reference value is itself measured), pass xerr= and yerr= together. The two error directions render in a single ax.errorbar call below the markers.

rng = np.random.default_rng(1)
n = 12
xx = np.linspace(0.5, 10.0, n)
yy = 0.85 * xx + 0.1 * rng.normal(size=n)
calib_df = pd.DataFrame({
    "x_meas": xx + 0.05 * rng.normal(size=n),
    "y_meas": yy,
    "x_err": 0.1 + 0.1 * rng.uniform(size=n),
    "y_err": 0.15 + 0.1 * rng.uniform(size=n),
})

pp.errorbarplot(
    data=calib_df,
    x="x_meas",
    y="y_meas",
    xerr="x_err",
    yerr="y_err",
    capsize=2,
    title="2D errorbars",
    xlabel="reference",
    ylabel="measurement",
)
pp.show()
2D errorbars

Asymmetric Errors via Tuple-of-Columns

When the lower and upper bounds differ (e.g. bootstrap CIs on a skewed statistic), pass a 2-tuple of column names (lo_col, hi_col). The values in each column are the distances below and above the point (matplotlib’s yerr convention).

rng = np.random.default_rng(2)
n = 10
x = np.arange(n)
y = np.cumsum(rng.normal(0.5, 0.2, n))
asym_df = pd.DataFrame({
    "x": x,
    "y": y,
    "y_lo": 0.1 + 0.4 * rng.uniform(size=n),
    "y_hi": 0.1 + 0.8 * rng.uniform(size=n),
})

pp.errorbarplot(
    data=asym_df,
    x="x",
    y="y",
    yerr=("y_lo", "y_hi"),
    capsize=2,
    title="Asymmetric errors",
    xlabel="time",
    ylabel="cumulative",
)
pp.show()
Asymmetric errors

Categorical Hue

Pass hue= to color the markers by group. With a categorical hue, errorbar stems are issued per-group with ecolor set from the resolved palette so each measurement’s uncertainty inherits its group’s color. (Continuous numeric hue= keeps stems neutral — see the next section.)

rng = np.random.default_rng(3)
groups = ["control", "low", "mid", "high"]
n_per = 8
hue_df = pd.concat([
    pd.DataFrame({
        "x": rng.uniform(0, 10, n_per),
        "y": (i + 1) + 0.3 * rng.normal(size=n_per),
        "yerr": 0.15 + 0.15 * rng.uniform(size=n_per),
        "group": g,
    })
    for i, g in enumerate(groups)
], ignore_index=True)

fig, ax = pp.subplots(axes_size=(60, 45))
pp.errorbarplot(
    data=hue_df,
    x="x",
    y="y",
    yerr="yerr",
    hue="group",
    palette="pastel",
    capsize=2,
    ax=ax,
    title="Errorbars by group",
    xlabel="x",
    ylabel="response",
)
pp.show()
Errorbars by group

Continuous Hue with Colorbar

Pass a numeric column as hue= to color markers along a continuous scale. pp.scatterplot (delegated to internally) registers a colorbar via the publiplots layout reactor, so the colorbar reserves space without colliding with the axes. Each stem inherits its marker’s cmap color (one ax.errorbar call per point) so the uncertainty visually attaches to the measurement.

rng = np.random.default_rng(4)
n = 25
score = rng.uniform(0, 100, n)
cont_df = pd.DataFrame({
    "x": rng.normal(size=n),
    "y": rng.normal(size=n),
    "yerr": 0.1 + 0.1 * rng.uniform(size=n),
    "score": score,
})

fig, ax = pp.subplots(axes_size=(60, 45))
pp.errorbarplot(
    data=cont_df,
    x="x",
    y="y",
    yerr="yerr",
    hue="score",
    palette="viridis",
    capsize=2,
    ax=ax,
    title="Continuous hue",
    xlabel="x",
    ylabel="y",
)
pp.show()
Continuous hue

Custom Capsize

capsize defaults to rcParams['capsize'] (currently 0 — no caps). Pass capsize=2 (or any positive value) for the publication look. capthick defaults to the stem linewidth.

pp.errorbarplot(
    data=basic_df,
    x="dose",
    y="response",
    yerr="sem",
    capsize=4,
    capthick=1.0,
    title="Larger caps",
    xlabel="dose (mg)",
    ylabel="response",
)
pp.show()
Larger caps

Custom Errorbar Styling via errorbar_kws

All extra kwargs accepted by matplotlib.axes.Axes.errorbar() pass through errorbar_kws=. The most useful overrides are ecolor= (force a non-edgecolor stem color) and elinewidth= (thicker or thinner stems than the default).

pp.errorbarplot(
    data=basic_df,
    x="dose",
    y="response",
    yerr="sem",
    capsize=2,
    errorbar_kws=dict(ecolor="#8b0000", elinewidth=1.2),
    title="Red, thicker stems",
    xlabel="dose (mg)",
    ylabel="response",
)
pp.show()
Red, thicker stems

Forcing Neutral Stems on a Hue Plot

Caller-supplied errorbar_kws['ecolor'] wins over the per-hue coloring. Pass it when you want hue-colored markers on top of a uniform, neutral set of stems — e.g. when groups overlap heavily or you want the marker fill alone to carry the hue.

fig, ax = pp.subplots(axes_size=(60, 45))
pp.errorbarplot(
    data=hue_df,
    x="x",
    y="y",
    yerr="yerr",
    hue="group",
    palette="pastel",
    capsize=2,
    errorbar_kws=dict(ecolor="0.4"),
    ax=ax,
    title="Neutral stems, hue-colored markers",
    xlabel="x",
    ylabel="response",
)
pp.show()
Neutral stems, hue-colored markers

Total running time of the script: (0 minutes 3.541 seconds)

Gallery generated by Sphinx-Gallery