Plotting and quick exploratory charts
df.plot, the chart kinds worth knowing, subplots for comparisons, styling, and when to hand the figure over to Matplotlib or Seaborn.
One line to a chart
import matplotlib.pyplot as plt
df.plot(x="date", y="sales", kind="line", figsize=(9, 4), title="Daily sales")
df.groupby("team")["score"].mean().sort_values().plot(kind="barh")
df.plot.scatter(x="price", y="units", alpha=0.6, s=12)
df["score"].plot.hist(bins=20, edgecolor="white")
df.set_index("date")["sales"].resample("ME").sum().plot.area(stacked=False)
df[["score", "hours"]].plot(subplots=True, layout=(1, 2), sharex=False, figsize=(11, 4))
plt.tight_layout()
plt.show()- The index is the x-axis by default; when a date column exists,
set_indexfirst or passx=explicitly. - A
DatetimeIndexgets sensible date ticks automatically - one of the few places where the index being special is a help. - Plot from an aggregated frame, not from raw rows:
groupbyorresamplefirst, or the chart shows noise at full resolution. - Matplotlib must be installed; pandas only dispatches to it.
Choosing a chart kind
| kind | Shows |
|---|---|
line | A trend over an ordered axis, usually time |
bar / barh | Comparison between categories; horizontal when labels are long |
hist | The distribution of one numeric column |
box | Spread and outliers per group |
scatter | Relationship between two numeric columns |
area | Composition over time, stacked |
kde | A smoothed version of the histogram |
pie | Parts of a whole - readable with at most four slices |
💡
A pandas plot is a Matplotlib figure:
ax = df.plot(...) returns the axes, so you can keep styling with ax.set_ylabel(), ax.legend() and ax.axhline(). There is no separate charting language to learn.When to leave pandas
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
long = df.melt(id_vars=["date"], value_vars=["sales", "returns"], var_name="metric")
for name, part in long.groupby("metric"):
axes[0].plot(part["date"], part["value"], label=name)
axes[0].legend(loc="upper left")
axes[0].set_title("Sales and returns")
df.boxplot(column="score", by="team", ax=axes[1])
plt.suptitle("")
plt.tight_layout()- Long format plus a
groupbyloop is the general pattern for several series with a legend - the samemeltyou use for modelling. - Move to Seaborn when you need faceting, regression lines or statistical summaries:
sns.relplot(data=df, x=..., y=..., col=...). - Move to Matplotlib when you need exact control of axes, annotations or a publication layout.
- Never build a chart by calling
plot()repeatedly on the same axes without checking which object owns the state; collect the axes explicitly.
FAQ
How do I save a chart to a file?
Keep the plot call and call
plt.savefig("chart.png", dpi=150, bbox_inches="tight") before plt.show(). Saving after showing can produce an empty file in some backends.Why is my chart empty?
Usually the data was not aggregated or the axis is text: a line plot needs a sorted numeric or datetime x-axis. Inspect the aggregated frame you plotted - the bug is almost always there, not in the plotting call.
Related
Dates, times and time series Pivot tables and crosstab
Last refreshed 2026-09-18.