Your first charts
Matplotlib is the drawing engine behind most Python charts, including the ones pandas and seaborn produce for you. Learn one small recipe and you can plot almost anything.
The recipe every chart follows
- Create a Figure (the canvas) and one or more Axes (the plot panels) with
plt.subplots(). - Draw your data on an Axes:
ax.plot(),ax.bar(),ax.scatter(). - Label it, tidy it, then show or save it.
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
sales = [120, 150, 170, 160, 195, 210] # ₹ '000, electronics store in Nashik
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(months, sales, marker="o", color="#F5A524", linewidth=2)
ax.set_title("Monthly sales (₹ '000)")
ax.set_xlabel("Month")
ax.set_ylabel("Sales")
ax.grid(alpha=.3)
fig.tight_layout()
plt.show()
figsize is in inches, so (8, 4) gives a wide chart that fits a slide. fig.tight_layout() stops long labels from being clipped.
Bar charts compare categories
Swap ax.plot for ax.bar, and sort the categories so the reader does not have to.
pairs = sorted(zip([48.2, 31.5, 18.9, 12.4],
["Mumbai", "Pune", "Nagpur", "Nashik"]))
revenue, cities = zip(*pairs) # ascending, so barh reads top-down
fig, ax = plt.subplots(figsize=(7, 4))
bars = ax.barh(cities, revenue, color="#2B7A78")
ax.bar_label(bars, fmt="%.1f", padding=3)
ax.set_xlabel("Revenue (₹ lakh)")
ax.set_title("Revenue by city, FY 2025-26")
Horizontal bars (barh) are kinder to long city names than rotated tick labels, and ax.bar_label prints the value at the end of each bar so no one has to squint at the axis.
Scatter shows a relationship
import numpy as np
rng = np.random.default_rng(7)
ad_spend = rng.uniform(10, 90, 40) # ₹ '000
units = 60 + 2.1 * ad_spend + rng.normal(0, 25, 40)
fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(ad_spend, units, s=45, alpha=.7, edgecolor="white")
ax.set_xlabel("Ad spend (₹ '000)")
ax.set_ylabel("Units sold")
ax.set_title("Does ad spend move units?")
alpha makes overlapping points visible, and s controls marker size.
Which method for which job
| Method | Draws | Question it answers |
|---|---|---|
ax.plot |
Line | How did sales move over the quarter? |
ax.bar / ax.barh |
Bars | Which city sells the most? |
ax.scatter |
Points | Does ad spend drive units? |
ax.hist |
Histogram | How are bill values spread? |
ax.fill_between |
Shaded band | What is the best-to-worst range? |
Common mistakes
- Calling
plt.show()beforefig.savefig(). In a script the figure is cleared, so the saved file is blank. Save first. - Leaving axes unlabelled. "Sales" means nothing without rupees, units and a period.
- Using
ax.plot()for categories such as cities; a line implies an order that does not exist. - Drawing dozens of series on one Axes. Three or four lines is usually the limit before the chart turns into spaghetti.
- Forgetting that
plt.subplots()returns a tuple:fig, ax = plt.subplots(), notax = plt.subplots().
Practice
Build a small DataFrame of six months of sales for three stores. Draw a line chart of the chain total, a sorted horizontal bar chart of store totals with bar_label, and a scatter of footfall against sales. Give each chart a title, axis labels with units, and save all three as PNG files.