To plot error bars in Matplotlib, use plt.errorbar(x, y, yerr=errors); add xerr for horizontal error bars and capsize for the little caps. For a bar chart, pass yerr to plt.bar(). This guide covers plt.errorbar step by step: styling, error bars without a connecting line, asymmetric error bars, calculating the error (standard deviation or standard error) with pandas, bar charts, dates on the x-axis, and shaded error bands.
Tested with Python 3.12.5, Matplotlib 3.11.2, NumPy 2.5.3 and pandas 3.0.6. The charts are real Matplotlib windows and the table comes from the Windows Command Prompt. Reference: matplotlib.pyplot.errorbar.
Basic error bars with plt.errorbar()
import matplotlib.pyplot as plt
doses = [0, 10, 20, 30, 40, 50]
response = [2.1, 3.8, 5.9, 7.2, 8.1, 8.6]
error = [0.4, 0.5, 0.6, 0.5, 0.7, 0.6]
plt.errorbar(doses, response, yerr=error, capsize=4, marker="o")
plt.xlabel("Dose (mg)")
plt.ylabel("Response")
plt.title("plt.errorbar with vertical error bars")
plt.show()
yerr draws a vertical bar of ± error at each point.| Argument | What it does |
|---|---|
yerr, xerr | Error size: one number for all points, one per point, or [lower, upper] |
fmt | Marker and line format, e.g. "o" (markers only) or "-o" |
capsize, capthick | Length and thickness of the caps |
ecolor, elinewidth | Colour and width of the error bars |
errorevery | Draw an error bar only on every n-th point |
uplims, lolims | Show arrows for upper or lower limits |
x and y error bars without a line
fmt="o" (or any marker without a line style) draws only the markers and the error bars, like a scatter plot with error bars:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(4)
x = np.arange(1, 9)
y = 2 * x + rng.normal(0, 1.5, 8)
xerr = rng.uniform(0.2, 0.5, 8)
yerr = rng.uniform(0.8, 2.0, 8)
plt.errorbar(x, y, xerr=xerr, yerr=yerr,
fmt="s", # markers only: no connecting line
color="darkblue", ecolor="gray", elinewidth=1.5, capsize=5, capthick=1.5, markersize=6)
plt.title("x and y error bars, fmt='s' (no line)")
plt.grid(alpha=0.3)
plt.show()
xerr + yerr with fmt="s": no line between the points.Asymmetric error bars
When the error is not the same above and below the point, pass a list of two sequences: the distances below and the distances above:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [10, 14, 12, 18, 16]
lower = [1, 2, 1.5, 3, 1] # distance below each point
upper = [3, 1, 4, 2, 5] # distance above each point
plt.errorbar(x, y, yerr=[lower, upper], fmt="o", capsize=5, color="tab:red")
plt.title("Asymmetric error bars: yerr=[lower, upper]")
plt.show()
yerr=[lower, upper].Both lists contain positive distances, not the end values. If you have lower and upper bounds (for example a confidence interval), convert them first: lower = y - lo, upper = hi - y.
For more examples, see asymmetric error bars in Matplotlib.
Calculate the error: standard deviation or standard error
Error bars usually show the standard deviation (spread of the data) or the standard error of the mean (SEM, uncertainty of the mean). With pandas you can get both per group:
import numpy as np
import pandas as pd
rng = np.random.default_rng(10)
df = pd.DataFrame({
"group": np.repeat(["Control", "Drug A", "Drug B"], 12),
"score": np.concatenate([rng.normal(50, 6, 12), rng.normal(58, 8, 12), rng.normal(63, 5, 12)]),
})
summary = df.groupby("group")["score"].agg(["mean", "std", "count"])
summary["sem"] = summary["std"] / np.sqrt(summary["count"]) # standard error of the mean
print(summary.round(2))
Output:
mean std count sem
group
Control 48.85 4.11 12 1.19
Drug A 53.99 6.05 12 1.75
Drug B 62.89 5.22 12 1.51
Always say in the axis label or caption which one you plot: SEM bars are much shorter than standard-deviation bars for the same data.
Bar chart with error bars
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
rng = np.random.default_rng(10)
df = pd.DataFrame({
"group": np.repeat(["Control", "Drug A", "Drug B"], 12),
"score": np.concatenate([rng.normal(50, 6, 12), rng.normal(58, 8, 12), rng.normal(63, 5, 12)]),
})
summary = df.groupby("group")["score"].agg(["mean", "std", "count"])
summary["sem"] = summary["std"] / np.sqrt(summary["count"])
fig, ax = plt.subplots(figsize=(6, 4.5))
ax.bar(summary.index, summary["mean"], yerr=summary["sem"], capsize=8,
color=["gray", "tab:blue", "tab:green"], edgecolor="black") # bar chart with error bars
ax.set_ylabel("Mean score (± SEM)")
plt.show()
ax.bar(..., yerr=summary["sem"], capsize=8).Error bars with dates on the x-axis
errorbar() accepts datetime values for x, so time series with uncertainty work the same way:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
dates = pd.date_range("2025-01-01", periods=8, freq="W")
temperature = [3.1, 4.0, 2.5, 5.2, 6.8, 6.1, 8.4, 9.0]
spread = [1.2, 0.9, 1.5, 1.1, 1.4, 0.8, 1.0, 1.3]
fig, ax = plt.subplots(figsize=(8, 4))
ax.errorbar(dates, temperature, yerr=spread, fmt="-o", capsize=4) # dates work as x values
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d %b"))
ax.set_ylabel("Weekly mean temperature (°C)")
fig.autofmt_xdate()
plt.show()
Many points: errorevery and shaded error bands
With dense data, a bar at every point is hard to read. Draw one every n points with errorevery, or show the error as a shaded band with fill_between():
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 50)
y = np.sin(x) + x / 3
err = 0.2 + 0.05 * x
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.errorbar(x, y, yerr=err, errorevery=5, capsize=3) # a bar on every 5th point
ax1.set_title("errorevery=5")
ax2.plot(x, y)
ax2.fill_between(x, y - err, y + err, alpha=0.3, label="± error") # shaded error band
ax2.set_title("fill_between error band")
ax2.legend()
plt.tight_layout()
plt.show()
errorevery=5 (left) and a fill_between band (right).Error bars for several series
Shift each series slightly on the x-axis so the error bars do not hide each other:
import matplotlib.pyplot as plt
import numpy as np
weeks = np.arange(1, 7)
series = {"Model A": ([70, 74, 77, 81, 83, 86], [3, 3, 2, 2, 3, 2]),
"Model B": ([68, 71, 76, 78, 84, 88], [4, 3, 3, 4, 3, 3])}
fig, ax = plt.subplots(figsize=(7, 4.5))
for shift, (name, (mean, err)) in zip([-0.1, 0.1], series.items()):
ax.errorbar(weeks + shift, mean, yerr=err, fmt="o-", capsize=4, label=name) # shift so bars do not overlap
ax.set_xlabel("Week")
ax.set_ylabel("Accuracy (%)")
ax.legend()
plt.show()
Related Matplotlib chart guides:
- Plot asymmetric error bars in Matplotlib
- Plot a bar chart in Matplotlib
- Plot multiple lines in Python
- Plot a line of best fit
- Set the x-axis label
Frequently asked questions
How do I plot error bars in Matplotlib?
Use plt.errorbar(x, y, yerr=errors, capsize=4). errors can be one number, one value per point, or [lower, upper].
How do I plot error bars without a line?
Pass a marker-only format: plt.errorbar(x, y, yerr=e, fmt="o"). Use fmt="none" to draw only the error bars.
How do I make asymmetric error bars?
Give yerr two sequences: yerr=[lower, upper], where both contain positive distances from each point.
How do I add error bars to a bar chart?
Pass yerr (and capsize) to plt.bar() or ax.bar().
Should error bars show standard deviation or standard error?
Standard deviation shows the spread of the data; standard error (std / √n) shows the uncertainty of the mean. Label which one you use.
How do I change the colour and cap size of error bars?
Use ecolor for the bar colour, elinewidth for their width, and capsize / capthick for the caps.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn