Three routes
| Route | Use it for |
|---|---|
df.plot() | Quick exploration — one line, no setup |
matplotlib | Full control over every element |
seaborn | Statistical charts and better defaults |
They work together: seaborn returns matplotlib objects, so you can style a seaborn chart with matplotlib calls.
The quick route
import matplotlib.pyplot as plt
df.plot(x='month', y='revenue')
plt.show()
Good enough for looking at something yourself. Not good enough to put in front of anyone else.
Presentable
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(df['month'], df['revenue'], linewidth=2)
ax.set_title('Monthly revenue, 2024')
ax.set_xlabel('Month')
ax.set_ylabel('Revenue ($)')
ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()
Always call tight_layout
Without it, axis labels and titles get cropped when you save the figure — and you usually only notice after sending it.
The fig/ax pattern
fig, ax = plt.subplots() is worth adopting as a default. fig is the whole image, ax is the plot area — and having a named ax is what lets you build several charts side by side:
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(df['month'], df['revenue'])
axes[1].bar(df['region'], df['total'])Saving
plt.savefig('revenue.png', dpi=150, bbox_inches='tight')
bbox_inches='tight' crops the whitespace. Call savefig before plt.show() — showing the figure clears it, and you get a blank file otherwise.