Module 4 · Section 3 of 10
Lesson 4.2 - Multi-panel Figures
Target: ~9 min read - 20 min hands-on
Overview
plt.subplots(nrows, ncols) creates a grid of Axes within one Figure - the standard way
to build a "dashboard" view combining several related charts. We'll build a 2-panel
facility dashboard: energy on top, ambient temperature below, sharing the same date
axis, plus an annotation flagging the year's peak-consumption day.
Why This Matters (Engineering Context)
Putting a driver (temperature) directly under the response (energy) on a shared timeline is the standard first figure in an energy or process report - it lets a reviewer see the relationship at a glance.
Code-Along
# subplots(2, 1) -> a 2-row x 1-col grid; axes is an array you index [0], [1].
# sharex=True locks both panels to the same x-axis range.
fig, axes = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
axes[0].bar(site1["date"], site1["energy_kwh"], width=1.0, color="steelblue")
axes[0].set_ylabel("Energy (kWh)")
axes[0].set_title("Charlie DC Facility Dashboard, 2023")
axes[1].plot(site1["date"], site1["ambient_c"], color="firebrick", linewidth=1.0)
axes[1].set_ylabel("Ambient (C)"); axes[1].set_xlabel("Date")
axes[1].xaxis.set_major_formatter(mdates.DateFormatter("%b"))
# .idxmax() gives the index LABEL of the max energy row; .loc fetches that whole row
peak_row = site1.loc[site1["energy_kwh"].idxmax()]
# annotate(text, xy=point to point at, xytext=label offset, arrowprops=arrow style)
axes[0].annotate(
f"Peak: {peak_row['energy_kwh']:.0f} kWh\n{peak_row['date'].strftime('%b %d')}",
xy=(peak_row["date"], peak_row["energy_kwh"]),
xytext=(15, 10), textcoords="offset points", # offset in points from xy
arrowprops=dict(arrowstyle="->", color="black"), fontsize=9,
)
plt.tight_layout(); plt.show()
print(f"Peak-consumption day: {peak_row['date'].date()} at {peak_row['energy_kwh']:.1f} kWh")
Run it: two stacked panels sharing the same x-axis, with an arrow annotation pointing to the single highest-consumption day of the year.
Practice Exercises
- Add a third panel showing a 7-day rolling average of energy (Module 2's rolling pattern).
- Change the layout to 1 row x 2 columns instead of 2 rows x 1 column, and adjust
figsize. - Annotate the coldest day of the year on the temperature panel, following the same pattern used for the peak day.
# Try the practice exercises here
Knowledge Check
- What does
sharex=Trueaccomplish inplt.subplots()? - What matplotlib function draws an arrow pointing to a specific data point?
- Why combine the two series into one multi-panel figure instead of two separate charts?
Answer key
- All subplots share the same x-axis scale/limits, keeping them aligned
ax.annotate()with anarrowpropsargument- A reader sees both series' timing and relationship at a glance, in the same visual frame
36 / 63 sections · Course home · Join the coaching cohort