Combined Visualizations¶
Combine box plots with other chart types for comprehensive data analysis and presentation.
Box Plot with Histogram¶
Pair box plots with histograms to show both summary statistics and distributional shape.
1. Side by Side Layout¶
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data = np.random.normal(100, 15, 500)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.hist(data, bins=25, edgecolor='black', alpha=0.7)
ax1.axvline(np.mean(data), color='red', linestyle='--', label='Mean')
ax1.axvline(np.median(data), color='blue', linestyle='--', label='Median')
ax1.legend()
ax1.set_title('Histogram')
ax2.boxplot(data)
ax2.set_title('Box Plot')
plt.tight_layout()
plt.show()
2. Stacked Vertically¶
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6),
gridspec_kw={'height_ratios': [3, 1]})
ax1.hist(data, bins=25, edgecolor='black', alpha=0.7)
ax1.set_ylabel('Frequency')
ax2.boxplot(data, vert=False)
ax2.set_xlabel('Value')
plt.tight_layout()
plt.show()
3. Reusable Function¶
def plot_distribution(data, title='Distribution Analysis', bins=20):
mean = np.mean(data)
median = np.median(data)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
fig.suptitle(title, fontsize=14)
ax1.hist(data, bins=bins, density=True, alpha=0.7, edgecolor='black')
ax1.axvline(mean, color='blue', linestyle='--', label=f'Mean: {mean:.1f}')
ax1.axvline(median, color='red', linestyle='--', label=f'Median: {median:.1f}')
ax1.legend()
ax1.set_title('Histogram')
ax2.boxplot(data)
ax2.set_title('Box Plot')
plt.tight_layout()
plt.show()
Box Plot with Reference Lines¶
Add horizontal reference lines to compare distributions against benchmarks.
1. Single Reference Line¶
fig, ax = plt.subplots()
data = [np.random.normal(100, 15, 100) for _ in range(4)]
ax.boxplot(data, labels=['Q1', 'Q2', 'Q3', 'Q4'])
ax.axhline(y=100, color='red', linestyle='--', label='Target', alpha=0.7)
ax.legend()
ax.set_ylabel('Performance')
plt.show()
2. Multiple Reference Lines¶
fig, ax = plt.subplots()
ax.boxplot(data, labels=['Q1', 'Q2', 'Q3', 'Q4'])
ax.axhline(y=90, color='red', linestyle='--', label='Minimum', alpha=0.7)
ax.axhline(y=100, color='green', linestyle='--', label='Target', alpha=0.7)
ax.axhline(y=110, color='blue', linestyle='--', label='Stretch', alpha=0.7)
ax.legend()
plt.show()
3. Shaded Region¶
fig, ax = plt.subplots()
ax.boxplot(data, labels=['Q1', 'Q2', 'Q3', 'Q4'])
ax.axhspan(95, 105, color='green', alpha=0.2, label='Acceptable Range')
ax.legend()
plt.show()
Box Plot with Scatter Overlay¶
Show individual data points alongside the box plot summary.
1. Jittered Points¶
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data = [np.random.normal(0, std, 50) for std in range(1, 5)]
fig, ax = plt.subplots()
bp = ax.boxplot(data, patch_artist=True, showfliers=False)
for patch in bp['boxes']:
patch.set_facecolor('lightblue')
patch.set_alpha(0.5)
for i, d in enumerate(data, 1):
jitter = np.random.normal(0, 0.04, len(d))
ax.scatter(np.full_like(d, i) + jitter, d, alpha=0.5, s=20, c='steelblue')
plt.show()
2. Swarm-Like Layout¶
def add_points(ax, data, positions, width=0.2):
for pos, d in zip(positions, data):
n = len(d)
offsets = np.linspace(-width/2, width/2, n)
ax.scatter(np.full(n, pos) + offsets, np.sort(d),
alpha=0.4, s=15, c='darkblue')
fig, ax = plt.subplots()
bp = ax.boxplot(data, showfliers=False)
add_points(ax, data, range(1, len(data) + 1))
plt.show()
3. Strip Plot Style¶
fig, ax = plt.subplots()
ax.boxplot(data, showfliers=False, widths=0.3)
for i, d in enumerate(data, 1):
y = d
x = np.random.uniform(i - 0.15, i + 0.15, len(d))
ax.scatter(x, y, alpha=0.3, s=10, c='black')
plt.show()
Grouped Box Plots¶
Compare multiple categories across groups.
1. Manual Positioning¶
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
group1_a = np.random.normal(100, 10, 50)
group1_b = np.random.normal(110, 15, 50)
group2_a = np.random.normal(90, 12, 50)
group2_b = np.random.normal(95, 18, 50)
fig, ax = plt.subplots()
positions_a = [1, 3]
positions_b = [1.6, 3.6]
bp1 = ax.boxplot([group1_a, group2_a], positions=positions_a,
widths=0.5, patch_artist=True)
bp2 = ax.boxplot([group1_b, group2_b], positions=positions_b,
widths=0.5, patch_artist=True)
for patch in bp1['boxes']:
patch.set_facecolor('lightblue')
for patch in bp2['boxes']:
patch.set_facecolor('lightcoral')
ax.set_xticks([1.3, 3.3])
ax.set_xticklabels(['Group 1', 'Group 2'])
ax.legend([bp1['boxes'][0], bp2['boxes'][0]], ['Method A', 'Method B'])
plt.show()
2. Color by Category¶
fig, ax = plt.subplots(figsize=(10, 5))
data_dict = {
'Control': [np.random.normal(100, 10, 50) for _ in range(3)],
'Treatment': [np.random.normal(110, 12, 50) for _ in range(3)]
}
colors = {'Control': 'lightblue', 'Treatment': 'lightcoral'}
positions = {'Control': [1, 4, 7], 'Treatment': [2, 5, 8]}
for label, datasets in data_dict.items():
bp = ax.boxplot(datasets, positions=positions[label],
widths=0.8, patch_artist=True)
for patch in bp['boxes']:
patch.set_facecolor(colors[label])
ax.set_xticks([1.5, 4.5, 7.5])
ax.set_xticklabels(['Week 1', 'Week 2', 'Week 3'])
plt.show()
3. Legend for Groups¶
from matplotlib.patches import Patch
legend_elements = [Patch(facecolor='lightblue', label='Control'),
Patch(facecolor='lightcoral', label='Treatment')]
ax.legend(handles=legend_elements, loc='upper right')
Box Plot with Violin Overlay¶
Combine box plots with violin plots for complete distribution visualization.
1. Overlay Approach¶
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data = [np.random.normal(0, std, 200) for std in range(1, 5)]
fig, ax = plt.subplots()
vp = ax.violinplot(data, showextrema=False)
for body in vp['bodies']:
body.set_alpha(0.3)
ax.boxplot(data, widths=0.1)
plt.show()
2. Side by Side¶
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5), sharey=True)
ax1.violinplot(data)
ax1.set_title('Violin Plot')
ax2.boxplot(data)
ax2.set_title('Box Plot')
plt.tight_layout()
plt.show()
3. Hybrid Visualization¶
fig, ax = plt.subplots()
vp = ax.violinplot(data, showmedians=False, showextrema=False)
for body in vp['bodies']:
body.set_facecolor('lightblue')
body.set_alpha(0.5)
bp = ax.boxplot(data, widths=0.15, patch_artist=True,
boxprops=dict(facecolor='white', edgecolor='black'),
medianprops=dict(color='red', linewidth=2))
plt.show()