Most real data is a time series, and a value without its uncertainty can mislead.
Matplotlib understands datetime, numpy.datetime64 and pandas timestamps on either axis: pass them to plot directly. It converts them to floating-point days internally and picks date-aware ticks.
To control the ticks, use the date locators and formatters from matplotlib.dates:
mdates.MonthLocator(),WeekdayLocator(),DayLocator(interval=7)choose positions;mdates.DateFormatter("%b %Y")formats with strftime codes;mdates.ConciseDateFormatter(locator)produces compact, non-repetitive labels (year shown only when it changes) and is usually the best default.
fig.autofmt_xdate() rotates and right-aligns crowded date labels.
For uncertainty:
ax.errorbar(x, y, yerr=err, fmt="o", capsize=3)draws points with error bars;yerrcan be a scalar, one value per point, or a 2xN array for asymmetric errors (below, above).ax.fill_between(x, low, high, alpha=0.25)draws a shaded band, which reads better than error bars for dense series such as forecasts or rolling statistics.
Say in the caption or legend what the bars mean: one standard deviation, standard error and a 95% confidence interval differ by large factors.
With pandas, df.plot() already uses these mechanisms; any formatter you set afterwards on ax.xaxis still applies.
Example
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
days = np.arange("2026-01-01", "2026-04-01", dtype="datetime64[D]")
rng = np.random.default_rng(3)
y = np.cumsum(rng.normal(size=days.size))
err = 1.0 + 0.02 * np.arange(days.size) # uncertainty grows over time
fig, ax = plt.subplots(layout="constrained")
ax.plot(days, y, color="C0")
ax.fill_between(days, y - err, y + err, color="C0", alpha=0.25)
loc = mdates.MonthLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.ConciseDateFormatter(loc))
fig.canvas.draw()
print(days.size) # 90
print([t.get_text() for t in ax.get_xticklabels()]) # ['2026', 'Feb', 'Mar', 'Apr']
fig.savefig("ts.png")Remember
- Pass datetimes straight to
plot; Matplotlib picks date ticks ConciseDateFormattergives compact, readable date labels- Use
errorbarfor sparse points andfill_betweenbands for dense series
Watch out for
- Showing error bars without stating whether they are standard deviation, standard error or a confidence interval.