Skip to main content
Data Visualization
CHAPTER 12 Beginner

Subplots and Multi-Chart Layouts

Updated: May 18, 2026
5 min read

# CHAPTER 12

Subplots and Multi-Chart Layouts

1. Chapter Introduction

Professional dashboards rarely show one chart. This chapter creates multi-panel layouts — from simple 2x2 grids to complex irregular layouts using GridSpec — producing print-ready analytics dashboards.

2. plt.subplots — Basic Grid

python
12345678910111213141516171819202122232425262728293031323334353637383940414243
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
revenue = [42000,48000,52000,49000,58000,63000,61000,67000,71000,69000,75000,82000]
units = [120,135,148,142,163,178,170,188,195,192,205,225]
categories = ['Electronics','Furniture','Clothing','Books']
cat_rev = [285000, 142000, 198000, 67000]

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# Top-left: Line chart
axes[0,0].plot(months, revenue, 'o-', color='#1565C0', linewidth=2.5)
axes[0,0].fill_between(range(12), revenue, alpha=0.1, color='#1565C0')
axes[0,0].set_title('Monthly Revenue', fontweight='bold')
axes[0,0].yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'${x/1000:.0f}K'))
axes[0,0].set_xticks(range(12))
axes[0,0].set_xticklabels(months, rotation=30)

# Top-right: Bar chart
axes[0,1].bar(categories, cat_rev, color=['#1565C0','#2E7D32','#E65100','#6A1B9A'])
axes[0,1].set_title('Revenue by Category', fontweight='bold')
axes[0,1].yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'${x/1000:.0f}K'))

# Bottom-left: Scatter
axes[1,0].scatter(units, revenue, alpha=0.7, s=80, color='#E91E63')
axes[1,0].set_title('Units vs Revenue', fontweight='bold')
axes[1,0].set_xlabel('Units Sold')

# Bottom-right: Histogram
axes[1,1].hist(np.random.normal(75000, 15000, 500), bins=25, color='#009688')
axes[1,1].set_title('Salary Distribution', fontweight='bold')

for ax in axes.flatten():
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.grid(True, alpha=0.3)

plt.suptitle('Business Analytics Dashboard', fontsize=15, fontweight='bold', y=1.01)
plt.tight_layout()
plt.savefig('basic_dashboard.png', dpi=150, bbox_inches='tight')
plt.show()

3. GridSpec — Irregular Layouts

python
12345678910111213141516171819202122232425262728293031323334353637
import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(16, 10))
gs = gridspec.GridSpec(3, 3, figure=fig, hspace=0.4, wspace=0.35)

# Wide chart across top (2 columns)
ax_top = fig.add_subplot(gs[0, :])
ax_top.plot(months, revenue, 'o-', color='#1565C0', linewidth=2.5)
ax_top.fill_between(range(12), revenue, alpha=0.1, color='#1565C0')
ax_top.set_title('Revenue Trend (Full Width)', fontweight='bold', fontsize=13)
ax_top.set_xticks(range(12))
ax_top.set_xticklabels(months)
ax_top.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'${x/1000:.0f}K'))

# Middle row: 3 KPI boxes
kpis = [('Total Revenue', '$756K', '#1565C0'), ('Units Sold', '1,861', '#2E7D32'), ('Avg Order', '$406', '#E65100')]
for i, (label, value, color) in enumerate(kpis):
    ax = fig.add_subplot(gs[1, i])
    ax.set_xlim(0, 1); ax.set_ylim(0, 1)
    ax.text(0.5, 0.6, value, ha='center', va='center', fontsize=24, fontweight='bold', color=color, transform=ax.transAxes)
    ax.text(0.5, 0.25, label, ha='center', va='center', fontsize=11, color='#666', transform=ax.transAxes)
    ax.axis('off')

# Bottom: Large bar + smaller pie
ax_bar = fig.add_subplot(gs[2, :2])
ax_bar.barh(categories, cat_rev, color=['#1565C0','#2E7D32','#E65100','#6A1B9A'])
ax_bar.set_title('Revenue by Category', fontweight='bold')

ax_pie = fig.add_subplot(gs[2, 2])
ax_pie.pie(cat_rev, labels=categories, autopct='%1.0f%%',
            colors=['#1565C0','#2E7D32','#E65100','#6A1B9A'],
            wedgeprops={'edgecolor': 'white'})
ax_pie.set_title('Category Share', fontweight='bold')

plt.suptitle('Executive Analytics Dashboard — Q4 2024', fontsize=14, fontweight='bold')
plt.savefig('gridspec_dashboard.png', dpi=150, bbox_inches='tight')
plt.show()

4. Common Mistakes

  • Not calling tightlayout(): Multi-chart layouts almost always need it to prevent overlap.
  • Too many charts per figure: More than 6-8 panels on one figure becomes hard to read. Split into multiple figures.

5. MCQs

Question 1

plt.subplots(2,3) creates?

Question 2

gridspec.GridSpec(3, 3) enables?

Question 3

gs[0, :] in GridSpec means?

Question 4

sharex=True in subplots?

Question 5

hspace=0.4 in GridSpec controls?

Question 6

Recommended max panels per figure?

Question 7

ax.axis('off') does?

Question 8

bboxinches='tight' in savefig?

Question 9

fig.addsubplot(gs[1, 2]) places chart at?

Question 10

KPI number cards in dashboards are best placed?

6. Interview Questions

  • Q: How do you create a full-width chart in a GridSpec layout?
  • Q: What is the difference between plt.subplots() and GridSpec?

7. Summary

plt.subplots(m,n) creates uniform grids. GridSpec creates complex irregular layouts with cell spanning. KPI number cards provide quick summary before detail charts. Always tight
layout() and bbox_inches='tight' for clean multi-panel exports. Keep panels ≤8 per figure for readability.

8. Next Chapter Recommendation

In Chapter 13: Introduction to Seaborn, we switch to the statistical visualization library that produces beautiful charts from DataFrames in one line.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·