Learn to choose, build and export charts that answer analytical questions—not just produce graphics.
Complete 12 of 24 practices (50%) and enter your name to unlock the Certificate of Participation.
Matplotlib is Python’s foundational plotting library. The most useful mental model is simple: a Figure is the full canvas, an Axes is one plotting area inside it, and the visible elements—lines, text, markers, bars—are Artists placed on that canvas.
Think like a report designer: the Figure is the page, the Axes is the chart panel, and every label, line and marker is an object you can control.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [72, 81, 95])
ax.set_title("Service Resolution Score")
ax.set_xlabel("Week")
ax.set_ylabel("Score")
plt.show()For quick exploration, pyplot is fine. For reusable business charts, dashboards, reports or multiple panels, prefer explicit Figure/Axes objects.
A line chart is strongest when the horizontal axis has meaningful order—especially time. It helps the eye follow direction, turning points and rate of change.
If a manager asks “Are response times improving week by week?”, the line is not decoration—it encodes continuity across time.
import matplotlib.pyplot as plt
weeks = [1, 2, 3, 4, 5]
avg_days = [6.2, 5.8, 5.1, 4.9, 4.4]
fig, ax = plt.subplots()
ax.plot(weeks, avg_days, marker="o")
ax.set_title("Average Resolution Time")
ax.set_xlabel("Week")
ax.set_ylabel("Days")
ax.grid(True, alpha=0.25)
plt.show()Use a line when connection between adjacent x-values is meaningful. Do not connect unrelated categories just because a line looks smooth.
Scatter plots place one numeric variable on each axis. They are ideal for asking whether two measures move together, whether groups form, and which observations behave unusually.
Imagine each point is one city service request type: x = volume, y = average days. The upper-right corner immediately exposes high-volume, slow-resolution areas.
import matplotlib.pyplot as plt
volume = [120, 210, 95, 310, 180]
avg_days = [2.1, 3.8, 1.9, 6.2, 4.0]
fig, ax = plt.subplots()
ax.scatter(volume, avg_days, s=70, alpha=0.75)
ax.set_title("Request Volume vs Resolution Time")
ax.set_xlabel("Monthly Requests")
ax.set_ylabel("Average Days")
plt.show()Scatter does not prove causation. It reveals structure worth investigating: direction, strength, clusters and unusual points.
Bar charts compare magnitudes across discrete categories. Their power comes from a shared baseline and easy length comparison, making them excellent for departments, products, regions or status groups.
If the question is “Which department has the most open requests?”, the bar length should make the answer visible before the reader studies exact labels.
import matplotlib.pyplot as plt
departments = ["Police", "Fire", "Parks", "Public Works"]
open_cases = [142, 88, 61, 173]
fig, ax = plt.subplots()
ax.barh(departments, open_cases)
ax.set_title("Open Service Requests")
ax.set_xlabel("Open Requests")
plt.show()Choose bars for category magnitude. If your x-axis is continuous time, a line may communicate the pattern more naturally.
A histogram groups numeric observations into bins and counts how many fall in each interval. It answers a different question from a bar chart: not “which category is larger?” but “how are numeric values distributed?”
Average resolution time can hide operational pain. A histogram can reveal whether most cases close quickly while a long tail of cases remains open for weeks.
import matplotlib.pyplot as plt
days_open = [1, 2, 2, 3, 3, 4, 4, 5, 7, 9, 12, 18, 27]
fig, ax = plt.subplots()
ax.hist(days_open, bins=6, edgecolor="black")
ax.set_title("Distribution of Days Open")
ax.set_xlabel("Days Open")
ax.set_ylabel("Number of Requests")
plt.show()A histogram summarizes a distribution; it does not preserve the identity of every observation. Use a scatter, strip-style view or table when individual identity matters.
A technically correct chart can still fail if the reader cannot identify the metric, units, comparison or key exception. Labels and annotations should reduce interpretation effort—not decorate the page.
The best annotation answers “why should I look here?” A note such as “system outage” next to a spike is more useful than labeling every point.
import matplotlib.pyplot as plt
months = ["May", "Jun", "Jul", "Aug", "Sep"]
incidents = [42, 47, 51, 93, 55]
fig, ax = plt.subplots()
ax.plot(months, incidents, marker="o", label="Incidents")
ax.set_title("Monthly Incident Volume")
ax.set_ylabel("Incidents")
ax.legend()
ax.annotate(
"System outage",
xy=("Aug", 93),
xytext=("Jun", 105),
arrowprops={"arrowstyle": "->"}
)
plt.show()Every extra label has a cost. Add text when it changes understanding; remove it when it only repeats what the chart already shows.
Subplots let several related views share one Figure. This is powerful when the panels answer parts of one question—trend, distribution, category comparison—but weak when unrelated charts are crowded together.
A useful operations page might show: top-left = weekly trend, top-right = department ranking, bottom = distribution of resolution days. Each panel adds a different angle to the same operational story.
import matplotlib.pyplot as plt
fig, axes = plt.subplots(
1, 2,
figsize=(10, 4),
constrained_layout=True
)
axes[0].plot([1, 2, 3, 4], [8, 7, 6, 5], marker="o")
axes[0].set_title("Avg Days by Week")
axes[1].bar(["A", "B", "C"], [42, 31, 18])
axes[1].set_title("Open Cases by Team")
plt.show()Use multiple panels when comparison benefits from proximity. If each chart answers a different audience or decision, separate pages may be clearer.
The final skill is not drawing a chart—it is producing a reproducible visual deliverable. A strong workflow prepares data, builds the Figure, validates labels and scales, and exports a file suitable for reports, web pages or presentations.
Think pipeline, not screenshot: raw table → Pandas summary → Matplotlib Figure → validated export. If the data changes next week, the same code should rebuild the chart.
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
"Department": ["Fire", "Parks", "Police", "Public Works"],
"Open": [88, 61, 142, 173]
})
summary = df.sort_values("Open")
fig, ax = plt.subplots(figsize=(8, 4))
ax.barh(summary["Department"], summary["Open"])
ax.set_title("Open Requests by Department")
ax.set_xlabel("Open Requests")
fig.savefig(
"open_requests.png",
dpi=300,
bbox_inches="tight"
)
plt.show()Export the Figure from code instead of relying on screenshots. That preserves repeatability, dimensions and output quality.
Open each item only after answering it in your own words. These are review prompts; the 24 interactive practices above drive certificate progress.
The Figure is the complete canvas. An Axes is one plotting region inside that Figure.
Line for ordered progression; bars for categories; scatter for numeric relationships.
A histogram groups numeric values into intervals; bars compare discrete categories.
It explains a meaningful event or exception that changes interpretation.
A controlled code pipeline that can regenerate the visual from refreshed data.
| Need | Matplotlib | Seaborn | Plotly |
|---|---|---|---|
| Precise low-level control of static charts | Strong | Built on Matplotlib | Different model |
| Fast statistical visualization from tidy data | Possible | Strong | Possible |
| Interactive hover, zoom and web-first charts | Limited by default | Limited by default | Strong |
| Foundation for learning Python visualization concepts | Excellent | Helpful next layer | Useful complementary tool |
These tools overlap. Matplotlib is the foundational layer in this series.
The technical concepts in this training follow Matplotlib’s official documentation and tutorials.
“I can build clear Matplotlib visuals using the Figure/Axes model, choose appropriate chart types, add meaningful labels and annotations, compose multiple panels, and export reproducible figures.”
Complete at least 12 of the 24 practice cases (50%) and enter your name.