Error Bars: SD vs SE vs 95% CI, and How to Show Uncertainty in a Graph on the X-Axis

⏱️ 10 min read 📊 Visualization

Standard deviation (SD) error bars show how spread out the individual values are. Standard error (SE) and 95% confidence interval (CI) error bars show how precisely the mean has been estimated. All three are drawn the same way, yet on the same data an SD bar is √n times longer than an SE bar, so a chart that doesn't say which one it shows can't be read.

Quick answer: Use SD error bars (mean ± SD) to show how much individual observations vary. SD does not shrink as you collect more data. Use SE (SD/√n), or better a 95% CI (mean ± t × SE, roughly mean ± 2 × SE once n is 10 or more), to show how precisely you know the mean and to compare groups. Always state in the caption which one is drawn and what n is. To show uncertainty on the x-axis, draw horizontal error bars: xerr in matplotlib, or X error bars on a scatter chart in Excel.

What do standard deviation, standard error, and confidence interval error bars show?

They answer different questions. In their 2007 Journal of Cell Biology paper "Error bars in experimental biology," Cumming, Fidler and Vaux call SD bars descriptive, because they describe the data you collected. SE and CI bars are inferential, because they tell you about the population mean you are trying to estimate. The two kinds look identical on a chart, which is the root of most error-bar confusion.

Error barFormulaWhat it showsShrinks with more data?
Standard deviation (SD)√(Σ(x − x̄)² / (n − 1))Spread: how much individual values vary around the meanNo. It settles near the population SD
Standard error (SE)SD / √nPrecision: how much the sample mean would vary from sample to sample. ±1 SE is only about a 68% interval in large samplesYes, in proportion to 1/√n
95% confidence intervalx̄ ± t × SEPrecision: the range of population means compatible with the data. The best default for comparing groupsYes, roughly as 1/√n (t also falls as n grows)

What are the formulas for SD, SE, and a 95% confidence interval?

SE is the SD divided by the square root of the sample size, and a 95% CI for a mean is the mean plus or minus a t multiplier times the SE. Use the sample SD, with n − 1 in the denominator (the standard deviation explainer covers why). These formulas are for the mean of independent observations. Proportions, medians, and model coefficients have different SE formulas, but the choice between SD, SE, and CI, and the captioning rule, work the same way.

SD      = sqrt( Σ(xᵢ − x̄)² / (n − 1) )
SE      = SD / sqrt(n)
95% CI  = x̄ ± t(0.975, n − 1) × SE      (≈ x̄ ± 1.96 × SE for large n)

t(0.975, df) by sample size:
  n = 3    → 4.30
  n = 5    → 2.78
  n = 10   → 2.26
  n = 30   → 2.05
  n = 100  → 1.98
  very large → 1.96

That table is why "double the SE bars" is only an approximation. Cumming and colleagues' rule of thumb is that doubling SE bars gives an approximate 95% CI when n is 10 or more, but with n = 3 you have to multiply by about 4. Even at n = 10, 2 × SE is about 12% shorter than the true 95% CI. For more on interpreting the interval itself, see confidence intervals explained.

How different are SD, SE, and CI error bars on the same data?

Very different. Here is one worked example: the response time of an API in 10 independent test runs, with each type of error bar computed from the same numbers.

Response times (ms), n = 10:
210, 240, 190, 280, 230, 260, 200, 250, 220, 270

Mean                 = 2350 / 10                 = 235.0 ms
Sum of squared devs  = 8,250
SD                   = sqrt(8,250 / 9)           = 30.3 ms
SE                   = 30.3 / sqrt(10)           = 9.6 ms
t(0.975, 9)          = 2.262
95% CI half-width    = 2.262 × 9.57              = 21.7 ms

What the error bar spans:
  ±1 SD   → 204.7 to 265.3 ms   (bar length ±30.3)
  95% CI  → 213.3 to 256.7 ms   (bar length ±21.7)
  ±1 SE   → 225.4 to 244.6 ms   (bar length ±9.6)

On identical data, the SD bar is 3.16 times (√10) the length of the SE bar. Now imagine 100 runs with the same spread. SD would still be about 30 ms, but SE would drop to about 3.0 ms and the 95% CI half-width to about 6.0 ms (1.98 × 3.03). The spread of the data hasn't changed. Only your knowledge of the mean has.

When should I use SD vs SE vs 95% CI error bars?

Pick the bar that matches the claim the chart makes. If the message is about variability ("individual response times typically vary by about ±30 ms"), use SD. If the message is about a mean or a comparison of means ("the new API is faster"), use an inferential bar, and prefer the 95% CI over SE.

Error bars are for discrete points and bars. For a continuous line such as a trend or forecast, a shaded band usually works better. See showing uncertainty in charts for bands and fan charts.

Why does the caption have to say which error bar is shown?

Because the same drawing can mean three different things, and the reader can't tell from the chart. In the example above, a bar reaching ±9.6 ms and a bar reaching ±30.3 ms support very different conclusions, and the graphic gives no hint which one you chose. The first two of Cumming, Fidler and Vaux's eight rules cover exactly this. Rule 1: always describe in the figure legend what the error bars are. Rule 2: state n, the number of independent observations or experiments, in the legend.

Weak:   "Mean response time by API version (± error)."
Good:   "Mean response time by API version. Error bars show 95% confidence
         intervals (t-based); n = 10 independent runs per version."

What does it mean when error bars overlap?

It depends on the bar type, and overlap rarely means what people assume. The rules below are rough shortcuts for comparing two independent groups with similar sample sizes and bar lengths. The P-value thresholds for overlapping CIs and for gaps between SE bars come from Cumming, Fidler and Vaux (2007). The rest follows from how each bar is calculated.

Adding a second group to the example shows the trap. New API: n = 10, mean 202 ms, 95% CI 189.5 to 214.5 ms. Old API: 213.3 to 256.7 ms. The CIs overlap from 213.3 to 214.5, but Welch's t-test gives t = 2.98, P ≈ 0.01, and the 95% CI for the 33 ms difference is 9.3 to 56.7 ms, well clear of zero. The SD bars (184.5 to 219.5 and 204.7 to 265.3) overlap heavily. For a real decision, skip the eyeballing and compute the CI of the difference, as explained in overlapping confidence intervals. The full set of eight rules, with figures, is in the original paper: Cumming, Fidler & Vaux, "Error bars in experimental biology," J Cell Biol 177(1):7–11.

How do I add SD, SE, or CI error bars in Excel?

Compute the bar lengths yourself and attach them as custom error bars. Excel's built-in "Standard Error" and "Standard Deviation" options calculate from the plotted values in the series, not from the raw observations behind each point. Every point gets the same bar, and it is almost never the one you want.

Summary table, one row per group. Row 2 = Old API, raw data on a sheet
named Data in B2:B11. Row 3 repeats it for New API (Data!C2:C11).

Col  Header              Row 2 formula                    Result
A    Group               Old API
B    Mean                =AVERAGE(Data!B2:B11)            235
C    SD                  =STDEV.S(Data!B2:B11)            30.28
D    n                   =COUNT(Data!B2:B11)              10
E    SE                  =C2/SQRT(D2)                     9.57
F    95% CI half-width   =CONFIDENCE.T(0.05, C2, D2)      21.66

1. Select A1:B3 → Insert → Column chart (or a scatter/dot chart)
2. Click the chart → Chart Elements (+) → Error Bars → More Options
3. In Format Error Bars: Direction = Both, End Style = Cap
4. Error Amount → Custom → Specify Value
5. Positive Error Value: clear ={1} and select F2:F3
   Negative Error Value: clear ={1} and select F2:F3
   (use column C for SD bars, column E for SE bars)

CONFIDENCE.T(alpha, standard_dev, size) returns the t-based half-width, t × SD/√n, which is exactly the ± amount you need. Avoid CONFIDENCE.NORM for small samples, because it uses 1.96 instead of the t value. For asymmetric intervals, such as bootstrap CIs, put the upper and lower distances in separate columns and point the positive and negative boxes at different ranges.

How do I draw error bars in matplotlib?

Compute the lengths, then pass them to yerr on ax.errorbar() for points or ax.bar() for bars. Matplotlib doesn't calculate SD, SE, or CIs for you. It draws whatever distances you give it.

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

data = {
    "Old API": np.array([210, 240, 190, 280, 230, 260, 200, 250, 220, 270]),
    "New API": np.array([190, 205, 180, 230, 200, 215, 175, 220, 195, 210]),
}
labels = list(data)
means = [v.mean() for v in data.values()]
sd = [v.std(ddof=1) for v in data.values()]          # sample SD (NumPy defaults to ddof=0)
se = [stats.sem(v) for v in data.values()]           # SD / sqrt(n), ddof=1 by default
ci = [stats.t.ppf(0.975, len(v) - 1) * stats.sem(v)  # t × SE = 95% CI half-width
      for v in data.values()]

fig, ax = plt.subplots()
ax.errorbar(labels, means, yerr=ci, fmt="o", capsize=4)   # or: ax.bar(labels, means, yerr=ci, capsize=4)
ax.set_ylabel("Mean response time (ms)")
ax.set_title("Error bars show 95% CIs; n = 10 runs per API")
plt.show()

yerr accepts a single number (same bar everywhere), one value per point (symmetric), or a 2 × N array [lower, upper] of positive distances for asymmetric bars. Put the bar type and n in the title or caption, as above.

How to show uncertainty in a graph on the x-axis?

Draw horizontal error bars. Use them when the x variable itself is measured with error, such as a temperature reading good to ±0.5 °C, or when the estimate sits on the x-axis, as in a horizontal dot plot, forest plot, or coefficient plot. In matplotlib, pass xerr instead of, or as well as, yerr:

# Continues from the matplotlib example above (np, plt, labels, means, ci)

# x measured with uncertainty: ±0.5 °C on x, SE on y
temp = np.array([10, 20, 30, 40])
rate = np.array([1.2, 2.1, 3.3, 3.9])
rate_se = np.array([0.15, 0.20, 0.25, 0.30])
fig, ax = plt.subplots()
ax.errorbar(temp, rate, xerr=0.5, yerr=rate_se, fmt="o", capsize=3)

# Estimates on the x-axis (forest-plot style): horizontal 95% CIs
fig, ax = plt.subplots()
ax.errorbar(means, labels, xerr=ci, fmt="o", capsize=4)
ax.set_xlabel("Mean response time (ms), bars = 95% CI")

# Horizontal bar chart
fig, ax = plt.subplots()
ax.barh(labels, means, xerr=ci, capsize=4)

In Excel, horizontal error bars exist only on scatter (XY) and bubble charts. On a horizontal bar chart, the ordinary error bars already run left to right along the value axis. Column and line charts support vertical error bars only.

1. Put x values, y values, and x uncertainties in columns → Insert → Scatter
2. Chart Elements (+) → tick Error Bars (a scatter chart gets both X and Y bars)
3. Format tab → Current Selection dropdown → choose the "... X Error Bars" entry
   → Format Selection
4. Error Amount → Custom → Specify Value → select your x-uncertainty range
   for both Positive and Negative Error Value
5. To keep only horizontal bars: pick "... Y Error Bars" in the same dropdown
   and press Delete

Common mistakes

Most error-bar problems come from not knowing what was drawn, or from drawing the flattering option:

Pro Tip: Plot the individual observations as a strip of semi-transparent dots behind the mean and its 95% CI. Readers see the spread that SD bars would have shown and the precision that the CI shows, and there's nothing to confuse, because each kind of uncertainty has its own mark.

← Back to Visualization Tips