Data Analysis for Engineers/Module 4

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

  1. Add a third panel showing a 7-day rolling average of energy (Module 2's rolling pattern).
  2. Change the layout to 1 row x 2 columns instead of 2 rows x 1 column, and adjust figsize.
  3. 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

  1. What does sharex=True accomplish in plt.subplots()?
  2. What matplotlib function draws an arrow pointing to a specific data point?
  3. Why combine the two series into one multi-panel figure instead of two separate charts?
Answer key
  1. All subplots share the same x-axis scale/limits, keeping them aligned
  2. ax.annotate() with an arrowprops argument
  3. 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