π Matplotlib
32 topics • Click any card to expand
The most basic Matplotlib plot. Use plt.plot() for time series, trends, and continuous data. Always label axes and add a title.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.plot(x, y, color='steelblue', linewidth=2, label='sin(x)')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Sine Wave')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('line_simple.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved line_simple.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
plt.figure(figsize=(8, 4))
plt.plot(x, np.sin(x), label='sin(x)', linewidth=2)
plt.plot(x, np.cos(x), label='cos(x)', linewidth=2, linestyle='--')
plt.plot(x, np.sin(2 * x), label='sin(2x)', linewidth=1, alpha=0.7)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Trig Functions')
plt.legend()
plt.axhline(0, color='gray', linewidth=0.8)
plt.tight_layout()
plt.savefig('line_multi.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved line_multi.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
x = np.linspace(0, 10, 50)
y1 = np.sin(x) + np.random.randn(50) * 0.1
y2 = np.cos(x) + np.random.randn(50) * 0.1
err = np.abs(np.random.randn(50) * 0.15)
fig, ax = plt.subplots(figsize=(9, 4))
ax.plot(x, y1, 'o-', color='steelblue', markersize=4, linewidth=1.5, label='Signal A')
ax.plot(x, y2, 's--', color='tomato', markersize=4, linewidth=1.5, label='Signal B')
# Confidence band around Signal A
ax.fill_between(x, y1 - err, y1 + err, alpha=0.2, color='steelblue', label='Β±1Ο band')
ax.axhline(0, color='gray', linewidth=0.7, linestyle=':')
ax.set_xlabel('Time'); ax.set_ylabel('Amplitude')
ax.set_title('Line Styles, Markers & Confidence Band')
ax.legend(fontsize=9); ax.grid(True, alpha=0.25)
plt.tight_layout()
plt.savefig('line_styles.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved line_styles.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(4)
x = np.arange(1, 13)
y = np.array([5, 8, 6, 10, 13, 11, 15, 14, 17, 16, 20, 22], dtype=float)
yerr = np.random.uniform(0.5, 2.0, 12)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
# Step plot β useful for histograms, digital signals, and discrete data
ax1.step(x, y, where='mid', color='steelblue', linewidth=2, label='Step (mid)')
ax1.step(x, y + 3, where='post', color='tomato', linewidth=2,
linestyle='--', label='Step (post)')
ax1.fill_between(x, y, step='mid', alpha=0.15, color='steelblue')
ax1.set_xlabel('Month'); ax1.set_ylabel('Value')
ax1.set_title('Step Plot Variants')
ax1.legend(fontsize=9); ax1.grid(True, alpha=0.25)
# Errorbar plot β shows measurement uncertainty
ax2.errorbar(x, y, yerr=yerr, fmt='o-', color='#2ecc71', ecolor='gray',
elinewidth=1.5, capsize=4, capthick=1.5, linewidth=2,
markersize=6, markerfacecolor='white', markeredgewidth=2,
label='Mean Β± std')
ax2.set_xlabel('Month'); ax2.set_ylabel('Measurement')
ax2.set_title('Errorbar Plot')
ax2.legend(fontsize=9); ax2.grid(True, alpha=0.25)
plt.tight_layout()
plt.savefig('line_step_errorbar.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved line_step_errorbar.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
days = np.arange(1, 31)
traffic = 1000 + np.cumsum(np.random.randn(30) * 50) + np.random.randn(30) * 80
ma7 = np.convolve(traffic, np.ones(7)/7, mode='same')
fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(days, traffic, alpha=0.4, color='steelblue', label='Daily visitors')
ax.plot(days, ma7, color='steelblue', linewidth=2.5, label='7-day MA')
ax.fill_between(days, traffic, alpha=0.1, color='steelblue')
ax.set_xlabel('Day of Month')
ax.set_ylabel('Visitors')
ax.set_title('Website Traffic β January 2024')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('traffic_trend.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved traffic_trend.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
fig, ax = plt.subplots(figsize=(9, 4))
# TODO: plot sin(x) β solid line, circle markers, steelblue
# ax.plot(x, np.sin(x), ...)
# TODO: plot sin(2x) β dashed line, square markers, tomato
# ax.plot(x, np.sin(2*x), ...)
# TODO: plot sin(3x) β dotted line, triangle markers, green
# ax.plot(x, np.sin(3*x), ...)
# TODO: add horizontal dashed line at y=0
# ax.axhline(...)
# TODO: labels, title, legend, grid
ax.set_xlabel('x')
ax.set_ylabel('y')
# ax.set_title(...)
# ax.legend()
# ax.grid(...)
plt.tight_layout()
# TODO: plt.savefig('practice_lines.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Bar charts compare discrete categories. Use plt.bar() for vertical and plt.barh() for horizontal. Add value labels for clarity.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
categories = ['Python', 'JavaScript', 'Java', 'C++', 'Rust']
values = [67.4, 63.6, 35.4, 24.1, 13.2]
colors = ['#4C72B0','#DD8452','#55A868','#C44E52','#8172B2']
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(categories, values, color=colors, edgecolor='white', linewidth=0.5)
# Add value labels on top
for bar, val in zip(bars, values):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,
f'{val}%', ha='center', va='bottom', fontsize=9)
ax.set_ylabel('Popularity (%)')
ax.set_title('Most Popular Programming Languages 2024')
ax.set_ylim(0, 80)
ax.grid(True, axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('bar_vertical.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved bar_vertical.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
product_a = [120, 150, 180, 210]
product_b = [80, 95, 110, 130]
x = np.arange(len(quarters))
w = 0.35
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# Grouped
axes[0].bar(x - w/2, product_a, w, label='Product A', color='#4C72B0')
axes[0].bar(x + w/2, product_b, w, label='Product B', color='#DD8452')
axes[0].set_xticks(x); axes[0].set_xticklabels(quarters)
axes[0].set_title('Grouped'); axes[0].legend()
# Stacked
axes[1].bar(quarters, product_a, label='Product A', color='#4C72B0')
axes[1].bar(quarters, product_b, bottom=product_a, label='Product B', color='#DD8452')
axes[1].set_title('Stacked'); axes[1].legend()
plt.tight_layout()
plt.savefig('bar_grouped_stacked.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved bar_grouped_stacked.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
skills = ['Python', 'SQL', 'Machine Learning', 'Data Viz', 'Statistics', 'Deep Learning']
scores = [92, 85, 78, 70, 65, 55]
colors = ['#4C72B0' if s >= 80 else '#DD8452' if s >= 65 else '#C44E52' for s in scores]
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.barh(skills, scores, color=colors, edgecolor='white', linewidth=0.5)
for bar, val in zip(bars, scores):
ax.text(val + 0.5, bar.get_y() + bar.get_height()/2,
f'{val}%', va='center', fontsize=9)
ax.set_xlabel('Proficiency Score (%)')
ax.set_title('Data Science Skill Assessment')
ax.set_xlim(0, 105)
ax.axvline(80, color='gray', linestyle='--', linewidth=1, alpha=0.6, label='Expert threshold')
ax.legend(fontsize=9); ax.grid(True, axis='x', alpha=0.3)
plt.tight_layout()
plt.savefig('bar_horizontal.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved bar_horizontal.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(21)
conditions = ['Control', 'Treatment A', 'Treatment B', 'Treatment C']
means = np.array([45.2, 52.7, 61.3, 58.9])
errors = np.array([3.1, 4.2, 3.8, 4.5]) # standard deviations
colors = ['#8172B2', '#4C72B0', '#55A868', '#DD8452']
fig, ax = plt.subplots(figsize=(8, 5))
x = np.arange(len(conditions))
bars = ax.bar(x, means, yerr=errors, color=colors, edgecolor='white',
linewidth=0.5, capsize=6, error_kw=dict(elinewidth=1.5, ecolor='black'))
# Add significance stars between bars
pairs = [(0, 2, '***'), (1, 2, '*')] # (bar_i, bar_j, label)
y_max = (means + errors).max()
for i, j, sig in pairs:
y = y_max + 4 + pairs.index((i, j, sig)) * 5
ax.annotate('', xy=(j, y), xytext=(i, y),
arrowprops=dict(arrowstyle='-', color='black', lw=1.2))
ax.text((i + j) / 2, y + 0.3, sig, ha='center', va='bottom', fontsize=11)
# Value labels above each bar
for bar, m, e in zip(bars, means, errors):
ax.text(bar.get_x() + bar.get_width()/2, m + e + 0.8,
f'{m:.1f}', ha='center', va='bottom', fontsize=9)
ax.set_xticks(x); ax.set_xticklabels(conditions)
ax.set_ylabel('Response Score'); ax.set_title('Experimental Results with Error Bars')
ax.set_ylim(0, y_max + 18); ax.grid(True, axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('bar_errorbars.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved bar_errorbars.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
regions = ['APAC', 'EMEA', 'LATAM', 'North America']
q1 = [2.1, 3.4, 1.2, 5.6]
q2 = [2.5, 3.8, 1.5, 6.1]
y = np.arange(len(regions))
h = 0.35
fig, ax = plt.subplots(figsize=(9, 4))
b1 = ax.barh(y + h/2, q1, h, label='Q1 2024', color='#4C72B0')
b2 = ax.barh(y - h/2, q2, h, label='Q2 2024', color='#55A868')
for bar in list(b1) + list(b2):
w = bar.get_width()
ax.text(w + 0.05, bar.get_y() + bar.get_height()/2,
f'${w:.1f}M', va='center', fontsize=8)
ax.set_yticks(y); ax.set_yticklabels(regions)
ax.set_xlabel('Revenue (USD millions)')
ax.set_title('Q1 vs Q2 2024 Revenue by Region')
ax.legend(); ax.grid(True, axis='x', alpha=0.3)
ax.set_xlim(0, 8)
plt.tight_layout()
plt.savefig('bar_region.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved bar_region.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
product_a = [45, 60, 55, 80]
product_b = [30, 45, 70, 65]
product_c = [20, 35, 40, 55]
x = np.arange(len(quarters))
w = 0.25 # bar width
fig, ax = plt.subplots(figsize=(9, 5))
# TODO: plot three groups of bars, offset by -w, 0, +w
# bars_a = ax.bar(x - w, product_a, w, label='Product A', color='#4C72B0')
# bars_b = ax.bar(x, product_b, w, label='Product B', color='#DD8452')
# bars_c = ax.bar(x + w, product_c, w, label='Product C', color='#55A868')
# TODO: add value labels on top of each bar
# for bars in [bars_a, bars_b, bars_c]:
# for bar in bars:
# ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,
# str(int(bar.get_height())), ha='center', va='bottom', fontsize=8)
ax.set_xticks(x)
ax.set_xticklabels(quarters)
# TODO: ax.set_xlabel(...), ax.set_ylabel(...), ax.set_title(...)
# TODO: ax.legend()
ax.grid(True, axis='y', alpha=0.3)
plt.tight_layout()
# TODO: plt.savefig('practice_grouped_bar.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Scatter plots reveal relationships between two numeric variables. Control color, size, and alpha to encode extra dimensions.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
x = np.random.randn(200)
y = 0.7 * x + np.random.randn(200) * 0.6
fig, ax = plt.subplots(figsize=(6, 5))
sc = ax.scatter(x, y, c=y, cmap='RdYlGn', alpha=0.7, edgecolors='white', linewidth=0.3)
plt.colorbar(sc, label='y value')
# Trend line
m, b = np.polyfit(x, y, 1)
xline = np.linspace(x.min(), x.max(), 100)
ax.plot(xline, m * xline + b, 'k--', linewidth=1.5, label=f'y={m:.2f}x+{b:.2f}')
ax.set_xlabel('X'); ax.set_ylabel('Y')
ax.set_title('Scatter with Trend Line')
ax.legend()
plt.tight_layout()
plt.savefig('scatter_basic.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved scatter_basic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
n = 20
x = np.random.uniform(10, 100, n)
y = np.random.uniform(5, 50, n)
size = np.random.uniform(50, 800, n) # bubble size
color= np.random.rand(n)
fig, ax = plt.subplots(figsize=(7, 5))
sc = ax.scatter(x, y, s=size, c=color, cmap='viridis', alpha=0.6,
edgecolors='white', linewidth=0.5)
plt.colorbar(sc, label='Category')
ax.set_xlabel('Revenue ($K)'); ax.set_ylabel('Profit Margin (%)')
ax.set_title('Product Portfolio β Bubble Chart')
plt.tight_layout()
plt.savefig('scatter_bubble.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved scatter_bubble.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
n_per_class = 80
classes = ['Class A', 'Class B', 'Class C']
centers = [(-2, -2), (0, 2), (3, 0)]
colors = ['#e74c3c', '#3498db', '#2ecc71']
fig, ax = plt.subplots(figsize=(7, 6))
for cls, center, color in zip(classes, centers, colors):
x = np.random.randn(n_per_class) * 0.8 + center[0]
y = np.random.randn(n_per_class) * 0.8 + center[1]
ax.scatter(x, y, c=color, label=cls, alpha=0.65,
edgecolors='white', linewidth=0.4, s=50)
ax.set_xlabel('Feature 1'); ax.set_ylabel('Feature 2')
ax.set_title('Multi-Class Scatter Plot')
ax.legend(title='Class', framealpha=0.8)
ax.grid(True, alpha=0.2)
plt.tight_layout()
plt.savefig('scatter_classes.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved scatter_classes.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(17)
n = 5000
# Two overlapping Gaussian clusters
x = np.concatenate([np.random.randn(n) * 1.2 - 1,
np.random.randn(n) * 0.8 + 2])
y = np.concatenate([np.random.randn(n) * 1.5 + 0.5,
np.random.randn(n) * 1.0 - 1])
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
# Hexbin β handles large datasets where individual points overlap
hb = axes[0].hexbin(x, y, gridsize=40, cmap='YlOrRd', mincnt=1)
plt.colorbar(hb, ax=axes[0], label='Count per bin')
axes[0].set_xlabel('X'); axes[0].set_ylabel('Y')
axes[0].set_title('Hexbin Density (gridsize=40)')
# Scatter with size proportional to local density (estimated via 2D hist)
H, xedges, yedges = np.histogram2d(x, y, bins=30)
xi = np.searchsorted(xedges, x, side='right').clip(1, H.shape[0]) - 1
yi = np.searchsorted(yedges, y, side='right').clip(1, H.shape[1]) - 1
density = H[xi, yi]
sc = axes[1].scatter(x[::5], y[::5], c=density[::5], s=density[::5] * 0.4 + 4,
cmap='plasma', alpha=0.5, edgecolors='none')
plt.colorbar(sc, ax=axes[1], label='Local density')
axes[1].set_xlabel('X'); axes[1].set_ylabel('Y')
axes[1].set_title('Scatter: Size & Color = Density')
plt.tight_layout()
plt.savefig('scatter_hexbin_density.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved scatter_hexbin_density.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(10)
neighborhoods = ['Downtown', 'Suburbs', 'Rural']
colors_map = {'Downtown': '#e74c3c', 'Suburbs': '#3498db', 'Rural': '#2ecc71'}
fig, ax = plt.subplots(figsize=(9, 5))
for nbhd in neighborhoods:
n = 60
sqft = np.random.normal({'Downtown':1200,'Suburbs':1800,'Rural':2500}[nbhd], 200, n)
base = {'Downtown':600000,'Suburbs':350000,'Rural':180000}[nbhd]
price= base + sqft * np.random.uniform(150,250) + np.random.randn(n) * 30000
ax.scatter(sqft, price/1000, label=nbhd, alpha=0.6,
color=colors_map[nbhd], edgecolors='white', linewidth=0.3, s=40)
ax.set_xlabel('Square Footage')
ax.set_ylabel('Price ($K)')
ax.set_title('House Price vs. Size by Neighborhood')
ax.legend(); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('scatter_housing.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved scatter_housing.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
x = np.random.randn(300)
y = 0.5 * x + np.random.randn(300) * 0.8
# TODO: compute distance from origin for each point
# dist = np.sqrt(x**2 + y**2)
fig, ax = plt.subplots(figsize=(7, 6))
# TODO: scatter with c=dist, cmap='plasma', alpha=0.7, edgecolors='white'
# sc = ax.scatter(x, y, c=dist, ...)
# TODO: plt.colorbar(sc, label='Distance from origin')
# TODO: fit and plot regression line
# m, b = np.polyfit(x, y, 1)
# xline = np.linspace(x.min(), x.max(), 100)
# ax.plot(xline, m * xline + b, 'k--', linewidth=1.5, label=f'fit')
ax.set_xlabel('X')
ax.set_ylabel('Y')
# TODO: ax.set_title(...)
# TODO: ax.legend()
plt.tight_layout()
# TODO: plt.savefig('practice_scatter.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Histograms show the distribution of a single variable. Control bins and density to compare distributions or estimate PDFs.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data = np.random.normal(170, 10, 1000) # heights in cm
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(data, bins=30, density=True, color='steelblue',
edgecolor='white', linewidth=0.4, alpha=0.7, label='Data')
# Overlay normal PDF manually (no scipy needed)
xr = np.linspace(data.min(), data.max(), 200)
pdf = (1 / (data.std() * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((xr - data.mean()) / data.std())**2)
ax.plot(xr, pdf, color='navy', linewidth=2, label='Normal PDF')
ax.axvline(data.mean(), color='red', linestyle='--', label=f'Mean={data.mean():.1f}')
ax.set_xlabel('Height (cm)'); ax.set_ylabel('Density')
ax.set_title('Height Distribution'); ax.legend()
plt.tight_layout()
plt.savefig('hist_basic.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved hist_basic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
group_a = np.random.normal(100, 15, 500)
group_b = np.random.normal(115, 12, 500)
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(group_a, bins=30, alpha=0.6, label='Group A', color='steelblue', edgecolor='white')
ax.hist(group_b, bins=30, alpha=0.6, label='Group B', color='tomato', edgecolor='white')
ax.axvline(group_a.mean(), color='steelblue', linestyle='--', linewidth=1.5)
ax.axvline(group_b.mean(), color='tomato', linestyle='--', linewidth=1.5)
ax.set_xlabel('Score'); ax.set_ylabel('Count')
ax.set_title('Score Distribution by Group')
ax.legend()
plt.tight_layout()
plt.savefig('hist_compare.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved hist_compare.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(5)
data = np.random.exponential(scale=2.0, size=800)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
# Regular histogram
ax1.hist(data, bins=35, color='#DD8452', edgecolor='white', linewidth=0.4, alpha=0.8)
ax1.set_xlabel('Value'); ax1.set_ylabel('Count')
ax1.set_title('Exponential Distribution')
ax1.grid(True, axis='y', alpha=0.3)
# Cumulative histogram (ECDF style)
ax2.hist(data, bins=35, cumulative=True, density=True,
color='#4C72B0', edgecolor='white', linewidth=0.4, alpha=0.7, label='ECDF')
# Overlay theoretical CDF: 1 - exp(-x/scale)
xr = np.linspace(0, data.max(), 200)
ax2.plot(xr, 1 - np.exp(-xr / 2.0), 'r-', linewidth=2, label='Theoretical CDF')
ax2.set_xlabel('Value'); ax2.set_ylabel('Cumulative Probability')
ax2.set_title('Cumulative Distribution')
ax2.legend(); ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('hist_cumulative.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved hist_cumulative.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(13)
data_a = np.random.normal(60, 12, 600)
data_b = np.random.normal(75, 10, 600)
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# Filled histogram (counts)
axes[0].hist(data_a, bins=30, alpha=0.6, color='steelblue',
edgecolor='white', label='Group A')
axes[0].hist(data_b, bins=30, alpha=0.6, color='tomato',
edgecolor='white', label='Group B')
axes[0].set_title('Filled β Count'); axes[0].legend()
axes[0].set_xlabel('Value'); axes[0].set_ylabel('Count')
axes[0].grid(True, axis='y', alpha=0.3)
# Step histogram (unfilled outline)
axes[1].hist(data_a, bins=30, histtype='step', linewidth=2,
color='steelblue', label='Group A')
axes[1].hist(data_b, bins=30, histtype='step', linewidth=2,
color='tomato', label='Group B')
axes[1].set_title('Step β Count'); axes[1].legend()
axes[1].set_xlabel('Value'); axes[1].set_ylabel('Count')
axes[1].grid(True, axis='y', alpha=0.3)
# Density=True β normalised to probability density
axes[2].hist(data_a, bins=30, density=True, histtype='stepfilled',
alpha=0.5, color='steelblue', edgecolor='steelblue',
linewidth=1.5, label='Group A')
axes[2].hist(data_b, bins=30, density=True, histtype='stepfilled',
alpha=0.5, color='tomato', edgecolor='tomato',
linewidth=1.5, label='Group B')
# Overlay normal PDFs
for data, col in [(data_a, 'steelblue'), (data_b, 'tomato')]:
xr = np.linspace(data.min(), data.max(), 200)
pdf = (1 / (data.std() * np.sqrt(2*np.pi))) * np.exp(
-0.5 * ((xr - data.mean()) / data.std())**2)
axes[2].plot(xr, pdf, color=col, linewidth=2.5)
axes[2].set_title('Step-Filled β Density'); axes[2].legend()
axes[2].set_xlabel('Value'); axes[2].set_ylabel('Probability Density')
axes[2].grid(True, axis='y', alpha=0.3)
plt.suptitle('Histogram Style Comparison', fontsize=12, fontweight='bold')
plt.tight_layout()
plt.savefig('hist_styles_comparison.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved hist_styles_comparison.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
# Simulate credit score distribution (skewed left β more mid/high scores)
approved = np.random.normal(700, 60, 800).clip(580, 850)
rejected = np.random.normal(580, 50, 400).clip(300, 680)
fig, ax = plt.subplots(figsize=(9, 4))
ax.hist(approved, bins=30, alpha=0.6, color='#2ecc71', label='Approved', edgecolor='white')
ax.hist(rejected, bins=30, alpha=0.6, color='#e74c3c', label='Rejected', edgecolor='white')
# Threshold line
ax.axvline(620, color='black', linestyle='--', linewidth=2, label='Threshold: 620')
ax.set_xlabel('Credit Score'); ax.set_ylabel('Applicants')
ax.set_title('Credit Score Distribution by Decision')
ax.legend(); ax.grid(True, axis='y', alpha=0.3)
# Annotation
ax.annotate('High risk zone', xy=(550, 30), fontsize=9, color='#e74c3c')
ax.annotate('Low risk zone', xy=(720, 60), fontsize=9, color='#2ecc71')
plt.tight_layout()
plt.savefig('hist_credit.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved hist_credit.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
data = np.random.normal(50, 12, 1000)
fig, ax = plt.subplots(figsize=(8, 4))
# TODO: plot histogram with density=True, bins=30, steelblue
# ax.hist(data, bins=30, density=True, ...)
# TODO: compute and overlay normal PDF
# xr = np.linspace(data.min(), data.max(), 200)
# mu, sigma = data.mean(), data.std()
# pdf = (1 / (sigma * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((xr - mu) / sigma)**2)
# ax.plot(xr, pdf, color='navy', linewidth=2, label='Normal PDF')
# TODO: add vertical lines for mean and Β±1 std
# ax.axvline(mu, color='red', linestyle='--', label=f'Mean={mu:.1f}')
# ax.axvline(mu - sigma, color='orange', linestyle=':', label='-1Ο')
# ax.axvline(mu + sigma, color='orange', linestyle=':', label='+1Ο')
ax.set_xlabel('Value')
ax.set_ylabel('Density')
# TODO: ax.set_title(...)
# TODO: ax.legend()
plt.tight_layout()
# TODO: plt.savefig('practice_hist.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')plt.subplots() creates a grid of axes in a single figure. Essential for dashboards and side-by-side comparisons.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
x = np.linspace(0, 10, 200)
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
axes[0,0].plot(x, np.sin(x), color='steelblue')
axes[0,0].set_title('Line: sin(x)')
axes[0,1].bar(['A','B','C','D'], [23,45,12,67], color='#DD8452')
axes[0,1].set_title('Bar Chart')
axes[1,0].scatter(np.random.randn(100), np.random.randn(100), alpha=0.5)
axes[1,0].set_title('Scatter')
axes[1,1].hist(np.random.randn(500), bins=25, color='#55A868')
axes[1,1].set_title('Histogram')
# Global title and spacing
fig.suptitle('Dashboard Overview', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('subplots_2x2.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved subplots_2x2.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(5)
dates = np.arange(30)
price = 100 + np.cumsum(np.random.randn(30))
volume = np.random.randint(1000, 5000, 30)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6),
sharex=True,
gridspec_kw={'height_ratios': [3, 1]})
ax1.plot(dates, price, color='steelblue', linewidth=2)
ax1.set_ylabel('Price ($)'); ax1.set_title('Stock Price & Volume')
ax1.grid(True, alpha=0.3)
ax2.bar(dates, volume, color='gray', alpha=0.5)
ax2.set_ylabel('Volume'); ax2.set_xlabel('Day')
plt.tight_layout()
plt.savefig('subplots_shared.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved subplots_shared.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
np.random.seed(8)
fig = plt.figure(figsize=(11, 7))
gs = gridspec.GridSpec(2, 3, figure=fig, hspace=0.35, wspace=0.3)
# Wide top plot spanning all 3 columns
ax_top = fig.add_subplot(gs[0, :])
x = np.linspace(0, 10, 200)
ax_top.plot(x, np.sin(x) * np.exp(-0.1*x), color='steelblue', linewidth=2)
ax_top.set_title('Wide Top: Damped Sine'); ax_top.grid(True, alpha=0.25)
# Three smaller bottom plots
for col, (title, color) in enumerate([('Scatter','#DD8452'),('Bar','#55A868'),('Hist','#8172B2')]):
ax = fig.add_subplot(gs[1, col])
if title == 'Scatter':
ax.scatter(np.random.randn(50), np.random.randn(50), color=color, alpha=0.6, s=25)
elif title == 'Bar':
ax.bar(['A','B','C'], [4, 7, 5], color=color)
else:
ax.hist(np.random.randn(200), bins=20, color=color, edgecolor='white', linewidth=0.4)
ax.set_title(title)
fig.suptitle('GridSpec Layout', fontsize=13, fontweight='bold')
plt.savefig('subplots_gridspec.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved subplots_gridspec.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(22)
fig = plt.figure(figsize=(12, 7))
# subplot2grid(shape, loc, rowspan, colspan) β place cells in a grid manually
ax_main = plt.subplot2grid((3, 4), (0, 0), rowspan=2, colspan=3) # big left
ax_right = plt.subplot2grid((3, 4), (0, 3), rowspan=3, colspan=1) # tall right
ax_bot1 = plt.subplot2grid((3, 4), (2, 0), rowspan=1, colspan=1) # bottom row
ax_bot2 = plt.subplot2grid((3, 4), (2, 1), rowspan=1, colspan=1)
ax_bot3 = plt.subplot2grid((3, 4), (2, 2), rowspan=1, colspan=1)
# Main panel β time series
t = np.linspace(0, 4 * np.pi, 300)
ax_main.plot(t, np.sin(t), color='steelblue', linewidth=2, label='sin')
ax_main.plot(t, np.cos(t), color='tomato', linewidth=2, linestyle='--', label='cos')
ax_main.fill_between(t, np.sin(t), np.cos(t), alpha=0.08, color='gray')
ax_main.set_title('Main β Trig Functions'); ax_main.legend(fontsize=8)
ax_main.grid(True, alpha=0.25)
# Tall right panel β horizontal bars (KPIs)
kpis = ['KPI A', 'KPI B', 'KPI C', 'KPI D', 'KPI E']
values = np.random.uniform(40, 95, 5)
colors = ['#2ecc71' if v >= 70 else '#e74c3c' for v in values]
ax_right.barh(kpis, values, color=colors, edgecolor='white', linewidth=0.5)
ax_right.set_xlim(0, 100)
ax_right.axvline(70, color='gray', linestyle='--', linewidth=0.8)
ax_right.set_title('KPIs', fontsize=9)
ax_right.tick_params(labelsize=7)
# Bottom three mini-panels
for ax, title, color in zip([ax_bot1, ax_bot2, ax_bot3],
['Alpha', 'Beta', 'Gamma'],
['#4C72B0', '#DD8452', '#55A868']):
data = np.random.randn(120)
ax.hist(data, bins=15, color=color, edgecolor='white', linewidth=0.3, alpha=0.8)
ax.set_title(title, fontsize=8); ax.tick_params(labelsize=6)
ax.grid(True, axis='y', alpha=0.3)
fig.suptitle('subplot2grid β Asymmetric Dashboard', fontsize=12, fontweight='bold')
plt.tight_layout()
plt.savefig('subplots_subplot2grid.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved subplots_subplot2grid.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
epochs = np.arange(1, 51)
train_loss= 1.5 * np.exp(-0.06 * epochs) + np.random.randn(50) * 0.02
val_loss = 1.5 * np.exp(-0.05 * epochs) + 0.05 + np.random.randn(50) * 0.03
train_acc = 1 - train_loss / 1.5 + 0.3
val_acc = 1 - val_loss / 1.5 + 0.28
fig, axes = plt.subplots(1, 3, figsize=(14, 4))
# Loss curves
axes[0].plot(epochs, train_loss, label='Train', color='steelblue')
axes[0].plot(epochs, val_loss, label='Val', color='tomato', linestyle='--')
axes[0].set_title('Loss'); axes[0].set_xlabel('Epoch')
axes[0].legend(); axes[0].grid(True, alpha=0.3)
# Accuracy curves
axes[1].plot(epochs, train_acc.clip(0,1), label='Train', color='steelblue')
axes[1].plot(epochs, val_acc.clip(0,1), label='Val', color='tomato', linestyle='--')
axes[1].set_title('Accuracy'); axes[1].set_xlabel('Epoch')
axes[1].legend(); axes[1].grid(True, alpha=0.3)
# Prediction histogram
preds = np.random.beta(2, 2, 500)
axes[2].hist(preds, bins=25, color='#55A868', edgecolor='white')
axes[2].axvline(0.5, color='red', linestyle='--', label='Threshold')
axes[2].set_title('Prediction Scores'); axes[2].set_xlabel('Score')
axes[2].legend()
fig.suptitle('Model Evaluation Dashboard', fontweight='bold')
plt.tight_layout()
plt.savefig('subplots_ml_dashboard.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved subplots_ml_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# Top-left: line plot of cos(x)
x = np.linspace(0, 4 * np.pi, 300)
# TODO: axes[0,0].plot(x, np.cos(x), ...)
# TODO: axes[0,0].set_title('...')
# Top-right: scatter of 100 random points, colored by angle
pts = np.random.randn(100, 2)
angles = np.arctan2(pts[:, 1], pts[:, 0])
# TODO: sc = axes[0,1].scatter(pts[:,0], pts[:,1], c=angles, cmap='hsv', alpha=0.7)
# TODO: plt.colorbar(sc, ax=axes[0,1])
# TODO: axes[0,1].set_title('...')
# Bottom-left: bar chart of 5 categories
cats = ['A', 'B', 'C', 'D', 'E']
values = np.random.randint(10, 80, 5)
# TODO: axes[1,0].bar(cats, values, ...)
# TODO: axes[1,0].set_title('...')
# Bottom-right: histogram of 500 normal samples
data = np.random.randn(500)
# TODO: axes[1,1].hist(data, bins=25, ...)
# TODO: axes[1,1].set_title('...')
# TODO: fig.suptitle('2x2 Dashboard', fontsize=14, fontweight='bold')
plt.tight_layout()
# TODO: plt.savefig('practice_subplots.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Control colors, line styles, markers, fonts, spines, and tick formatting. Good styling makes charts publication-ready.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(1, 8)
y1 = [3, 7, 5, 9, 6, 8, 10]
y2 = [1, 4, 3, 6, 4, 7, 8]
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y1, 'o-', color='steelblue', markersize=8,
linewidth=2, markerfacecolor='white', markeredgewidth=2, label='Series A')
ax.plot(x, y2, 's--', color='tomato', markersize=7,
linewidth=2, markerfacecolor='white', markeredgewidth=2, label='Series B')
# Remove top/right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_xticks(x)
ax.set_xticklabels([f'Day {i}' for i in x], rotation=30, ha='right')
ax.set_title('Weekly Performance', fontsize=13, fontweight='bold', pad=12)
ax.legend(frameon=False); ax.grid(True, alpha=0.2)
plt.tight_layout()
plt.savefig('custom_markers.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved custom_markers.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
x = np.linspace(0, 10, 100)
y = np.sin(x) * np.exp(-0.1 * x)
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y, color='steelblue', linewidth=2)
# Peak annotation
peak_idx = np.argmax(y)
ax.annotate(f'Peak ({x[peak_idx]:.1f}, {y[peak_idx]:.2f})',
xy=(x[peak_idx], y[peak_idx]),
xytext=(x[peak_idx]+1.5, y[peak_idx]+0.1),
arrowprops=dict(arrowstyle='->', color='red'),
color='red', fontsize=9)
ax.axhline(0, color='gray', linewidth=0.8, linestyle='--')
ax.fill_between(x, y, where=(y > 0), alpha=0.15, color='steelblue')
ax.fill_between(x, y, where=(y < 0), alpha=0.15, color='tomato')
ax.set_title('Damped Sine Wave'); ax.set_xlabel('x')
plt.tight_layout()
plt.savefig('custom_annotations.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved custom_annotations.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
np.random.seed(2)
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
revenue = np.array([42, 38, 51, 47, 59, 65, 70, 62, 55, 68, 75, 88]) * 1000
fig, ax = plt.subplots(figsize=(11, 4))
ax.plot(range(12), revenue, 'o-', color='#1a73e8', linewidth=2.5,
markersize=7, markerfacecolor='white', markeredgewidth=2)
ax.fill_between(range(12), revenue, alpha=0.1, color='#1a73e8')
# Format y-axis as currency
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f'${v/1000:.0f}K'))
# Color background by quarter
colors = ['#fff9f0','#f0fff4','#f0f4ff','#fff0f4']
for q, color in enumerate(colors):
ax.axvspan(q*3 - 0.5, q*3 + 2.5, alpha=0.25, color=color, zorder=0)
# Annotate max
best_idx = int(np.argmax(revenue))
ax.annotate(f'Best: ${revenue[best_idx]/1000:.0f}K', xy=(best_idx, revenue[best_idx]),
xytext=(best_idx - 2, revenue[best_idx] + 4000),
arrowprops=dict(arrowstyle='->', color='green'), color='green', fontsize=9)
ax.set_xticks(range(12)); ax.set_xticklabels(months)
ax.spines['top'].set_visible(False); ax.spines['right'].set_visible(False)
ax.set_title('Monthly Revenue with Quarter Shading', fontsize=13, fontweight='bold')
ax.grid(True, axis='y', alpha=0.25)
plt.tight_layout()
plt.savefig('custom_tick_format.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved custom_tick_format.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
revenue = [4.2, 3.8, 5.1, 5.8, 6.2, 7.0, 6.5, 7.8, 8.1, 7.5, 9.2, 10.4]
target = [5.0] * 12
fig, ax = plt.subplots(figsize=(11, 5))
ax.plot(months, revenue, 'o-', color='#1a73e8', linewidth=2.5,
markersize=7, markerfacecolor='white', markeredgewidth=2.5, label='Actual Revenue')
ax.plot(months, target, '--', color='#ea4335', linewidth=1.5,
alpha=0.7, label='Monthly Target ($5M)')
ax.fill_between(months, revenue, target,
where=[r >= t for r, t in zip(revenue, target)],
alpha=0.1, color='green', label='Above target')
ax.fill_between(months, revenue, target,
where=[r < t for r, t in zip(revenue, target)],
alpha=0.1, color='red', label='Below target')
# Annotate best month
best = months[revenue.index(max(revenue))]
ax.annotate(f'Best: ${max(revenue):.1f}M', xy=(best, max(revenue)),
xytext=(best, max(revenue)+0.4),
ha='center', fontsize=9, color='green', fontweight='bold')
ax.spines['top'].set_visible(False); ax.spines['right'].set_visible(False)
ax.set_ylabel('Revenue (USD millions)'); ax.set_title('2024 Monthly Revenue vs Target',
fontsize=14, fontweight='bold')
ax.legend(frameon=False, loc='upper left'); ax.grid(True, axis='y', alpha=0.2)
plt.tight_layout()
plt.savefig('custom_kpi.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved custom_kpi.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
sales_a = np.array([42, 38, 51, 47, 59, 65, 70, 62, 55, 68, 75, 88]) * 1000
sales_b = np.array([30, 35, 40, 38, 45, 50, 55, 52, 48, 58, 62, 70]) * 1000
x = np.arange(12)
fig, ax = plt.subplots(figsize=(11, 5))
# TODO: plot sales_a with 'o-' markers, steelblue, markerfacecolor='white'
# ax.plot(x, sales_a, 'o-', ...)
# TODO: plot sales_b with 's--' markers, tomato, markerfacecolor='white'
# ax.plot(x, sales_b, 's--', ...)
# TODO: shade region between the two lines
# ax.fill_between(x, sales_a, sales_b, alpha=0.1, color='gray')
# TODO: remove top/right spines
# ax.spines['top'].set_visible(False)
# ax.spines['right'].set_visible(False)
# TODO: format y-axis as '$XK'
# ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f'${v/1000:.0f}K'))
# TODO: annotate peak of sales_a with arrow
# best = int(np.argmax(sales_a))
# ax.annotate(...)
ax.set_xticks(x)
ax.set_xticklabels(months, rotation=30, ha='right')
# TODO: ax.set_title(...), ax.legend(), ax.grid(...)
plt.tight_layout()
# TODO: plt.savefig('practice_custom.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Pie charts show part-to-whole relationships. Donut charts are a modern alternative. Avoid too many slices β use 5 or fewer.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
labels = ['Python', 'JavaScript', 'Java', 'C++', 'Other']
sizes = [30, 25, 20, 15, 10]
explode = [0.05, 0, 0, 0, 0] # pull out the first slice
colors = ['#4C72B0','#DD8452','#55A868','#C44E52','#8172B2']
fig, ax = plt.subplots(figsize=(7, 5))
wedges, texts, autotexts = ax.pie(
sizes, labels=labels, explode=explode, colors=colors,
autopct='%1.1f%%', startangle=140,
wedgeprops=dict(edgecolor='white', linewidth=2)
)
for t in autotexts: t.set_fontsize(9)
ax.set_title('Language Market Share')
plt.tight_layout()
plt.savefig('pie_basic.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved pie_basic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
labels = ['Organic', 'Paid Search', 'Social', 'Email', 'Direct']
sizes = [35, 25, 20, 12, 8]
colors = ['#2ecc71','#3498db','#e74c3c','#f39c12','#9b59b6']
fig, ax = plt.subplots(figsize=(7, 5))
wedges, texts, autotexts = ax.pie(
sizes, labels=labels, colors=colors,
autopct='%1.0f%%', startangle=90,
wedgeprops=dict(width=0.5, edgecolor='white', linewidth=2) # donut!
)
for t in autotexts: t.set_fontsize(9)
ax.text(0, 0, 'Traffic\nSources', ha='center', va='center',
fontsize=11, fontweight='bold')
ax.set_title('Website Traffic Sources')
plt.tight_layout()
plt.savefig('pie_donut.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved pie_donut.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
# Outer ring: main categories
outer_labels = ['Engineering', 'Sales', 'Marketing', 'Other']
outer_sizes = [40, 30, 20, 10]
outer_colors = ['#4C72B0', '#DD8452', '#55A868', '#C44E52']
# Inner ring: sub-breakdown for Engineering and Sales only (simplified)
inner_labels = ['FE', 'BE', 'DevOps', 'Inside', 'Field', 'Mkt-A', 'Mkt-B', 'Misc']
inner_sizes = [15, 15, 10, 18, 12, 12, 8, 10]
inner_colors = ['#6B9BE8', '#8BB2F0', '#AACCFF',
'#F0A875', '#F5C49A',
'#7DC88A', '#A5DDB0',
'#E88A8A']
fig, ax = plt.subplots(figsize=(8, 7))
ax.pie(outer_sizes, labels=outer_labels, colors=outer_colors,
radius=1.0, startangle=90,
wedgeprops=dict(width=0.35, edgecolor='white', linewidth=2),
autopct='%1.0f%%', pctdistance=0.82)
ax.pie(inner_sizes, colors=inner_colors,
radius=0.65, startangle=90,
wedgeprops=dict(width=0.35, edgecolor='white', linewidth=1))
ax.set_title('Headcount β Nested Donut', fontsize=13, fontweight='bold', pad=15)
plt.tight_layout()
plt.savefig('pie_nested.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved pie_nested.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
categories = ['Completed', 'In Progress', 'Blocked', 'Not Started']
values = [45, 30, 10, 15]
colors = ['#2e7d32', '#1565c0', '#b71c1c', '#9e9e9e']
total = sum(values)
squares = [round(v / total * 100) for v in values]
squares[-1] += 100 - sum(squares)
grid = []
for color, count in zip(colors, squares):
grid.extend([color] * count)
fig, ax = plt.subplots(figsize=(8, 8))
for i, color in enumerate(grid):
row, col = divmod(i, 10)
ax.add_patch(mpatches.FancyBboxPatch(
(col * 1.1, (9 - row) * 1.1), 1.0, 1.0,
boxstyle='round,pad=0.05', fc=color, ec='white', lw=2))
ax.set_xlim(-0.1, 11.1); ax.set_ylim(-0.1, 11.1)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title('Project Task Status (Waffle Chart)', fontsize=13, pad=15)
legend_patches = [mpatches.Patch(fc=c, label=f'{l} ({v}%)')
for c, l, v in zip(colors, categories, squares)]
ax.legend(handles=legend_patches, loc='lower center',
ncol=2, frameon=False, fontsize=11,
bbox_to_anchor=(0.5, -0.05))
plt.tight_layout()
plt.savefig('waffle_chart.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved waffle_chart.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
depts = ['Engineering', 'Sales', 'Marketing', 'Operations', 'HR', 'R&D']
budget = [32, 22, 18, 12, 8, 8]
colors = ['#1a73e8','#34a853','#fbbc04','#ea4335','#9c27b0','#00bcd4']
total = sum(budget)
fig, ax = plt.subplots(figsize=(8, 6))
wedges, texts, autotexts = ax.pie(
budget, labels=depts, colors=colors,
autopct=lambda p: f'${p*total/100:.0f}M\n({p:.0f}%)',
startangle=120,
wedgeprops=dict(width=0.55, edgecolor='white', linewidth=2)
)
for t in autotexts: t.set_fontsize(8)
ax.text(0, 0, f'Total\n${total}M', ha='center', va='center',
fontsize=12, fontweight='bold')
ax.set_title('FY2024 Budget Allocation by Department',
fontsize=13, fontweight='bold', pad=20)
plt.tight_layout()
plt.savefig('pie_budget.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved pie_budget.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
labels = ['Electronics', 'Clothing', 'Food', 'Books', 'Other']
sizes = [35, 25, 20, 12, 8]
# TODO: choose 5 colors
colors = ['#4C72B0', '#DD8452', '#55A868', '#C44E52', '#8172B2']
fig, ax = plt.subplots(figsize=(7, 6))
# TODO: create donut chart using ax.pie with wedgeprops=dict(width=0.45, ...)
# wedges, texts, autotexts = ax.pie(
# sizes, labels=labels, colors=colors,
# autopct='%1.0f%%', startangle=90,
# wedgeprops=dict(width=0.45, edgecolor='white', linewidth=2)
# )
# TODO: resize autopct text
# for t in autotexts: t.set_fontsize(9)
# TODO: add center label
# ax.text(0, 0, 'Sales\n2024', ha='center', va='center', fontsize=12, fontweight='bold')
# TODO: ax.set_title(...)
plt.tight_layout()
# TODO: plt.savefig('practice_donut.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Heatmaps encode a 2D matrix as color intensities. Great for correlation matrices, confusion matrices, and timeΓmetric data.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data = np.random.randn(100, 5)
labels = ['Age', 'Income', 'Score', 'Tenure', 'Spend']
corr = np.corrcoef(data.T)
fig, ax = plt.subplots(figsize=(6, 5))
im = ax.imshow(corr, cmap='RdBu_r', vmin=-1, vmax=1)
plt.colorbar(im, ax=ax)
ax.set_xticks(range(5)); ax.set_yticks(range(5))
ax.set_xticklabels(labels, rotation=45, ha='right')
ax.set_yticklabels(labels)
# Annotate values
for i in range(5):
for j in range(5):
ax.text(j, i, f'{corr[i,j]:.2f}', ha='center', va='center',
fontsize=8, color='black' if abs(corr[i,j]) < 0.6 else 'white')
ax.set_title('Feature Correlation Matrix')
plt.tight_layout()
plt.savefig('heatmap_corr.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved heatmap_corr.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
# 7 days Γ 24 hours activity matrix
activity = np.random.poisson(lam=5, size=(7, 24)).astype(float)
activity[1:5, 9:17] += 15 # weekday work hours spike
days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
hours = [f'{h:02d}:00' for h in range(24)]
fig, ax = plt.subplots(figsize=(14, 4))
im = ax.imshow(activity, cmap='YlOrRd', aspect='auto')
plt.colorbar(im, label='Requests/hr')
ax.set_yticks(range(7)); ax.set_yticklabels(days)
ax.set_xticks(range(0, 24, 2)); ax.set_xticklabels(hours[::2], rotation=45, ha='right')
ax.set_title('API Request Heatmap β Weekday vs Weekend')
plt.tight_layout()
plt.savefig('heatmap_calendar.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved heatmap_calendar.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
# 10 assets x 12 months return matrix (%)
n_assets, n_months = 10, 12
returns = np.random.randn(n_assets, n_months) * 5 # % monthly returns
asset_names = [f'Asset {i+1}' for i in range(n_assets)]
month_names = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
fig, ax = plt.subplots(figsize=(13, 5))
mesh = ax.pcolormesh(returns, cmap='RdYlGn', vmin=-12, vmax=12)
plt.colorbar(mesh, label='Monthly Return (%)', ax=ax)
# Annotate cells
for i in range(n_assets):
for j in range(n_months):
color = 'white' if abs(returns[i, j]) > 8 else 'black'
ax.text(j + 0.5, i + 0.5, f'{returns[i,j]:+.1f}',
ha='center', va='center', fontsize=7, color=color)
ax.set_xticks(np.arange(n_months) + 0.5); ax.set_xticklabels(month_names)
ax.set_yticks(np.arange(n_assets) + 0.5); ax.set_yticklabels(asset_names)
ax.set_title('Asset Monthly Returns Heatmap (%)', fontweight='bold')
plt.tight_layout()
plt.savefig('heatmap_pcolormesh.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved heatmap_pcolormesh.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
import datetime
rng = np.random.default_rng(42)
days = 365
start = datetime.date(2024, 1, 1)
counts = rng.integers(0, 20, days)
for i in range(days):
if (start + datetime.timedelta(i)).weekday() >= 5:
counts[i] = max(0, int(counts[i] * 0.3))
padding = (start.weekday() + 1) % 7
padded = np.concatenate([np.zeros(padding, dtype=int), counts])
n_pad = 7 - len(padded) % 7 if len(padded) % 7 else 0
padded = np.concatenate([padded, np.zeros(n_pad)])
grid = padded.reshape(-1, 7).T
cmap = mcolors.LinearSegmentedColormap.from_list(
'gh', ['#ebedf0','#9be9a8','#40c463','#30a14e','#216e39'])
fig, ax = plt.subplots(figsize=(16, 3))
im = ax.imshow(grid, cmap=cmap, aspect='auto', vmin=0, vmax=counts.max())
ax.set_yticks(range(7))
ax.set_yticklabels(['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], fontsize=9)
ax.set_xticks([]); ax.set_title('2024 Activity Calendar', fontsize=12)
fig.colorbar(im, ax=ax, orientation='horizontal', fraction=0.02,
pad=0.15, label='Activity count')
plt.tight_layout()
plt.savefig('calendar_heatmap.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved calendar_heatmap.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
# Simulated confusion matrix: 5 classes
classes = ['Cat','Dog','Bird','Fish','Rabbit']
cm = np.array([
[85, 5, 3, 2, 5],
[ 4, 88, 2, 1, 5],
[ 3, 2, 82, 8, 5],
[ 1, 2, 6, 89, 2],
[ 6, 4, 3, 2, 85],
])
fig, ax = plt.subplots(figsize=(7, 6))
im = ax.imshow(cm, cmap='Blues')
plt.colorbar(im, ax=ax)
ax.set_xticks(range(5)); ax.set_yticks(range(5))
ax.set_xticklabels(classes, rotation=45, ha='right')
ax.set_yticklabels(classes)
ax.set_xlabel('Predicted'); ax.set_ylabel('Actual')
ax.set_title('Confusion Matrix β Animal Classifier')
for i in range(5):
for j in range(5):
color = 'white' if cm[i,j] > 50 else 'black'
ax.text(j, i, str(cm[i,j]), ha='center', va='center',
fontsize=11, color=color, fontweight='bold')
# Overall accuracy
acc = cm.diagonal().sum() / cm.sum()
ax.set_xlabel(f'Predicted (Accuracy: {acc:.1%})', fontsize=10)
plt.tight_layout()
plt.savefig('heatmap_confusion.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved heatmap_confusion.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
n = 200
# Build correlated dataset
x1 = np.random.randn(n)
x2 = 0.8 * x1 + np.random.randn(n) * 0.4 # correlated with x1
x3 = -0.5 * x1 + np.random.randn(n) * 0.7 # negatively correlated
x4 = np.random.randn(n) # independent
x5 = 0.6 * x2 + np.random.randn(n) * 0.5 # correlated with x2
x6 = np.random.randn(n) # independent
data = np.column_stack([x1, x2, x3, x4, x5, x6])
labels = ['X1', 'X2', 'X3', 'X4', 'X5', 'X6']
# TODO: corr = np.corrcoef(data.T)
fig, ax = plt.subplots(figsize=(7, 6))
# TODO: im = ax.imshow(corr, cmap='coolwarm', vmin=-1, vmax=1)
# TODO: plt.colorbar(im, ax=ax)
# TODO: set tick labels (rotated 45 for x-axis)
# ax.set_xticks(range(6)); ax.set_xticklabels(labels, rotation=45, ha='right')
# ax.set_yticks(range(6)); ax.set_yticklabels(labels)
# TODO: annotate each cell with corr value
# for i in range(6):
# for j in range(6):
# color = 'white' if abs(corr[i,j]) > 0.6 else 'black'
# ax.text(j, i, f'{corr[i,j]:.2f}', ha='center', va='center', fontsize=8, color=color)
# TODO: ax.set_title(...)
plt.tight_layout()
# TODO: plt.savefig('practice_heatmap.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')twinx() creates a second y-axis sharing the same x-axis β essential when two variables have different scales.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
months = ['Jan','Feb','Mar','Apr','May','Jun']
revenue = [120, 135, 128, 155, 162, 180]
margin = [22.1, 21.5, 23.0, 24.2, 23.8, 25.5]
fig, ax1 = plt.subplots(figsize=(9, 4))
ax2 = ax1.twinx()
bars = ax1.bar(months, revenue, color='steelblue', alpha=0.7, label='Revenue ($K)')
line = ax2.plot(months, margin, 'o-', color='tomato', linewidth=2.5,
markersize=7, markerfacecolor='white', markeredgewidth=2, label='Margin %')
ax1.set_ylabel('Revenue ($K)', color='steelblue')
ax2.set_ylabel('Gross Margin (%)', color='tomato')
ax1.tick_params(axis='y', labelcolor='steelblue')
ax2.tick_params(axis='y', labelcolor='tomato')
lines = line
labels = [l.get_label() for l in lines]
ax1.legend(bars, ['Revenue ($K)'], loc='upper left')
ax2.legend(lines, labels, loc='lower right')
ax1.set_title('Revenue & Gross Margin')
plt.tight_layout()
plt.savefig('twin_bar_line.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved twin_bar_line.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(9)
hours = np.arange(24)
temp = 20 + 8 * np.sin((hours - 6) * np.pi / 12) + np.random.randn(24)
humidity = 60 - 20 * np.sin((hours - 6) * np.pi / 12) + np.random.randn(24) * 3
fig, ax1 = plt.subplots(figsize=(10, 4))
ax2 = ax1.twinx()
ax1.plot(hours, temp, color='#e74c3c', linewidth=2, label='Temp (Β°C)')
ax1.fill_between(hours, temp, alpha=0.1, color='#e74c3c')
ax2.plot(hours, humidity, color='#3498db', linewidth=2,
linestyle='--', label='Humidity (%)')
ax1.set_xlabel('Hour of Day'); ax1.set_ylabel('Temperature (Β°C)', color='#e74c3c')
ax2.set_ylabel('Humidity (%)', color='#3498db')
ax1.set_title('24-Hour Weather Profile')
ax1.grid(True, alpha=0.2)
plt.tight_layout()
plt.savefig('twin_weather.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved twin_weather.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(11)
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
x = np.arange(12)
revenue = np.array([42, 38, 51, 47, 59, 65, 70, 62, 55, 68, 75, 88])
cost = np.array([30, 29, 36, 34, 41, 44, 48, 43, 40, 46, 51, 59])
margin = (revenue - cost) / revenue * 100
fig, ax1 = plt.subplots(figsize=(11, 5))
ax2 = ax1.twinx()
# Stacked area (revenue, cost on ax1)
ax1.fill_between(x, cost, alpha=0.35, color='#C44E52', label='Cost ($K)')
ax1.fill_between(x, revenue, cost, alpha=0.35, color='#55A868', label='Profit ($K)')
ax1.plot(x, revenue, 'o-', color='#4C72B0', linewidth=2,
markersize=5, markerfacecolor='white', markeredgewidth=1.5, label='Revenue ($K)')
# Margin % on secondary axis
ax2.plot(x, margin, 's--', color='#DD8452', linewidth=1.8,
markersize=6, markerfacecolor='white', markeredgewidth=1.5, label='Margin %')
ax2.set_ylabel('Gross Margin (%)', color='#DD8452')
ax2.tick_params(axis='y', labelcolor='#DD8452')
ax2.set_ylim(0, 50)
ax1.set_xticks(x); ax1.set_xticklabels(months, rotation=30, ha='right')
ax1.set_ylabel('Amount ($K)', color='#4C72B0')
ax1.tick_params(axis='y', labelcolor='#4C72B0')
ax1.set_title('Revenue, Cost & Margin β Full Year', fontweight='bold')
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', fontsize=8)
ax1.grid(True, axis='y', alpha=0.2)
plt.tight_layout()
plt.savefig('twin_three_axis.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved twin_three_axis.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(0)
t = np.linspace(0, 365, 365)
revenue = 1000 + 2*t + 150*np.sin(2*np.pi*t/365) + rng.normal(0, 30, 365)
traffic = 5000 + 10*t + rng.normal(0, 200, 365)
fig, ax1 = plt.subplots(figsize=(12, 5))
ax2 = ax1.twinx()
l1, = ax1.plot(t, revenue, color='steelblue', lw=1.5, label='Revenue ($)')
l2, = ax2.plot(t, traffic, color='tomato', lw=1.2, alpha=0.7, label='Traffic')
# Highlight events
events = [(90, 120, '#ffffcc', 'Summer\nPromo'),
(200, 220, '#e8f5e9', 'Product\nLaunch'),
(300, 340, '#fce4ec', 'Holiday\nSale')]
for start, end, color, label in events:
ax1.axvspan(start, end, alpha=0.4, color=color)
ax1.annotate(label, xy=((start+end)/2, revenue.max()*0.95),
ha='center', fontsize=9, fontweight='bold')
ax1.set(xlabel='Day of Year', ylabel='Revenue ($)', title='Revenue & Traffic with Event Annotations')
ax2.set_ylabel('Daily Traffic', color='tomato')
ax2.tick_params(axis='y', labelcolor='tomato')
ax1.legend(handles=[l1, l2], loc='upper left')
plt.tight_layout()
plt.savefig('twin_annotated.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved twin_annotated.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(12)
days = np.arange(1, 31)
orders = (500 + np.cumsum(np.random.randn(30)*20) +
np.random.randn(30)*30).clip(400, 900).astype(int)
cvr = (3.5 + np.random.randn(30)*0.4 +
np.sin(days/5) * 0.3).clip(2.5, 5.0)
fig, ax1 = plt.subplots(figsize=(12, 4))
ax2 = ax1.twinx()
ax1.bar(days, orders, color='#4C72B0', alpha=0.5, label='Orders')
ax2.plot(days, cvr, 'o-', color='#DD8452', linewidth=2,
markersize=5, markerfacecolor='white', markeredgewidth=1.5,
label='Conversion Rate (%)')
# Flag low-CVR days
low_cvr = days[cvr < 3.0]
for d in low_cvr:
ax1.axvspan(d-0.5, d+0.5, color='red', alpha=0.1)
ax1.set_xlabel('Day of Month')
ax1.set_ylabel('Orders', color='#4C72B0')
ax2.set_ylabel('Conversion Rate (%)', color='#DD8452')
ax1.set_title('January 2024 β Orders & Conversion Rate')
ax1.legend(loc='upper left', frameon=False)
ax2.legend(loc='upper right', frameon=False)
plt.tight_layout()
plt.savefig('twin_ecommerce.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved twin_ecommerce.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
revenue = np.array([42, 38, 51, 47, 59, 65, 70, 62, 55, 68, 75, 88])
# TODO: compute MoM growth rate (%)
# growth = np.concatenate([[0], np.diff(revenue) / revenue[:-1] * 100])
fig, ax1 = plt.subplots(figsize=(11, 5))
ax2 = ax1.twinx()
# TODO: ax1.bar(months, revenue, color='steelblue', alpha=0.7, label='Revenue ($K)')
# TODO: ax2.plot(months, growth, 'o-', color='tomato', ...)
# TODO: color y-axis labels
# ax1.set_ylabel('Revenue ($K)', color='steelblue')
# ax2.set_ylabel('MoM Growth (%)', color='tomato')
# ax1.tick_params(axis='y', labelcolor='steelblue')
# ax2.tick_params(axis='y', labelcolor='tomato')
# TODO: add a horizontal dashed line at growth=0 on ax2
# ax2.axhline(0, color='gray', linestyle='--', linewidth=0.8)
# TODO: legends for both axes
ax1.set_title('Monthly Revenue & Growth Rate')
plt.tight_layout()
# TODO: plt.savefig('practice_twin.png', dpi=100, bbox_inches='tight')
plt.close()
print('Done')Save plots as PNG, PDF, SVG, or EPS with savefig(). Use plt.style.use() or rcParams to apply consistent styling across all charts.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import os
fig, ax = plt.subplots(figsize=(8, 4))
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), linewidth=2)
ax.set_title('Saved Figure Example')
ax.set_xlabel('x'); ax.set_ylabel('sin(x)')
# Save as PNG (high DPI for print)
fig.savefig('plot.png', dpi=150, bbox_inches='tight', facecolor='white')
# Save as PDF (vector β best for papers)
fig.savefig('plot.pdf', bbox_inches='tight')
# Save as SVG (scalable for web)
fig.savefig('plot.svg', bbox_inches='tight')
print('Saved: plot.png, plot.pdf, plot.svg')
plt.close()
for f in ['plot.png','plot.pdf','plot.svg']:
if os.path.exists(f): os.remove(f)
print('Cleaned up.')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
print("Available styles (first 5):", plt.style.available[:5], "...")
# Apply a style
with plt.style.context('seaborn-v0_8-whitegrid'):
fig, ax = plt.subplots(figsize=(8, 4))
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), linewidth=2, label='sin(x)')
ax.plot(x, np.cos(x), linewidth=2, label='cos(x)')
ax.set_title('Seaborn Whitegrid Style')
ax.legend()
plt.tight_layout()
fig.savefig('style_whitegrid.png', dpi=100, bbox_inches='tight')
plt.close()
print('Saved style_whitegrid.png')
# Custom rcParams for global defaults
plt.rcParams.update({
'font.size': 12,
'axes.titlesize': 14,
'figure.facecolor': 'white',
})
print('rcParams updated.')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import os
plt.rcParams.update({
'font.size': 10,
'axes.spines.top': False,
'axes.spines.right': False,
'grid.alpha': 0.3,
})
np.random.seed(42)
datasets = {
'alpha': np.random.randn(300) * 2 + 5,
'beta': np.random.exponential(2, 300),
'gamma': np.random.uniform(0, 10, 300),
}
saved = []
for name, data in datasets.items():
fig, axes = plt.subplots(1, 2, figsize=(9, 3))
axes[0].hist(data, bins=25, color='steelblue', edgecolor='white', linewidth=0.4)
axes[0].set_title(f'{name.capitalize()} β Histogram')
axes[0].axvline(data.mean(), color='red', linestyle='--', linewidth=1.2, label=f'mean={data.mean():.2f}')
axes[0].legend(fontsize=8)
axes[1].boxplot(data, vert=True, patch_artist=True,
boxprops=dict(facecolor='steelblue', alpha=0.5))
axes[1].set_title(f'{name.capitalize()} β Boxplot')
axes[1].set_ylabel('Value')
fname = f'report_{name}.png'
fig.tight_layout()
fig.savefig(fname, dpi=120, bbox_inches='tight', facecolor='white')
plt.close(fig)
saved.append(fname)
print(f' Saved {fname} ({os.path.getsize(fname)//1024} KB)')
# Clean up
for f in saved:
if os.path.exists(f): os.remove(f)
print('Batch export complete.')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots(figsize=(6, 5))
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.set_aspect('equal'); ax.set_title('Bouncing Ball Animation')
ax.set_facecolor('#1a1a2e')
ball, = ax.plot([], [], 'o', color='#ffa600', ms=18)
trail_x, trail_y = [], []
trail, = ax.plot([], [], '-', color='#ffa600', alpha=0.3, lw=2)
x, y = 5.0, 8.0
vx, vy = 0.15, -0.12
def init():
ball.set_data([], []); trail.set_data([], [])
return ball, trail
def update(frame):
global x, y, vx, vy
x += vx; y += vy
vy -= 0.005 # gravity
if x <= 0 or x >= 10: vx *= -1
if y <= 0: vy = abs(vy) * 0.92; y = 0
trail_x.append(x); trail_y.append(y)
if len(trail_x) > 40:
trail_x.pop(0); trail_y.pop(0)
ball.set_data([x], [y])
trail.set_data(trail_x, trail_y)
return ball, trail
ani = animation.FuncAnimation(fig, update, frames=80, init_func=init,
interval=40, blit=True)
ani.save('bouncing_ball.gif', writer='pillow', fps=25, dpi=80)
plt.close()
print('Saved bouncing_ball.gif')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
import os
# Apply consistent branding
plt.rcParams.update({
'font.family': 'DejaVu Sans',
'font.size': 10,
'axes.titlesize': 12,
'axes.titleweight': 'bold',
'axes.spines.top': False,
'axes.spines.right':False,
'grid.alpha': 0.3,
})
def save_kpi_chart(metric, values, labels, filename, color='steelblue'):
fig, ax = plt.subplots(figsize=(8, 3))
ax.plot(range(len(values)), values, 'o-', color=color,
linewidth=2, markersize=6, markerfacecolor='white', markeredgewidth=2)
ax.fill_between(range(len(values)), values, alpha=0.1, color=color)
ax.set_xticks(range(len(labels)))
ax.set_xticklabels(labels, rotation=30, ha='right')
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x,_: f'${x:,.0f}'))
ax.set_title(metric); ax.grid(True)
fig.tight_layout()
fig.savefig(filename, dpi=120, bbox_inches='tight', facecolor='white')
plt.close(fig)
print(f'Saved {filename} ({os.path.getsize(filename)//1024} KB)')
months = ['Jan','Feb','Mar','Apr','May','Jun']
rev = [42000, 38500, 51000, 47200, 59800, 65600]
save_kpi_chart('Monthly Revenue', rev, months, 'revenue_report.png')
if os.path.exists('revenue_report.png'):
os.remove('revenue_report.png')
print('Cleaned up.')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import os
# TODO: update rcParams (font.size=11, figure.facecolor='white')
# plt.rcParams.update({...})
x = np.linspace(0, 2 * np.pi, 200)
cats = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 17, 38, 29]
# TODO: use plt.style.context('seaborn-v0_8-whitegrid') to create the figure
# with plt.style.context('seaborn-v0_8-whitegrid'):
# fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
#
# # left: line plot of sin(x)
# ax1.plot(x, np.sin(x), color='steelblue', linewidth=2)
# ax1.set_title('sin(x)'); ax1.set_xlabel('x'); ax1.set_ylabel('y')
#
# # right: bar chart
# ax2.bar(cats, values, color='#DD8452', edgecolor='white')
# ax2.set_title('Category Values'); ax2.set_ylabel('Count')
#
# plt.tight_layout()
#
# # TODO: save as PNG and SVG
# # fig.savefig('practice_output.png', dpi=150, bbox_inches='tight', facecolor='white')
# # fig.savefig('practice_output.svg', bbox_inches='tight')
# plt.close()
# TODO: print file sizes
# for f in ['practice_output.png', 'practice_output.svg']:
# print(f'{f}: {os.path.getsize(f)//1024} KB')
# TODO: clean up both files
# for f in ['practice_output.png', 'practice_output.svg']:
# if os.path.exists(f): os.remove(f)
print('Done')Create 3D visualizations with Axes3D β surface plots, wireframes, 3D scatter plots, and line trajectories that reveal multi-dimensional structure.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
np.random.seed(42)
x, y, z = np.random.randn(3, 100)
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
sc = ax.scatter(x, y, z, c=z, cmap='plasma', s=50)
plt.colorbar(sc, ax=ax, label='Z value')
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
ax.set_title('3D Scatter Plot')
plt.tight_layout()
plt.savefig('3d_scatter.png', dpi=80); plt.close()
print('Saved 3d_scatter.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
x = np.linspace(-3, 3, 50)
y = np.linspace(-3, 3, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.9)
plt.colorbar(surf, ax=ax, shrink=0.5, label='sin(r)')
ax.set_title('3D Surface: sin(sqrt(x^2+y^2))')
plt.tight_layout()
plt.savefig('surface3d.png', dpi=80); plt.close()
print('Saved surface3d.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
x = np.linspace(-2, 2, 30)
y = np.linspace(-2, 2, 30)
X, Y = np.meshgrid(x, y)
Z = X**2 - Y**2
fig = plt.figure(figsize=(12, 5))
ax1 = fig.add_subplot(121, projection='3d')
ax1.plot_wireframe(X, Y, Z, rstride=3, cstride=3, color='teal', linewidth=0.5)
ax1.set_title('Wireframe: x^2 - y^2')
ax2 = fig.add_subplot(122, projection='3d')
ax2.plot_surface(X, Y, Z, cmap='coolwarm', alpha=0.7)
ax2.contour(X, Y, Z, zdir='z', offset=Z.min(), cmap='coolwarm')
ax2.set_title('Surface + Contour')
plt.tight_layout()
plt.savefig('wireframe3d.png', dpi=80); plt.close()
print('Saved wireframe3d.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
t = np.linspace(0, 4*np.pi, 300)
x = np.sin(t)
y = np.cos(t)
z = t / (4*np.pi)
fig = plt.figure(figsize=(7, 6))
ax = fig.add_subplot(111, projection='3d')
for i in range(len(t)-1):
ax.plot(x[i:i+2], y[i:i+2], z[i:i+2], color=plt.cm.plasma(z[i]), linewidth=2)
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Height')
ax.set_title('3D Helix Trajectory')
plt.tight_layout()
plt.savefig('helix3d.png', dpi=80); plt.close()
print('Saved helix3d.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
x = np.linspace(-2, 2, 100)
y = np.linspace(-1, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.clip((1-X)**2 + 100*(Y-X**2)**2, 0, 2500)
# TODO: create 3D surface plot
# TODO: mark minimum at (1, 1, 0)
# TODO: save to 'rosenbrock.png'Make publication-quality figures with style sheets, rcParams, custom color cycles, and reusable theming functions.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
print('Available styles (sample):', plt.style.available[:8])
styles = ['seaborn-v0_8-darkgrid', 'ggplot', 'bmh']
x = np.linspace(0, 2*np.pi, 100)
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
for ax, style in zip(axes, styles):
with plt.style.context(style):
for i in range(3):
ax.plot(x, np.sin(x + i*np.pi/3))
ax.set_title(style.split('-')[-1])
plt.tight_layout()
plt.savefig('styles.png', dpi=80); plt.close()
print('Saved styles.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
custom = {
'figure.facecolor': '#1e1e2e', 'axes.facecolor': '#1e1e2e',
'axes.edgecolor': '#6e6e8e', 'axes.labelcolor': '#cdd6f4',
'xtick.color': '#cdd6f4', 'ytick.color': '#cdd6f4',
'text.color': '#cdd6f4', 'grid.color': '#313244',
'axes.prop_cycle': matplotlib.cycler('color', ['#89b4fa','#f38ba8','#a6e3a1','#fab387']),
'font.size': 12,
}
plt.rcParams.update(custom)
x = np.linspace(0, 4*np.pi, 200)
fig, ax = plt.subplots(figsize=(9, 5))
for i, label in enumerate(['sin', 'cos', 'sin2']):
y = np.sin(x)*np.sin(x) if i==2 else (np.sin(x) if i==0 else np.cos(x))
ax.plot(x, y, linewidth=2, label=label)
ax.legend(facecolor='#313244'); ax.set_title('Dark Theme'); ax.grid(True)
plt.tight_layout()
plt.savefig('dark_theme.png', dpi=80, facecolor=fig.get_facecolor()); plt.close()
plt.rcParams.update(plt.rcParamsDefault)
print('Saved dark_theme.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
PALETTE = ['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00']
plt.rcParams['axes.prop_cycle'] = matplotlib.cycler('color', PALETTE)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
categories = ['A','B','C','D']; x = np.arange(len(categories)); width=0.25
for i, grp in enumerate(['G1','G2','G3']):
axes[0].bar(x+i*width, np.random.randint(10,50,4), width, label=grp)
axes[0].set_xticks(x+width); axes[0].set_xticklabels(categories)
axes[0].legend(); axes[0].set_title('Custom Colors β Bars')
t = np.linspace(0,10,200)
for i in range(5):
axes[1].plot(t, np.sin(t+i)*np.exp(-0.1*t), label=f'S{i+1}')
axes[1].legend(fontsize=8); axes[1].set_title('Custom Colors β Lines')
plt.tight_layout()
plt.savefig('colors.png', dpi=80); plt.close()
plt.rcParams.update(plt.rcParamsDefault)
print('Saved colors.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from contextlib import contextmanager
@contextmanager
def pub_style(w=8, h=5):
params = {
'font.size': 12, 'axes.titlesize': 14, 'axes.labelsize': 12,
'lines.linewidth': 2, 'axes.spines.top': False, 'axes.spines.right': False,
}
with plt.style.context('seaborn-v0_8-whitegrid'):
plt.rcParams.update(params)
fig, ax = plt.subplots(figsize=(w, h))
yield fig, ax
plt.tight_layout()
x = np.linspace(0, 10, 200)
with pub_style() as (fig, ax):
ax.plot(x, np.sin(x), label='sin(x)')
ax.plot(x, np.cos(x), '--', label='cos(x)')
ax.set_xlabel('x'); ax.set_ylabel('Amplitude')
ax.set_title('Publication-Ready Figure'); ax.legend()
fig.savefig('publication.png', bbox_inches='tight')
plt.close()
print('Saved publication.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
# TODO: set dark rcParams
# TODO: 2x2 subplots
# TODO: top-left: scatter (x,y normal, color=magnitude)
# TODO: top-right: 3 sine waves
# TODO: bottom-left: 12-bar monthly sales
# TODO: bottom-right: histogram 500 samples, 30 bins
# TODO: suptitle and save to 'dark_dashboard.png'Add rich annotations β arrows, text boxes, spans, and LaTeX math expressions β to communicate insights directly on the plot.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 4*np.pi, 300)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, y, 'steelblue', linewidth=2)
# Annotate maximum
max_idx = y.argmax()
ax.annotate('Global Max', xy=(x[max_idx], y[max_idx]),
xytext=(x[max_idx]+1, 0.6),
arrowprops=dict(arrowstyle='->', color='red', lw=2),
fontsize=11, color='red', fontweight='bold')
# Annotate minimum
min_idx = y.argmin()
ax.annotate('Global Min', xy=(x[min_idx], y[min_idx]),
xytext=(x[min_idx]-1.5, -0.6),
arrowprops=dict(arrowstyle='->', color='orange', lw=2),
fontsize=11, color='orange')
ax.set_title('sin(x) with Annotations'); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('annotated_sine.png', dpi=80); plt.close()
print('Saved annotated_sine.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 200)
fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(x, np.exp(-0.3*x)*np.sin(x*2), linewidth=2)
box_styles = [('round,pad=0.3', 'lightblue', 'navy'),
('round4,pad=0.4', 'lightyellow', 'darkorange'),
('sawtooth,pad=0.3', 'lightgreen', 'darkgreen')]
for i, (style, fc, ec) in enumerate(box_styles):
ax.text(2+i*3, 0.5-i*0.3, f'Style: {style.split(",")[0]}',
fontsize=10, ha='center',
bbox=dict(boxstyle=style, facecolor=fc, edgecolor=ec, alpha=0.9))
ax.set_title('Text Box Styles'); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('textboxes.png', dpi=80); plt.close()
print('Saved textboxes.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
dates = np.arange(60)
prices = 100 + np.cumsum(np.random.randn(60))
fig, ax = plt.subplots(figsize=(11, 5))
ax.plot(dates, prices, 'steelblue', linewidth=1.5)
# Shade event regions
ax.axvspan(10, 20, color='red', alpha=0.15, label='Crash period')
ax.axvspan(35, 45, color='green', alpha=0.15, label='Recovery period')
ax.axhline(prices.mean(), color='gray', linestyle='--', linewidth=1, label='Mean price')
# Annotate events
ax.text(15, ax.get_ylim()[1]*0.98, 'Crash', ha='center', color='darkred', fontsize=10)
ax.text(40, ax.get_ylim()[1]*0.98, 'Recovery', ha='center', color='darkgreen', fontsize=10)
ax.legend(); ax.set_xlabel('Day'); ax.set_ylabel('Price')
ax.set_title('Price Series with Event Annotations')
plt.tight_layout()
plt.savefig('event_regions.png', dpi=80); plt.close()
print('Saved event_regions.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 300)
mu, sigma = 0, 1
y = (1/(sigma*np.sqrt(2*np.pi))) * np.exp(-0.5*((x-mu)/sigma)**2)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, y, 'steelblue', linewidth=2.5)
ax.fill_between(x, y, where=(x>=-1)&(x<=1), alpha=0.3, color='steelblue', label=r'$\pm 1\sigma$ (68.3%)')
# LaTeX in axis labels
ax.set_xlabel(r'$x$', fontsize=14)
ax.set_ylabel(r'$f(x) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{1}{2}\left(\frac{x-\mu}{\sigma}\right)^2}$', fontsize=11)
ax.set_title(r'Normal Distribution $\mathcal{N}(\mu=0, \sigma=1)$', fontsize=13)
# LaTeX annotation
ax.annotate(r'$\mu = 0$', xy=(0, y.max()), xytext=(1.2, y.max()*0.9),
arrowprops=dict(arrowstyle='->'), fontsize=12)
ax.legend(fontsize=11)
plt.tight_layout()
plt.savefig('latex_plot.png', dpi=80); plt.close()
print('Saved latex_plot.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
x = np.linspace(0, 10, 50)
y = 2*x + 1 + np.random.randn(50) * 2
x_fit = np.linspace(0, 12, 200)
y_fit = 2*x_fit + 1
fig, ax = plt.subplots(figsize=(9, 5))
ax.scatter(x, y, alpha=0.6, label='Data')
ax.plot(x_fit, y_fit, 'r-', label='Fit')
# TODO: add shaded CI band (y_fit +/- 2 units)
# TODO: shade extrapolation x>8 with axvspan
# TODO: annotate slope with arrow and r'$\hat{\beta}_1 = 2$'
# TODO: save to 'ci_plot.png'import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots(figsize=(7, 3))
x = np.linspace(0, 2*np.pi, 200)
line, = ax.plot(x, np.sin(x))
ax.set_ylim(-1.3, 1.3)
def update(frame):
line.set_ydata(np.sin(x + frame * 0.15))
return line,
ani = animation.FuncAnimation(fig, update, frames=40, interval=60, blit=True)
try:
ani.save('sine_anim.gif', writer='pillow', fps=15)
print('Saved sine_anim.gif')
except Exception as e:
print(f'pillow not installed ({e}) β animation built ok')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
np.random.seed(42)
n = 20
pos = np.random.randn(n, 2)
fig, ax = plt.subplots(figsize=(5, 5))
sc = ax.scatter(pos[:, 0], pos[:, 1], c=range(n), cmap='hsv', s=50)
ax.set_xlim(-5, 5); ax.set_ylim(-5, 5)
ax.set_title('Random Walk Particles')
def update(frame):
global pos
pos += np.random.randn(n, 2) * 0.15
pos = np.clip(pos, -4.5, 4.5)
sc.set_offsets(pos)
return sc,
ani = animation.FuncAnimation(fig, update, frames=50, interval=80, blit=True)
try:
ani.save('particles.gif', writer='pillow', fps=12)
print('Saved particles.gif')
except Exception as e:
print(f'pillow not found ({e})')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
x = np.linspace(0, 2*np.pi, 200)
l1, = ax1.plot(x, np.sin(x), 'b-')
l2, = ax2.plot(x, np.cos(x), 'r-')
ax1.set_title('sin(x+t)'); ax2.set_title('cos(x-t)')
def update(frame):
t = frame * 0.12
l1.set_ydata(np.sin(x + t))
l2.set_ydata(np.cos(x - t))
return l1, l2
ani = animation.FuncAnimation(fig, update, frames=50, blit=True)
try:
ani.save('dual_anim.gif', writer='pillow', fps=15)
print('Saved dual_anim.gif')
except:
print('Animation created (pillow needed to save)')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots(figsize=(6, 4))
np.random.seed(0)
frames = []
for i in range(10):
data = np.random.randn(50) + i * 0.5
hist = ax.hist(data, bins=20, range=(-3, 9),
color=plt.cm.viridis(i/10), alpha=0.7)
title = ax.text(0.5, 1.01, f'Shift = {i*0.5:.1f}',
transform=ax.transAxes, ha='center')
frames.append(hist[2].tolist() + [title])
ani = animation.ArtistAnimation(fig, frames, interval=300, blit=True)
try:
ani.save('hist_anim.gif', writer='pillow', fps=3)
print('Saved hist_anim.gif')
except:
print('ArtistAnimation built (pillow needed to save)')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots(figsize=(4, 6))
ax.set_xlim(0, 1); ax.set_ylim(-0.2, 5.5)
ball, = ax.plot([0.5], [5], 'bo', ms=15)
dt = 0.05; g = 9.8
y, vy = 5.0, 0.0
# TODO: define update(frame) that applies gravity, reverses on bounce
# TODO: FuncAnimation for 100 frames
# TODO: save to 'bounce.gif' with pillowimport matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 4*np.pi, 200)
styles = ['seaborn-v0_8-paper', 'ggplot', 'bmh']
fig, axes = plt.subplots(1, 3, figsize=(13, 4))
for ax, style in zip(axes, styles):
with plt.style.context(style):
ax.plot(x, np.sin(x), label='sin')
ax.plot(x, np.cos(x), label='cos')
ax.set_title(style.split('_')[-1])
ax.legend(fontsize=8)
fig.tight_layout()
fig.savefig('styles_compare.png', dpi=120, bbox_inches='tight')
print('Saved styles_compare.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(6, 4))
x = np.linspace(0.1, 3, 200)
ax.plot(x, np.exp(-x**2), label=r'$f(x) = e^{-x^2}$', lw=2)
ax.plot(x, 1/(1+x**2), label=r'$g(x) = \frac{1}{1+x^2}$', lw=2, ls='--')
ax.set_xlabel(r'$x$ (normalized)', fontsize=12)
ax.set_ylabel(r'$f(x)$', fontsize=12)
ax.set_title(r'Gaussian vs Lorentzian decay', fontsize=13)
ax.legend(fontsize=11); ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('latex_labels.png', dpi=150, bbox_inches='tight')
print('Saved latex_labels.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
fig, axes = plt.subplots(2, 3, figsize=(12, 7), sharex=True, sharey=True)
for i, ax in enumerate(axes.flat):
data = np.random.normal(i, 1.2, 80)
ax.hist(data, bins=18, edgecolor='k', alpha=0.7)
ax.axvline(data.mean(), color='red', ls='--', lw=1.2)
ax.set_title(f'Group {i+1} (ΞΌ={i})', fontsize=10)
fig.suptitle('Shared-Axis Multi-Panel', fontsize=14, fontweight='bold')
fig.tight_layout()
fig.savefig('multi_panel.png', dpi=120, bbox_inches='tight')
print('Saved multi_panel.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams.update({'font.family': 'serif', 'font.size': 10,
'axes.linewidth': 1.2, 'xtick.major.width': 1.2})
np.random.seed(42)
groups = ['Control', 'Drug A', 'Drug B']
means = [2.1, 3.4, 2.9]; stds = [0.3, 0.4, 0.35]
fig, ax = plt.subplots(figsize=(4.5, 3.5))
bars = ax.bar(groups, means, yerr=stds, capsize=5,
color=['#4878D0','#EE854A','#6ACC65'], edgecolor='k', lw=0.8)
for b, m in zip(bars, means):
ax.text(b.get_x()+b.get_width()/2, b.get_height()+0.06,
f'{m:.1f}', ha='center', fontsize=9)
ax.set_ylabel(r'Response ($ΞΌmol/L)', fontsize=11)
ax.set_title('Treatment Effect', fontsize=12)
ax.spines[['top','right']].set_visible(False)
fig.tight_layout()
fig.savefig('publication_fig.png', dpi=300, bbox_inches='tight')
print('Saved publication_fig.png at 300 DPI')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes, mark_inset
import numpy as np
t = np.linspace(0, 20, 500)
y = np.exp(-0.1*t) * np.sin(2*t)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4))
# TODO: ax1 linear plot + inset zoom t in [0,2]
# TODO: ax2 semilogy plot
# TODO: seaborn-v0_8-paper style, 300 DPI exportimport matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
colors = ['#1a1a2e','#16213e','#0f3460','#e94560']
cmap = mcolors.LinearSegmentedColormap.from_list('dark_red', colors, N=256)
np.random.seed(0)
data = np.random.randn(40, 40).cumsum(axis=0)
fig, ax = plt.subplots(figsize=(6, 4))
im = ax.imshow(data, cmap=cmap, aspect='auto')
plt.colorbar(im, ax=ax, label='Value')
ax.set_title('Custom Dark-Red Colormap')
fig.savefig('custom_cmap.png', dpi=120, bbox_inches='tight')
print('Saved custom_cmap.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
np.random.seed(42)
data = np.random.randn(20, 20) * 3 + 1
vmax = max(abs(data.min()), abs(data.max()))
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
im1 = ax1.imshow(data, cmap='RdBu_r', vmin=-vmax, vmax=vmax)
ax1.set_title('Symmetric Norm'); plt.colorbar(im1, ax=ax1)
norm = mcolors.TwoSlopeNorm(vmin=data.min(), vcenter=0, vmax=data.max())
im2 = ax2.imshow(data, cmap='RdBu_r', norm=norm)
ax2.set_title('TwoSlopeNorm'); plt.colorbar(im2, ax=ax2)
fig.tight_layout()
fig.savefig('diverging_norm.png', dpi=120, bbox_inches='tight')
print('Saved diverging_norm.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
bounds = [0, 1, 2, 3, 4, 5]
cmap = plt.get_cmap('RdYlGn', len(bounds)-1)
norm = mcolors.BoundaryNorm(bounds, cmap.N)
levels = ['None','Low','Med','High','Max']
np.random.seed(7)
data = np.random.randint(0, 5, (8, 10))
fig, ax = plt.subplots(figsize=(9, 5))
im = ax.imshow(data, cmap=cmap, norm=norm)
cbar = plt.colorbar(im, ax=ax, boundaries=bounds, ticks=[0.5,1.5,2.5,3.5,4.5])
cbar.set_ticklabels(levels)
for i in range(data.shape[0]):
for j in range(data.shape[1]):
ax.text(j, i, levels[data[i,j]][:3],
ha='center', va='center', fontsize=8)
ax.set_title('Discrete Risk Heatmap')
fig.savefig('discrete_cmap.png', dpi=120, bbox_inches='tight')
print('Saved discrete_cmap.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
cmaps = ['viridis', 'plasma', 'inferno', 'cividis']
x = y = np.linspace(-np.pi, np.pi, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
fig, axes = plt.subplots(1, 4, figsize=(14, 3.5))
for ax, cm in zip(axes, cmaps):
im = ax.imshow(Z, cmap=cm, aspect='auto')
ax.set_title(cm)
plt.colorbar(im, ax=ax, fraction=0.046)
fig.suptitle('Perceptually Uniform Colormaps', fontsize=12)
fig.tight_layout()
fig.savefig('perceptual_cmaps.png', dpi=120, bbox_inches='tight')
print('Saved perceptual_cmaps.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
colors = ['#1a6b9a','#2ecc71','#f1c40f','#8b5e3c','#f5f5f5']
cmap = mcolors.LinearSegmentedColormap.from_list('terrain_custom', colors)
x = y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
# TODO: imshow with custom cmap
# TODO: colorbar with 5 labeled ticks
# TODO: save 'terrain.png' at 150 DPIVisualize measurement uncertainty with errorbar(), fill_between() for confidence bands, and asymmetric errors.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
x = np.arange(1, 8)
y = np.array([2.3, 3.1, 2.8, 4.5, 3.9, 5.2, 4.8])
yerr = np.random.uniform(0.2, 0.6, len(x))
fig, ax = plt.subplots(figsize=(8, 4))
ax.errorbar(x, y, yerr=yerr, fmt='o-', color='steelblue',
ecolor='lightsteelblue', elinewidth=2, capsize=5,
capthick=2, label='Mean Β± SD')
ax.set_xlabel('Experiment')
ax.set_ylabel('Value')
ax.set_title('Error Bars β Symmetric')
ax.legend()
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('errorbars_sym.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved errorbars_sym.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
x = np.arange(5)
y = np.array([1.5, 2.8, 2.2, 3.6, 3.0])
yerr_low = np.array([0.3, 0.5, 0.4, 0.6, 0.3])
yerr_high = np.array([0.5, 0.3, 0.6, 0.2, 0.7])
fig, ax = plt.subplots(figsize=(7, 4))
ax.errorbar(x, y, yerr=[yerr_low, yerr_high],
fmt='s--', color='tomato', ecolor='lightcoral',
elinewidth=2, capsize=6, label='Median [IQR]')
ax.set_xticks(x)
ax.set_xticklabels([f'Group {i+1}' for i in x])
ax.set_title('Asymmetric Error Bars')
ax.legend()
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('errorbars_asym.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved errorbars_asym.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(2)
x = np.linspace(0, 10, 100)
y_true = np.sin(x)
noise = np.random.randn(100) * 0.3
y_mean = y_true + noise * 0.2
y_lower = y_mean - 1.96 * 0.3
y_upper = y_mean + 1.96 * 0.3
fig, ax = plt.subplots(figsize=(9, 4))
ax.plot(x, y_mean, color='steelblue', linewidth=2, label='Mean')
ax.fill_between(x, y_lower, y_upper, alpha=0.2, color='steelblue',
label='95% CI')
ax.plot(x, y_true, 'k--', linewidth=1, alpha=0.6, label='True')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Confidence Interval Band')
ax.legend()
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('conf_band.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved conf_band.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
x = np.linspace(0, 5, 80)
colors = ['steelblue', 'tomato', 'seagreen']
labels = ['Model A', 'Model B', 'Model C']
offsets = [0, 0.5, 1.0]
fig, ax = plt.subplots(figsize=(9, 5))
for c, lab, off in zip(colors, labels, offsets):
mu = np.sin(x + off)
sd = 0.15 + 0.05 * np.abs(np.cos(x))
ax.plot(x, mu, color=c, linewidth=2, label=lab)
ax.fill_between(x, mu - sd, mu + sd, color=c, alpha=0.15)
ax.set_xlabel('Time')
ax.set_ylabel('Score')
ax.set_title('Model Comparison with Confidence Bands')
ax.legend()
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('multi_band.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved multi_band.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
groups = ['Placebo', '10mg', '25mg', '50mg']
means = [0.0, 1.2, 2.8, 3.5]
low = [0.0, 0.3, 0.5, 0.4]
high = [0.0, 0.5, 0.6, 0.8]
fig, ax = plt.subplots(figsize=(7, 5))
x = np.arange(len(groups))
ax.bar(x, means, color=['#aaa','#5ab4d6','#2171b5','#084594'],
alpha=0.85, width=0.5)
ax.errorbar(x, means, yerr=[low, high],
fmt='none', ecolor='black', elinewidth=2, capsize=8, capthick=2)
ax.axhline(0, color='gray', linewidth=0.8, linestyle='--')
ax.set_xticks(x); ax.set_xticklabels(groups)
ax.set_ylabel('Effect Size vs Baseline')
ax.set_title('Clinical Trial: Dose-Response', fontweight='bold')
for xi, m, h in zip(x[1:], means[1:], high[1:]):
ax.text(xi, m + h + 0.05, '*' if m < 3 else '***',
ha='center', fontsize=14, color='darkred')
fig.tight_layout()
fig.savefig('clinical_trial.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved clinical_trial.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(10)
groups = [f'Group {i}' for i in range(1, 7)]
means = np.random.uniform(2, 8, 6)
errors = np.random.uniform(0.3, 1.2, 6)
# TODO: horizontal errorbar plot
# TODO: color by quartile
# TODO: vertical reference line at x=5
# TODO: save 'hbar_errors.png'Compare distributions across groups with boxplot() for quartile summaries and violinplot() for full density shapes. Combine both for richer insights.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
data = [np.random.normal(loc, 1.0, 80) for loc in [2, 3.5, 2.8, 4.2, 3.0]]
labels = ['A', 'B', 'C', 'D', 'E']
fig, ax = plt.subplots(figsize=(8, 5))
bp = ax.boxplot(data, labels=labels, patch_artist=True, notch=True,
medianprops=dict(color='white', linewidth=2))
colors = ['#4c72b0','#dd8452','#55a868','#c44e52','#8172b2']
for patch, color in zip(bp['boxes'], colors):
patch.set_facecolor(color)
patch.set_alpha(0.8)
ax.set_xlabel('Group')
ax.set_ylabel('Value')
ax.set_title('Notched Box Plots by Group')
ax.grid(True, axis='y', alpha=0.3)
fig.tight_layout()
fig.savefig('boxplot.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved boxplot.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
data = [np.concatenate([np.random.normal(0, 1, 60),
np.random.normal(3, 0.5, 20)])
for _ in range(4)]
labels = ['Q1', 'Q2', 'Q3', 'Q4']
fig, ax = plt.subplots(figsize=(8, 5))
parts = ax.violinplot(data, positions=range(1, 5), showmedians=True,
showextrema=True)
for pc in parts['bodies']:
pc.set_facecolor('#4c72b0')
pc.set_alpha(0.7)
ax.boxplot(data, positions=range(1, 5), widths=0.1,
patch_artist=True,
boxprops=dict(facecolor='white', linewidth=1),
medianprops=dict(color='red', linewidth=2),
whiskerprops=dict(linewidth=1),
capprops=dict(linewidth=1),
flierprops=dict(markersize=3))
ax.set_xticks(range(1, 5)); ax.set_xticklabels(labels)
ax.set_title('Violin + Box Plot Overlay')
ax.grid(True, axis='y', alpha=0.3)
fig.tight_layout()
fig.savefig('violin_box.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved violin_box.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(2)
n = 60
months = ['Jan', 'Feb', 'Mar', 'Apr']
treatments = ['Control', 'Treatment']
x_pos = np.array([0, 1, 2, 3])
width = 0.35
fig, ax = plt.subplots(figsize=(9, 5))
for i, (trt, color) in enumerate(zip(treatments, ['#4c72b0','#dd8452'])):
data = [np.random.normal(2 + i * 0.8 + j * 0.3, 0.7, n) for j in range(4)]
bp = ax.boxplot(data, positions=x_pos + (i - 0.5) * width,
widths=width * 0.85, patch_artist=True,
medianprops=dict(color='white', linewidth=2))
for patch in bp['boxes']:
patch.set_facecolor(color); patch.set_alpha(0.75)
ax.set_xticks(x_pos); ax.set_xticklabels(months)
ax.set_xlabel('Month'); ax.set_ylabel('Score')
ax.set_title('Grouped Box Plots: Control vs Treatment')
handles = [plt.Rectangle((0,0),1,1, color=c, alpha=0.75) for c in ['#4c72b0','#dd8452']]
ax.legend(handles, treatments)
ax.grid(True, axis='y', alpha=0.3)
fig.tight_layout()
fig.savefig('grouped_box.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved grouped_box.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
groups = ['Low', 'Mid', 'High']
data = [np.random.normal(m, 0.8, 80) for m in [1.5, 3.0, 4.5]]
colors = ['#5ab4d6', '#f4a261', '#e76f51']
fig, ax = plt.subplots(figsize=(8, 5))
for i, (d, c) in enumerate(zip(data, colors)):
parts = ax.violinplot([d], positions=[i], showmedians=False,
showextrema=False)
for pc in parts['bodies']:
pc.set_facecolor(c); pc.set_alpha(0.6)
# half violin: mask right side
verts = pc.get_paths()[0].vertices
verts[:, 0] = np.clip(verts[:, 0], -np.inf, i)
pc.get_paths()[0].vertices = verts
# jitter
jitter = np.random.uniform(-0.05, 0.05, len(d))
ax.scatter(i + 0.05 + jitter, d, alpha=0.4, s=15, color=c)
ax.hlines(np.median(d), i - 0.3, i + 0.1, colors='black', linewidth=2)
ax.set_xticks(range(3)); ax.set_xticklabels(groups)
ax.set_title('Raincloud Plot (Half Violin + Jitter)')
ax.grid(True, axis='y', alpha=0.3)
fig.tight_layout()
fig.savefig('raincloud.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved raincloud.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(99)
lines = ['L1','L2','L3','L4','L5']
shifts = ['Morning','Afternoon','Night']
colors = ['#2196f3','#ff9800','#9c27b0']
x_pos = np.arange(5)
width = 0.25
fig, ax = plt.subplots(figsize=(11, 5))
for si, (shift, col) in enumerate(zip(shifts, colors)):
data = [np.random.exponential(1 + si * 0.5 + li * 0.2, 50) for li in range(5)]
bp = ax.boxplot(data, positions=x_pos + (si-1)*width, widths=width*0.85,
patch_artist=True, notch=True,
medianprops=dict(color='white', linewidth=2),
flierprops=dict(marker='x', color=col, markersize=5))
for patch in bp['boxes']:
patch.set_facecolor(col); patch.set_alpha(0.75)
ax.axhline(3.0, color='red', linestyle='--', linewidth=1.5, label='Threshold')
ax.set_xticks(x_pos); ax.set_xticklabels(lines)
ax.set_xlabel('Production Line'); ax.set_ylabel('Defects per 100 units')
ax.set_title('Quality Control: Defects by Line & Shift', fontweight='bold')
handles = [plt.Rectangle((0,0),1,1,color=c,alpha=0.75) for c in colors] + [plt.Line2D([0],[0],color='red',linestyle='--')]
ax.legend(handles, shifts + ['Threshold'], ncol=4)
ax.grid(True, axis='y', alpha=0.3)
fig.tight_layout()
fig.savefig('qc_boxplot.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved qc_boxplot.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(5)
bimodal = np.concatenate([np.random.normal(-2,0.5,100), np.random.normal(2,0.5,100)])
skewed = np.random.exponential(1.5, 200)
uniform = np.random.uniform(-3, 3, 200)
heavy = np.random.standard_t(df=2, size=200)
datasets = [bimodal, skewed, uniform, heavy]
titles = ['Bimodal', 'Right-Skewed', 'Uniform', 'Heavy-Tailed']
fig, axes = plt.subplots(2, 2, figsize=(9, 7))
for ax, d, title in zip(axes.flat, datasets, titles):
ax.violinplot([d], showmedians=True, showextrema=True)
# TODO: add mean as diamond marker
# TODO: label the title
pass
fig.suptitle('Distribution Shapes Comparison', fontweight='bold')
fig.tight_layout()
fig.savefig('dist_shapes.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved dist_shapes.png')Use contour() for lines and contourf() for filled regions to display 2D scalar fields, decision boundaries, and topographic data.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = y = np.linspace(-3, 3, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
# Filled contour
cf = ax1.contourf(X, Y, Z, levels=20, cmap='RdBu_r')
fig.colorbar(cf, ax=ax1, label='Z')
ax1.set_title('contourf β filled')
# Line contour with labels
cs = ax2.contour(X, Y, Z, levels=15, cmap='RdBu_r')
ax2.clabel(cs, inline=True, fontsize=8, fmt='%.1f')
ax2.set_title('contour β lines with labels')
for ax in (ax1, ax2):
ax.set_xlabel('x'); ax.set_ylabel('y')
fig.tight_layout()
fig.savefig('contour_basic.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved contour_basic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
np.random.seed(0)
X_cls = np.random.randn(200, 2)
y_cls = ((X_cls[:,0]**2 + X_cls[:,1]**2) < 1.5).astype(int)
xx, yy = np.meshgrid(np.linspace(-3,3,300), np.linspace(-3,3,300))
r = xx**2 + yy**2
zz = (r < 1.5).astype(float)
fig, ax = plt.subplots(figsize=(6, 5))
ax.contourf(xx, yy, zz, alpha=0.3, cmap=ListedColormap(['#ff7f7f','#7fbfff']))
ax.contour(xx, yy, zz, colors='black', linewidths=1.5)
colors_pt = ['#cc0000' if yi else '#0055aa' for yi in y_cls]
ax.scatter(X_cls[:,0], X_cls[:,1], c=colors_pt, s=30, edgecolors='k', linewidths=0.5)
ax.set_title('Circular Decision Boundary')
ax.set_xlabel('Feature 1'); ax.set_ylabel('Feature 2')
fig.tight_layout()
fig.savefig('decision_boundary.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved decision_boundary.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LightSource
x = y = np.linspace(0, 4*np.pi, 300)
X, Y = np.meshgrid(x, y)
Z = np.sin(X/2) * np.cos(Y/3) + 0.5*np.sin(X + Y)
ls = LightSource(azdeg=315, altdeg=45)
hillshade = ls.hillshade(Z, vert_exag=1.5)
fig, ax = plt.subplots(figsize=(8, 6))
ax.imshow(hillshade, cmap='gray', origin='lower', alpha=0.6)
cf = ax.contourf(Z, levels=25, cmap='terrain', alpha=0.7, origin='lower')
cs = ax.contour(Z, levels=10, colors='k', linewidths=0.5, alpha=0.5, origin='lower')
fig.colorbar(cf, ax=ax, label='Elevation')
ax.set_title('Topographic Map with Hillshading')
fig.tight_layout()
fig.savefig('topo_map.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved topo_map.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
np.random.seed(3)
x = np.concatenate([np.random.normal(0,1,150), np.random.normal(3,0.8,100)])
y = np.concatenate([np.random.normal(0,1,150), np.random.normal(2,0.8,100)])
# KDE over a grid
xi = np.linspace(x.min()-1, x.max()+1, 150)
yi = np.linspace(y.min()-1, y.max()+1, 150)
Xi, Yi = np.meshgrid(xi, yi)
k = gaussian_kde(np.vstack([x, y]))
Zi = k(np.vstack([Xi.ravel(), Yi.ravel()])).reshape(Xi.shape)
fig, ax = plt.subplots(figsize=(7, 6))
ax.scatter(x, y, s=15, alpha=0.4, color='steelblue')
cf = ax.contourf(Xi, Yi, Zi, levels=10, cmap='Blues', alpha=0.5)
ax.contour(Xi, Yi, Zi, levels=10, colors='navy', linewidths=0.8, alpha=0.7)
fig.colorbar(cf, ax=ax, label='Density')
ax.set_title('KDE Contour Overlay on Scatter')
fig.tight_layout()
fig.savefig('kde_contour.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved kde_contour.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2, 3, 300)
y = np.linspace(-2.5, 1.5, 300)
X, Y = np.meshgrid(x, y)
Z = (X-1)**2 + 2*(Y+0.5)**2 + 0.5*np.sin(3*X)
# Simulated gradient-descent path
path_x = [-1.5]
path_y = [-2.0]
lr = 0.1
for _ in range(40):
gx = 2*(path_x[-1]-1) + 1.5*np.cos(3*path_x[-1])
gy = 4*(path_y[-1]+0.5)
path_x.append(path_x[-1] - lr*gx)
path_y.append(path_y[-1] - lr*gy)
fig, ax = plt.subplots(figsize=(8, 6))
cf = ax.contourf(X, Y, Z, levels=30, cmap='viridis')
fig.colorbar(cf, ax=ax, label='Loss')
ax.contour(X, Y, Z, levels=15, colors='white', linewidths=0.5, alpha=0.4)
ax.plot(path_x, path_y, 'w-o', markersize=4, linewidth=1.5, label='GD path')
ax.plot(path_x[0], path_y[0], 'rs', markersize=10, label='Start')
ax.plot(path_x[-1], path_y[-1], 'r*', markersize=14, label='End')
ax.set_xlabel('w1'); ax.set_ylabel('w2')
ax.set_title('Loss Landscape & Gradient Descent', fontweight='bold')
ax.legend(facecolor='#222')
fig.tight_layout()
fig.savefig('loss_landscape.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved loss_landscape.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = y = np.linspace(-6, 6, 300)
X, Y = np.meshgrid(x, y)
Z = np.cos(np.sqrt(X**2 + Y**2))
fig, ax = plt.subplots(figsize=(7, 6))
# TODO: contourf with plasma cmap
# TODO: white contour lines, 10 levels
# TODO: colorbar labeled 'Amplitude'
# TODO: red star marker at (0, 0)
# TODO: save 'ripple.png'
plt.close()Use polar projections for directional data, radar charts, and rose diagrams. Access the polar axes with subplot_kw={'projection':'polar'}.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2*np.pi, 300)
r = 1 + 0.5 * np.cos(3*theta)
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw={'projection': 'polar'})
ax.plot(theta, r, color='steelblue', linewidth=2)
ax.fill(theta, r, color='steelblue', alpha=0.2)
ax.set_title('Rose Curve: 1 + 0.5Β·cos(3ΞΈ)', pad=20)
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('polar_rose.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved polar_rose.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(5)
n_dirs = 16
theta_bars = np.linspace(0, 2*np.pi, n_dirs, endpoint=False)
radii = np.abs(np.random.randn(n_dirs)) * 10 + 5
width = 2*np.pi / n_dirs
fig, ax = plt.subplots(figsize=(7, 7), subplot_kw={'projection': 'polar'})
bars = ax.bar(theta_bars, radii, width=width, bottom=0,
color=plt.cm.hsv(theta_bars / (2*np.pi)), alpha=0.8, edgecolor='white')
ax.set_theta_direction(-1)
ax.set_theta_zero_location('N')
dirs = ['N','NNE','NE','ENE','E','ESE','SE','SSE',
'S','SSW','SW','WSW','W','WNW','NW','NNW']
ax.set_xticks(theta_bars)
ax.set_xticklabels(dirs, fontsize=8)
ax.set_title('Wind Rose Diagram', pad=20, fontweight='bold')
fig.tight_layout()
fig.savefig('wind_rose.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved wind_rose.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
categories = ['Speed','Strength','Defense','Agility','Intelligence','Stamina']
N = len(categories)
angles = np.linspace(0, 2*np.pi, N, endpoint=False).tolist()
angles += angles[:1] # close the loop
player_a = [8, 6, 7, 9, 5, 7]
player_b = [5, 9, 8, 4, 7, 6]
for v in (player_a, player_b):
v.append(v[0])
fig, ax = plt.subplots(figsize=(7, 7), subplot_kw={'projection': 'polar'})
ax.plot(angles, player_a, 'o-', color='steelblue', linewidth=2, label='Player A')
ax.fill(angles, player_a, color='steelblue', alpha=0.2)
ax.plot(angles, player_b, 's-', color='tomato', linewidth=2, label='Player B')
ax.fill(angles, player_b, color='tomato', alpha=0.2)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(categories, fontsize=10)
ax.set_ylim(0, 10)
ax.set_title('Player Stats Radar Chart', pad=20, fontweight='bold')
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1))
fig.tight_layout()
fig.savefig('radar.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved radar.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
n = 200
theta = np.random.uniform(0, 2*np.pi, n)
r = np.random.exponential(2, n)
c = theta / (2*np.pi)
fig, ax = plt.subplots(figsize=(7, 7), subplot_kw={'projection': 'polar'})
sc = ax.scatter(theta, r, c=c, cmap='hsv', s=40, alpha=0.7)
fig.colorbar(sc, ax=ax, label='Direction (normalized)', pad=0.1)
ax.set_title('Polar Scatter β Exponential Radii', pad=20)
fig.tight_layout()
fig.savefig('polar_scatter.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved polar_scatter.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(21)
n_dirs = 12
months = ['Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec']
theta_bars = np.linspace(0, 2*np.pi, n_dirs, endpoint=False)
sales = np.abs(np.random.randn(n_dirs)) * 50 + 80
width = 2*np.pi / n_dirs
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
norm = plt.Normalize(sales.min(), sales.max())
colors = plt.cm.viridis(norm(sales))
bars = ax.bar(theta_bars, sales, width=width, bottom=5,
color=colors, alpha=0.85, edgecolor='white')
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_xticks(theta_bars); ax.set_xticklabels(months, fontsize=9)
ax.set_title('Monthly Sales by Direction', pad=20, fontweight='bold')
# annotate top 3
top3 = np.argsort(sales)[-3:]
for idx in top3:
ax.annotate(f'{sales[idx]:.0f}',
xy=(theta_bars[idx], sales[idx]+8),
ha='center', fontsize=9, color='gold', fontweight='bold')
sm = plt.cm.ScalarMappable(cmap='viridis', norm=norm)
fig.colorbar(sm, ax=ax, label='Sales Volume', pad=0.1)
fig.tight_layout()
fig.savefig('sales_polar.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved sales_polar.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
categories = ['Communication','Analysis','Design','Coding',
'Testing','DevOps','Leadership','Creativity']
N = len(categories)
np.random.seed(42)
eng1 = np.random.randint(4, 10, N).tolist()
eng2 = np.random.randint(3, 10, N).tolist()
angles = np.linspace(0, 2*np.pi, N, endpoint=False).tolist()
# TODO: close the polygon (append first element to angles, eng1, eng2)
# TODO: polar subplot
# TODO: plot and fill both engineers
# TODO: set tick labels to categories
# TODO: save 'skills_radar.png'Show part-to-whole relationships over categories or time with stacked bar charts and area plots using stackplot().
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
categories = ['Q1','Q2','Q3','Q4']
product_a = [120, 145, 160, 180]
product_b = [90, 110, 95, 130]
product_c = [60, 75, 80, 95]
x = np.arange(len(categories))
colors = ['#4c72b0','#dd8452','#55a868']
fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(x, product_a, label='Product A', color=colors[0], width=0.5)
ax.bar(x, product_b, bottom=product_a, label='Product B', color=colors[1], width=0.5)
bottom_c = [a+b for a,b in zip(product_a, product_b)]
ax.bar(x, product_c, bottom=bottom_c, label='Product C', color=colors[2], width=0.5)
ax.set_xticks(x); ax.set_xticklabels(categories)
ax.set_ylabel('Revenue ($K)')
ax.set_title('Quarterly Revenue by Product β Stacked')
ax.legend(loc='upper left')
ax.grid(True, axis='y', alpha=0.3)
fig.tight_layout()
fig.savefig('stacked_bar.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved stacked_bar.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
categories = ['North','South','East','West','Central']
a = np.array([30, 45, 20, 60, 35])
b = np.array([50, 30, 55, 25, 40])
c = np.array([20, 25, 25, 15, 25])
total = a + b + c
a_p, b_p, c_p = a/total*100, b/total*100, c/total*100
x = np.arange(len(categories))
fig, ax = plt.subplots(figsize=(9, 5))
ax.bar(x, a_p, label='Tier 1', color='#4c72b0', width=0.55)
ax.bar(x, b_p, bottom=a_p, label='Tier 2', color='#dd8452', width=0.55)
ax.bar(x, c_p, bottom=a_p+b_p, label='Tier 3', color='#55a868', width=0.55)
for xi, (ap, bp, cp) in enumerate(zip(a_p, b_p, c_p)):
ax.text(xi, ap/2, f'{ap:.0f}%', ha='center', va='center', fontsize=9, color='white', fontweight='bold')
ax.text(xi, ap+bp/2, f'{bp:.0f}%', ha='center', va='center', fontsize=9, color='white', fontweight='bold')
ax.text(xi, ap+bp+cp/2, f'{cp:.0f}%', ha='center', va='center', fontsize=9, fontweight='bold')
ax.set_xticks(x); ax.set_xticklabels(categories)
ax.set_ylabel('Percentage'); ax.set_ylim(0,100)
ax.set_title('100% Stacked Bar β Market Share by Region')
ax.legend(loc='upper right')
fig.tight_layout()
fig.savefig('stacked_100.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved stacked_100.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
months = np.arange(1, 13)
direct = np.array([200,210,225,240,260,280,270,290,310,295,320,350])
organic = np.array([80, 95, 100,110,125,140,135,150,160,155,175,190])
referral = np.array([40, 45, 50, 55, 60, 65, 70, 68, 75, 72, 80, 90])
labels_s = ['Direct','Organic','Referral']
colors_s = ['#4c72b0','#55a868','#dd8452']
fig, ax = plt.subplots(figsize=(9, 5))
ax.stackplot(months, direct, organic, referral,
labels=labels_s, colors=colors_s, alpha=0.8)
ax.set_xlabel('Month'); ax.set_ylabel('Sessions (K)')
ax.set_title('Website Traffic by Source β Stacked Area')
ax.set_xticks(months)
ax.set_xticklabels(['Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec'], rotation=30)
ax.legend(loc='upper left'); ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('stackplot.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved stackplot.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
x = np.linspace(0, 10, 100)
n_series = 5
ys = [np.abs(np.random.randn(100)).cumsum() * 0.3 + np.random.uniform(1,3)
for _ in range(n_series)]
baseline = -np.array(ys).sum(axis=0) / 2 # center
fig, ax = plt.subplots(figsize=(10, 5))
cmap = plt.cm.Set2
ax.stackplot(x, *ys, baseline='sym',
colors=[cmap(i/n_series) for i in range(n_series)],
alpha=0.85)
ax.set_title('Stream Graph (Symmetric Baseline)')
ax.set_xlabel('Time'); ax.set_ylabel('Magnitude')
ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('streamgraph.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved streamgraph.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(15)
months = np.arange(12)
solar = 20 + 15*np.sin(np.linspace(0, np.pi, 12)) + np.random.randn(12)*2
wind = 18 + 8*np.cos(np.linspace(0, 2*np.pi, 12)) + np.random.randn(12)*2
hydro = np.full(12, 22.0) + np.random.randn(12)
gas = 25 - 5*np.sin(np.linspace(0, np.pi, 12)) + np.random.randn(12)
coal = 100 - solar - wind - hydro - gas
sources = np.vstack([solar, wind, hydro, gas, coal])
sources = np.clip(sources, 1, None)
pct = sources / sources.sum(axis=0) * 100
fig, ax = plt.subplots(figsize=(10, 5))
mnames = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
ax.stackplot(months, *pct,
labels=['Solar','Wind','Hydro','Gas','Coal'],
colors=['#f9c74f','#90be6d','#43aa8b','#f3722c','#555'],
alpha=0.9)
ren = pct[:3].sum(axis=0)
best = ren.argmax()
ax.annotate(f'Peak renewable
{ren[best]:.1f}%',
xy=(best, 50), xytext=(best+1, 70),
arrowprops=dict(arrowstyle='->', color='white'),
fontsize=9, color='white',
bbox=dict(boxstyle='round', fc='#333'))
ax.set_xticks(months); ax.set_xticklabels(mnames)
ax.set_ylim(0,100); ax.set_ylabel('Share (%)')
ax.set_title('Energy Mix by Month', fontweight='bold')
ax.legend(loc='lower right', ncol=5, fontsize=8)
fig.tight_layout()
fig.savefig('energy_mix.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved energy_mix.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
weeks = ['Wk1','Wk2','Wk3','Wk4','Wk5']
rent = np.array([800, 800, 800, 800, 800])
food = np.array([200, 220, 180, 240, 210])
transport = np.array([80, 90, 75, 85, 95])
entertainment = np.array([100, 60, 120, 80, 50])
savings = np.array([150, 200, 180, 130, 220])
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 8), sharex=True)
x = np.arange(len(weeks))
# TODO: stacked bar on ax1
# TODO: 100% stacked bar on ax2
# TODO: legend, labels, title
fig.tight_layout()
fig.savefig('budget_stacked.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved budget_stacked.png')Use step() and drawstyle='steps-*' for discrete/piecewise data, stairs() for histograms, and eventplot() for spike-train and event sequence data.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10)
y = np.array([2, 3, 3, 5, 4, 6, 5, 7, 6, 8])
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
for ax, where, title in zip(axes,
['pre','mid','post'],
['steps-pre','steps-mid','steps-post']):
ax.step(x, y, where=where, color='steelblue', linewidth=2)
ax.scatter(x, y, color='steelblue', zorder=5)
ax.set_title(title); ax.grid(True, alpha=0.3)
fig.suptitle('Step Plot Variants', fontweight='bold')
fig.tight_layout()
fig.savefig('step_variants.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved step_variants.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
data = np.sort(np.random.normal(5, 1.5, 200))
ecdf_y = np.arange(1, len(data)+1) / len(data)
fig, ax = plt.subplots(figsize=(8, 4))
ax.step(data, ecdf_y, where='post', color='steelblue', linewidth=2, label='ECDF')
ax.axhline(0.5, color='red', linestyle='--', linewidth=1, label='Median')
ax.axvline(np.median(data), color='red', linestyle='--', linewidth=1)
ax.set_xlabel('Value'); ax.set_ylabel('Cumulative Probability')
ax.set_title('Empirical CDF (step-post)')
ax.legend(); ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('ecdf_step.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved ecdf_step.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
n_neurons = 5
spike_trains = [np.sort(np.random.uniform(0, 1, np.random.randint(10, 30)))
for _ in range(n_neurons)]
colors_ev = plt.cm.tab10(np.linspace(0, 0.5, n_neurons))
fig, ax = plt.subplots(figsize=(10, 4))
ax.eventplot(spike_trains, colors=colors_ev,
lineoffsets=range(1, n_neurons+1),
linelengths=0.7, linewidths=1.5)
ax.set_xlabel('Time (s)')
ax.set_yticks(range(1, n_neurons+1))
ax.set_yticklabels([f'Neuron {i}' for i in range(1, n_neurons+1)])
ax.set_title('Neural Spike Train Raster Plot')
ax.set_xlim(0, 1)
ax.grid(True, axis='x', alpha=0.3)
fig.tight_layout()
fig.savefig('spike_raster.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved spike_raster.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(2)
t = np.arange(0, 50)
signal = np.where(np.random.rand(50) > 0.6, 1, 0)
signal[10:15] = 1; signal[30:38] = 1 # force some pulses
fig, ax = plt.subplots(figsize=(10, 3))
ax.step(t, signal, where='post', color='steelblue', linewidth=1.5)
ax.fill_between(t, signal, step='post', alpha=0.2, color='steelblue')
ax.set_ylim(-0.1, 1.4)
ax.set_xlabel('Time (ms)'); ax.set_ylabel('State')
ax.set_title('Digital Signal β Step Fill')
ax.set_yticks([0, 1]); ax.set_yticklabels(['OFF', 'ON'])
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('digital_signal.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved digital_signal.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(8)
services = ['API','DB','Cache','Auth','Queue']
events = [np.sort(np.random.uniform(0, 60, np.random.randint(8, 25)))
for _ in services]
colors_svc = ['#4c72b0','#dd8452','#55a868','#c44e52','#9467bd']
fig, ax = plt.subplots(figsize=(11, 4))
ax.eventplot(events, colors=colors_svc,
lineoffsets=range(1, len(services)+1),
linelengths=0.6, linewidths=2)
ax.axvspan(20, 35, color='red', alpha=0.1, label='Incident window')
ax.axvline(20, color='red', linestyle='--', linewidth=1)
ax.axvline(35, color='red', linestyle='--', linewidth=1)
ax.set_xlabel('Time (s)'); ax.set_xlim(0, 60)
ax.set_yticks(range(1, len(services)+1)); ax.set_yticklabels(services)
ax.set_title('Service Event Log β 60s Window', fontweight='bold')
ax.legend(loc='upper right')
ax.grid(True, axis='x', alpha=0.3)
fig.tight_layout()
fig.savefig('event_log.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved event_log.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(11)
t = np.arange(80)
state = np.zeros(80, dtype=int)
for i in range(1, 80):
if np.random.rand() < 0.1:
state[i] = np.random.choice([0, 1, 2])
else:
state[i] = state[i-1]
fig, ax = plt.subplots(figsize=(11, 3))
# TODO: step plot with post
# TODO: fill_between for state=0 (blue), 1 (green), 2 (red)
# TODO: add legend, labels, title
# TODO: save 'state_machine.png'
plt.close()Use set_xscale/set_yscale with 'log', 'symlog', or 'logit' to handle data spanning many orders of magnitude.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.logspace(0, 4, 100)
y_power = 2.5 * x**1.7
noise = np.random.lognormal(0, 0.1, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
ax1.plot(x, y_power * noise, 'o', markersize=4, alpha=0.6, color='steelblue')
ax1.set_title('Linear Scale'); ax1.set_xlabel('x'); ax1.set_ylabel('y')
ax1.grid(True, alpha=0.3)
ax2.loglog(x, y_power * noise, 'o', markersize=4, alpha=0.6, color='steelblue')
ax2.loglog(x, y_power, 'r--', linewidth=2, label=r'y = 2.5 x^{1.7}')
ax2.set_title('Log-Log Scale'); ax2.set_xlabel('x'); ax2.set_ylabel('y')
ax2.legend(); ax2.grid(True, which='both', alpha=0.3)
fig.suptitle('Power-Law: Linear vs Log-Log', fontweight='bold')
fig.tight_layout()
fig.savefig('loglog.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved loglog.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0, 10, 200)
decay_fast = np.exp(-0.8 * t)
decay_slow = np.exp(-0.2 * t)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
for ax, scale, title in [(ax1, 'linear', 'Linear Y'), (ax2, 'log', 'Log Y')]:
ax.plot(t, decay_fast, label='Fast (k=0.8)', linewidth=2)
ax.plot(t, decay_slow, label='Slow (k=0.2)', linewidth=2, linestyle='--')
ax.set_yscale(scale)
ax.set_xlabel('Time'); ax.set_ylabel('Concentration')
ax.set_title(title); ax.legend(); ax.grid(True, which='both', alpha=0.3)
fig.suptitle('Exponential Decay on Linear vs Semilog', fontweight='bold')
fig.tight_layout()
fig.savefig('semilog.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved semilog.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
x = np.linspace(-1000, 1000, 500)
y = x + np.random.randn(500) * 50
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
ax1.scatter(x, y, s=8, alpha=0.5, color='steelblue')
ax1.set_title('Linear Scale')
ax2.scatter(x, y, s=8, alpha=0.5, color='steelblue')
ax2.set_xscale('symlog', linthresh=10)
ax2.set_yscale('symlog', linthresh=10)
ax2.set_title('Symlog Scale (linthresh=10)')
for ax in (ax1, ax2):
ax.axhline(0, color='gray', linewidth=0.8)
ax.axvline(0, color='gray', linewidth=0.8)
ax.grid(True, which='both', alpha=0.3)
ax.set_xlabel('X'); ax.set_ylabel('Y')
fig.tight_layout()
fig.savefig('symlog.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved symlog.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as ticker
f = np.logspace(1, 5, 300) # 10 Hz to 100 kHz
gain_db = -20 * np.log10(1 + (f/1000)**2) # simple LP filter
fig, ax = plt.subplots(figsize=(9, 4))
ax.semilogx(f, gain_db, color='steelblue', linewidth=2)
ax.axhline(-3, color='red', linestyle='--', linewidth=1, label='-3 dB cutoff')
ax.axvline(1000, color='red', linestyle='--', linewidth=1)
ax.set_xlabel('Frequency (Hz)')
ax.set_ylabel('Gain (dB)')
ax.set_title('Bode Plot β Low-Pass Filter')
ax.grid(True, which='both', alpha=0.3)
ax.xaxis.set_major_formatter(ticker.FuncFormatter(
lambda x, _: f'{x/1000:.0f}k' if x >= 1000 else f'{x:.0f}'))
ax.legend()
fig.tight_layout()
fig.savefig('bode.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved bode.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
mu, sigma = 5.5, 0.8 # lognormal params
data = np.random.lognormal(mu, sigma, 10000) # ms
p95, p99 = np.percentile(data, [95, 99])
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
bins = 80
ax1.hist(data, bins=bins, color='steelblue', alpha=0.7, density=True)
for p, lab, col in [(p95,'p95','orange'),(p99,'p99','red')]:
ax1.axvline(p, color=col, linestyle='--', linewidth=2, label=f'{lab}: {p:.0f}ms')
ax1.set_title('Linear Scale'); ax1.legend(); ax1.grid(True, alpha=0.3)
ax2.hist(data, bins=np.logspace(np.log10(data.min()), np.log10(data.max()), bins),
color='steelblue', alpha=0.7, density=True)
x_pdf = np.logspace(np.log10(data.min()), np.log10(data.max()), 300)
pdf = (1/(x_pdf * sigma * np.sqrt(2*np.pi))) * np.exp(-(np.log(x_pdf)-mu)**2/(2*sigma**2))
ax2.plot(x_pdf, pdf, 'r-', linewidth=2, label='Lognormal PDF')
ax2.set_xscale('log')
for p, lab, col in [(p95,'p95','orange'),(p99,'p99','red')]:
ax2.axvline(p, color=col, linestyle='--', linewidth=2)
ax2.set_title('Log-X Scale'); ax2.legend(); ax2.grid(True, which='both', alpha=0.3)
for ax in (ax1, ax2):
ax.set_xlabel('Response Time (ms)'); ax.set_ylabel('Density')
fig.suptitle('Server Response Time Distribution', fontweight='bold')
fig.tight_layout()
fig.savefig('response_time.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved response_time.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(6)
x = np.logspace(0, 4, 200)
y = 3 * x**(-1.5) * np.random.lognormal(0, 0.15, 200)
fig, axes = plt.subplots(1, 3, figsize=(13, 4))
titles = ['Linear', 'Log-Log', 'Symlog']
scales = [('linear','linear'), ('log','log'), ('symlog','symlog')]
for ax, title, (xs, ys) in zip(axes, titles, scales):
ax.scatter(x, y, s=10, alpha=0.5)
ax.set_xscale(xs); ax.set_yscale(ys)
ax.set_title(title); ax.grid(True, which='both', alpha=0.3)
# TODO: on log-log, add fitted power-law line using np.polyfit
fig.suptitle('Power Law on Three Scales', fontweight='bold')
fig.tight_layout()
fig.savefig('powerlaw_scales.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved powerlaw_scales.png')Go beyond plt.subplots() using GridSpec for unequal column/row spans, subplot_mosaic() for named panels, and add_axes() for insets.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
np.random.seed(0)
fig = plt.figure(figsize=(11, 5))
gs = GridSpec(2, 3, figure=fig, width_ratios=[2,1,1], hspace=0.4, wspace=0.3)
ax_main = fig.add_subplot(gs[:, 0]) # spans both rows, col 0
ax_tr = fig.add_subplot(gs[0, 1])
ax_br = fig.add_subplot(gs[1, 1])
ax_tall = fig.add_subplot(gs[:, 2])
x = np.random.randn(200); y = np.random.randn(200)
ax_main.scatter(x, y, s=15, alpha=0.5, color='steelblue')
ax_main.set_title('Main Scatter')
ax_tr.hist(x, bins=20, color='steelblue', alpha=0.7); ax_tr.set_title('X dist')
ax_br.hist(y, bins=20, orientation='horizontal', color='tomato', alpha=0.7)
ax_br.set_title('Y dist')
ax_tall.boxplot([x, y], labels=['X','Y'], patch_artist=True)
ax_tall.set_title('Box')
fig.suptitle('GridSpec Complex Layout', fontweight='bold')
fig.savefig('gridspec.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved gridspec.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
layout = [['A', 'A', 'B'],
['C', 'D', 'B']]
fig, axd = plt.subplot_mosaic(layout, figsize=(11, 6),
gridspec_kw={'hspace':0.35,'wspace':0.3})
x = np.linspace(0, 10, 100)
axd['A'].plot(x, np.sin(x), color='steelblue'); axd['A'].set_title('A: Wide Line')
axd['B'].imshow(np.random.rand(20,20), cmap='viridis', aspect='auto'); axd['B'].set_title('B: Tall Image')
axd['C'].bar(['x','y','z'], [3,7,5], color=['#4c72b0','#dd8452','#55a868']); axd['C'].set_title('C: Bar')
axd['D'].scatter(*np.random.randn(2,50), s=20, alpha=0.6); axd['D'].set_title('D: Scatter')
fig.suptitle('subplot_mosaic β Named Panels', fontweight='bold')
fig.savefig('mosaic.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved mosaic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec
np.random.seed(2)
fig = plt.figure(figsize=(11, 6))
outer = GridSpec(1, 2, figure=fig, wspace=0.3)
# Left: single scatter
ax_left = fig.add_subplot(outer[0])
ax_left.scatter(*np.random.randn(2, 80), s=20, alpha=0.5)
ax_left.set_title('Left Panel')
# Right: 2x2 subgrid
inner = GridSpecFromSubplotSpec(2, 2, subplot_spec=outer[1], hspace=0.4, wspace=0.3)
for i in range(4):
ax = fig.add_subplot(inner[i])
ax.plot(np.random.randn(30).cumsum(), linewidth=1.5)
ax.set_title(f'R{i+1}', fontsize=9)
fig.suptitle('Nested GridSpec', fontweight='bold')
fig.savefig('nested_gs.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved nested_gs.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
x = np.linspace(0, 10, 300)
y = np.sin(x) * np.exp(-0.2*x) + np.random.randn(300)*0.05
fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(x, y, color='steelblue', linewidth=1.5)
ax.set_xlabel('x'); ax.set_ylabel('y')
ax.set_title('Main Plot with Inset Zoom')
# Inset: zoom [0, 1.5]
ax_inset = ax.inset_axes([0.55, 0.55, 0.42, 0.38])
ax_inset.plot(x, y, color='steelblue', linewidth=1.5)
ax_inset.set_xlim(0, 1.5); ax_inset.set_ylim(-0.1, 1.05)
ax_inset.set_title('Zoom [0,1.5]', fontsize=8)
ax_inset.tick_params(labelsize=7)
ax.indicate_inset_zoom(ax_inset, edgecolor='black')
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('inset_axis.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved inset_axis.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
np.random.seed(42)
fig = plt.figure(figsize=(13, 5))
gs = GridSpec(2, 2, figure=fig, width_ratios=[1.8, 1], hspace=0.4, wspace=0.35)
ax_curve = fig.add_subplot(gs[:, 0])
ax_cm = fig.add_subplot(gs[0, 1])
ax_roc = fig.add_subplot(gs[1, 1])
# Training curves
epochs = np.arange(1, 31)
for name, color, offset in [('CNN','#4c72b0',0), ('RNN','#dd8452',0.3), ('MLP','#55a868',0.5)]:
loss = 2.5*np.exp(-0.15*epochs) + offset*np.exp(-0.1*epochs) + np.random.randn(30)*0.04
ax_curve.plot(epochs, loss, color=color, linewidth=2, label=name)
ax_curve.set_xlabel('Epoch'); ax_curve.set_ylabel('Loss')
ax_curve.set_title('Training Loss'); ax_curve.legend(); ax_curve.grid(True, alpha=0.3)
# Confusion matrix
cm = np.array([[45,5,2],[3,38,4],[1,2,50]])
im = ax_cm.imshow(cm, cmap='Blues')
for i in range(3):
for j in range(3):
ax_cm.text(j, i, cm[i,j], ha='center', va='center',
color='white' if cm[i,j] > 30 else 'black', fontsize=10)
ax_cm.set_title('Confusion Matrix', fontsize=9)
# ROC
fpr = np.linspace(0, 1, 100)
tpr = np.sqrt(fpr) * 0.92
ax_roc.plot(fpr, tpr, color='steelblue', linewidth=2, label='AUC=0.92')
ax_roc.plot([0,1],[0,1],'k--',linewidth=0.8)
ax_roc.set_xlabel('FPR', fontsize=8); ax_roc.set_ylabel('TPR', fontsize=8)
ax_roc.set_title('ROC Curve', fontsize=9); ax_roc.legend(fontsize=8)
fig.suptitle('ML Model Comparison Dashboard', fontweight='bold')
fig.savefig('ml_dashboard.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved ml_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(12, 8))
gs = GridSpec(3, 3, figure=fig, hspace=0.4, wspace=0.3)
x = np.linspace(0, 2*np.pi, 200)
# Row 0: spans 3 cols β title area
ax_title = fig.add_subplot(gs[0, :])
ax_title.text(0.5, 0.5, 'GridSpec Practice Dashboard', ha='center', va='center',
fontsize=14, fontweight='bold', transform=ax_title.transAxes)
ax_title.axis('off')
# TODO: Row 1: three plots (sin, cos, tan clipped to [-5,5])
# TODO: Row 2: wide bar chart spanning all 3 cols
# TODO: save 'gridspec_practice.png'
plt.close()Use hexbin() for large scatter datasets, hist2d() for rectangular binning, and KDE-based density coloring to visualize joint distributions.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
n = 5000
x = np.random.normal(0, 1.5, n)
y = 0.6*x + np.random.normal(0, 1, n)
fig, ax = plt.subplots(figsize=(7, 5))
hb = ax.hexbin(x, y, gridsize=40, cmap='YlOrRd', mincnt=1)
cb = fig.colorbar(hb, ax=ax, label='Count')
ax.set_xlabel('X'); ax.set_ylabel('Y')
ax.set_title('Hexbin β 5000 Points')
fig.tight_layout()
fig.savefig('hexbin.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved hexbin.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
n = 3000
x = np.concatenate([np.random.normal(-2, 0.8, n//2), np.random.normal(2, 0.8, n//2)])
y = np.concatenate([np.random.normal(-1, 1.0, n//2), np.random.normal(1, 1.0, n//2)])
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
h, xedges, yedges, img = ax1.hist2d(x, y, bins=40, cmap='Blues')
fig.colorbar(img, ax=ax1, label='Count')
ax1.set_title('hist2d')
h2, xe, ye, img2 = ax2.hist2d(x, y, bins=40, cmap='Blues',
norm=plt.matplotlib.colors.LogNorm())
fig.colorbar(img2, ax=ax2, label='Log Count')
ax2.set_title('hist2d (log scale)')
for ax in (ax1, ax2):
ax.set_xlabel('X'); ax.set_ylabel('Y')
fig.tight_layout()
fig.savefig('hist2d.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved hist2d.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
np.random.seed(2)
n = 2000
x = np.random.multivariate_normal([0,0], [[1,0.7],[0.7,1]], n)[:,0]
y = np.random.multivariate_normal([0,0], [[1,0.7],[0.7,1]], n)[:,1]
xy = np.vstack([x, y])
kde = gaussian_kde(xy)
density = kde(xy)
idx = density.argsort()
fig, ax = plt.subplots(figsize=(7, 6))
sc = ax.scatter(x[idx], y[idx], c=density[idx], cmap='inferno', s=10, alpha=0.8)
fig.colorbar(sc, ax=ax, label='Density')
ax.set_xlabel('X'); ax.set_ylabel('Y')
ax.set_title('Scatter Colored by KDE Density')
fig.tight_layout()
fig.savefig('kde_scatter.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved kde_scatter.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
np.random.seed(3)
n = 1000
x = np.random.normal(0, 1, n)
y = x * 0.8 + np.random.normal(0, 0.6, n)
fig = plt.figure(figsize=(8, 8))
gs = GridSpec(2, 2, width_ratios=[4,1], height_ratios=[1,4],
hspace=0.05, wspace=0.05)
ax_main = fig.add_subplot(gs[1, 0])
ax_top = fig.add_subplot(gs[0, 0], sharex=ax_main)
ax_side = fig.add_subplot(gs[1, 1], sharey=ax_main)
ax_main.hexbin(x, y, gridsize=35, cmap='Blues', mincnt=1)
ax_top.hist(x, bins=40, color='steelblue', alpha=0.7)
ax_side.hist(y, bins=40, orientation='horizontal', color='tomato', alpha=0.7)
plt.setp(ax_top.get_xticklabels(), visible=False)
plt.setp(ax_side.get_yticklabels(), visible=False)
ax_main.set_xlabel('X'); ax_main.set_ylabel('Y')
ax_top.set_title('Hexbin with Marginal Distributions', fontweight='bold')
fig.savefig('marginal.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved marginal.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
np.random.seed(55)
n = 20000
basket = np.random.lognormal(1.5, 0.6, n)
revenue = basket * np.random.uniform(15, 80, n) + np.random.normal(0, 20, n)
revenue = np.clip(revenue, 1, None)
fig = plt.figure(figsize=(9, 9))
gs = GridSpec(2, 2, width_ratios=[4,1], height_ratios=[1,4],
hspace=0.05, wspace=0.05)
ax = fig.add_subplot(gs[1,0])
ax_top = fig.add_subplot(gs[0,0], sharex=ax)
ax_side = fig.add_subplot(gs[1,1], sharey=ax)
hb = ax.hexbin(basket, revenue, gridsize=50, cmap='YlOrRd', mincnt=1,
norm=plt.matplotlib.colors.LogNorm())
fig.colorbar(hb, ax=ax, label='Log Count')
ax_top.hist(basket, bins=50, color='#f4a261', alpha=0.8)
ax_side.hist(revenue, bins=50, orientation='horizontal', color='#e76f51', alpha=0.8)
plt.setp(ax_top.get_xticklabels(), visible=False)
plt.setp(ax_side.get_yticklabels(), visible=False)
ax.set_xlabel('Basket Size (items)'); ax.set_ylabel('Revenue ($)')
ax.annotate('Peak density', xy=(5, 200), xytext=(12, 500),
arrowprops=dict(arrowstyle='->', color='black'),
fontsize=9, fontweight='bold')
ax_top.set_title('Customer Purchase Patterns', fontweight='bold')
fig.savefig('purchase_density.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved purchase_density.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
np.random.seed(7)
centers = [(0,0), (3,3), (-2,3)]
n_each = 1000
pts = np.vstack([np.random.multivariate_normal(c, np.eye(2), n_each) for c in centers])
x, y = pts[:,0], pts[:,1]
fig, ax = plt.subplots(figsize=(7, 6))
# TODO: hexbin with plasma cmap
# TODO: KDE contour overlay
# TODO: colorbar, axis labels
# TODO: save 'mixture_density.png'
plt.close()Draw custom geometric shapes with matplotlib.patches: Rectangle, Circle, Ellipse, Polygon, FancyArrow, and Arc for annotations and diagrams.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_xlim(0, 10); ax.set_ylim(0, 8)
ax.set_aspect('equal')
rect = mpatches.Rectangle((1, 1), 2.5, 1.5, linewidth=2,
edgecolor='steelblue', facecolor='lightblue', alpha=0.8)
circ = mpatches.Circle((6, 4), radius=1.5, linewidth=2,
edgecolor='tomato', facecolor='lightsalmon', alpha=0.8)
ellip = mpatches.Ellipse((4, 6), width=3, height=1.2, angle=30,
linewidth=2, edgecolor='seagreen', facecolor='lightgreen', alpha=0.8)
for patch in [rect, circ, ellip]:
ax.add_patch(patch)
ax.text(2.25, 1.75, 'Rectangle', ha='center', fontsize=9)
ax.text(6, 4, 'Circle', ha='center', fontsize=9)
ax.text(4, 6, 'Ellipse', ha='center', fontsize=9)
ax.set_title('Basic Patch Artists')
ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('patches_basic.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved patches_basic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_xlim(0, 10); ax.set_ylim(0, 8)
ax.set_aspect('equal')
# Star polygon
n = 5
outer = np.array([[np.cos(2*np.pi*i/n - np.pi/2), np.sin(2*np.pi*i/n - np.pi/2)]
for i in range(n)]) * 2.0 + [3, 4]
inner = np.array([[np.cos(2*np.pi*i/n + np.pi/n - np.pi/2),
np.sin(2*np.pi*i/n + np.pi/n - np.pi/2)]
for i in range(n)]) * 0.8 + [3, 4]
verts = np.empty((2*n, 2))
verts[0::2] = outer; verts[1::2] = inner
star = mpatches.Polygon(verts, closed=True, facecolor='gold', edgecolor='orange', linewidth=2)
ax.add_patch(star)
arrow = mpatches.FancyArrow(5.5, 4, 2, 0, width=0.3,
head_width=0.7, head_length=0.5,
facecolor='steelblue', edgecolor='navy')
ax.add_patch(arrow)
arc = mpatches.Arc((8.5, 2), 2, 2, angle=0, theta1=30, theta2=270,
color='tomato', linewidth=2.5)
ax.add_patch(arc)
ax.set_title('Polygon, FancyArrow, Arc')
ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('patches_advanced.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved patches_advanced.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(9, 5))
np.random.seed(0)
x = np.linspace(0, 10, 100)
y = np.sin(x) + np.random.randn(100)*0.1
ax.plot(x, y, color='steelblue', linewidth=2)
# Highlight a region
highlight = mpatches.FancyBboxPatch((3.0, -0.3), 2.0, 0.6,
boxstyle='round,pad=0.1', linewidth=2,
edgecolor='gold', facecolor='yellow', alpha=0.3)
ax.add_patch(highlight)
ax.annotate('Peak region', xy=(4, 0.8), xytext=(6.5, 1.3),
arrowprops=dict(arrowstyle='->', color='darkred', lw=2),
fontsize=11, color='darkred', fontweight='bold',
bbox=dict(boxstyle='round,pad=0.3', facecolor='lightyellow', edgecolor='gold'))
ax.set_title('Annotations with FancyBboxPatch')
ax.set_xlabel('x'); ax.set_ylabel('y')
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('fancy_annotate.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved fancy_annotate.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(11, 4))
ax.set_xlim(0, 11); ax.set_ylim(0, 4)
ax.set_aspect('equal'); ax.axis('off')
boxes = [
(0.5, 1.5, 'Data
Ingestion', '#4c72b0'),
(3.0, 1.5, 'Clean &
Transform', '#dd8452'),
(5.5, 1.5, 'Feature
Engineering', '#55a868'),
(8.0, 1.5, 'Model
Training', '#c44e52'),
]
for x, y, label, color in boxes:
box = mpatches.FancyBboxPatch((x, y), 2, 1,
boxstyle='round,pad=0.1', facecolor=color, edgecolor='white',
linewidth=2, alpha=0.9)
ax.add_patch(box)
ax.text(x+1, y+0.5, label, ha='center', va='center',
color='white', fontsize=9, fontweight='bold')
for i in range(len(boxes)-1):
x_start = boxes[i][0] + 2
x_end = boxes[i+1][0]
y_mid = 2.0
ax.annotate('', xy=(x_end, y_mid), xytext=(x_start, y_mid),
arrowprops=dict(arrowstyle='->', color='gray', lw=2))
ax.set_title('ML Pipeline Diagram', fontsize=13, fontweight='bold', y=0.95)
fig.tight_layout()
fig.savefig('pipeline.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved pipeline.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(11, 6))
ax.set_xlim(0, 12); ax.set_ylim(0, 7)
ax.axis('off')
# Client
circ = mpatches.Circle((1, 3.5), 0.7, facecolor='#4c72b0', edgecolor='white', lw=2)
ax.add_patch(circ); ax.text(1, 3.5, 'Client', ha='center', va='center', color='white', fontsize=8, fontweight='bold')
# Load balancer
lb = mpatches.FancyBboxPatch((2.8, 2.8), 2, 1.4, boxstyle='round,pad=0.15',
facecolor='#dd8452', edgecolor='white', lw=2)
ax.add_patch(lb); ax.text(3.8, 3.5, 'Load
Balancer', ha='center', va='center', color='white', fontsize=8, fontweight='bold')
# App servers
for i, (y, col) in enumerate(zip([1.2, 3.5, 5.8], ['#55a868','#55a868','#55a868'])):
srv = mpatches.FancyBboxPatch((6.5, y), 1.8, 1.0, boxstyle='round,pad=0.1',
facecolor=col, edgecolor='white', lw=2)
ax.add_patch(srv)
ax.text(7.4, y+0.5, f'App {i+1}', ha='center', va='center', color='white', fontsize=8, fontweight='bold')
ax.annotate('', xy=(6.5, y+0.5), xytext=(4.8, 3.5),
arrowprops=dict(arrowstyle='->', color='gray', lw=1.5))
# DB
db = mpatches.Ellipse((10.5, 3.5), 1.4, 0.9, facecolor='#c44e52', edgecolor='white', lw=2)
ax.add_patch(db); ax.text(10.5, 3.5, 'DB', ha='center', va='center', color='white', fontsize=9, fontweight='bold')
for y in [1.7, 3.5, 6.3]:
ax.annotate('', xy=(9.8, 3.5), xytext=(8.3, y+0.5 if y != 3.5 else y),
arrowprops=dict(arrowstyle='->', color='gray', lw=1.2))
ax.annotate('', xy=(2.8, 3.5), xytext=(1.7, 3.5),
arrowprops=dict(arrowstyle='->', color='gray', lw=2))
ax.set_title('3-Tier Architecture Diagram', fontsize=13, fontweight='bold')
fig.tight_layout()
fig.savefig('architecture.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved architecture.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(7, 6))
ax.set_xlim(0, 7); ax.set_ylim(0, 7)
ax.set_aspect('equal'); ax.axis('off')
# Three overlapping circles
circles = [
mpatches.Circle((2.8, 4.2), 2, facecolor='#4c72b0', alpha=0.35, edgecolor='navy', lw=2),
mpatches.Circle((4.2, 4.2), 2, facecolor='#dd8452', alpha=0.35, edgecolor='darkred', lw=2),
mpatches.Circle((3.5, 2.5), 2, facecolor='#55a868', alpha=0.35, edgecolor='darkgreen', lw=2),
]
for c in circles: ax.add_patch(c)
# TODO: add text labels A, B, C in non-overlapping regions
# TODO: add intersection labels Aβ©B, Bβ©C, Aβ©C, Aβ©Bβ©C
# TODO: add title and save 'venn3.png'
plt.close()Visualize 2D vector fields with quiver() for arrow grids and streamplot() for continuous flow lines. Used for fluid dynamics, electric fields, and gradient maps.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = y = np.linspace(-2, 2, 15)
X, Y = np.meshgrid(x, y)
U = -Y # velocity components
V = X
fig, ax = plt.subplots(figsize=(6, 6))
q = ax.quiver(X, Y, U, V, np.sqrt(U**2+V**2),
cmap='coolwarm', scale=30, pivot='mid')
fig.colorbar(q, ax=ax, label='Speed')
ax.set_title('Rotational Vector Field')
ax.set_xlabel('x'); ax.set_ylabel('y')
ax.set_aspect('equal')
ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('quiver_basic.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved quiver_basic.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 100)
y = np.linspace(-2, 2, 80)
X, Y = np.meshgrid(x, y)
U = 1 - X**2
V = -Y
speed = np.sqrt(U**2 + V**2)
fig, ax = plt.subplots(figsize=(9, 5))
strm = ax.streamplot(X, Y, U, V, color=speed, cmap='plasma',
linewidth=1.5, density=1.5, arrowsize=1.2)
fig.colorbar(strm.lines, ax=ax, label='Speed')
ax.set_xlabel('x'); ax.set_ylabel('y')
ax.set_title('Streamplot: Flow Field Colored by Speed')
ax.set_aspect('equal')
ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('streamplot.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved streamplot.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = y = np.linspace(-3, 3, 50)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2)/2) # 2D Gaussian
dZdX, dZdY = np.gradient(Z, x, y)
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
cf = axes[0].contourf(X, Y, Z, levels=20, cmap='viridis')
fig.colorbar(cf, ax=axes[0], label='f(x,y)')
axes[0].set_title('Scalar Field: 2D Gaussian')
# Subsample for quiver
step = 4
axes[1].contourf(X, Y, Z, levels=20, cmap='viridis', alpha=0.5)
axes[1].quiver(X[::step,::step], Y[::step,::step],
dZdX[::step,::step], dZdY[::step,::step],
color='white', scale=10, alpha=0.9)
axes[1].set_title('Gradient Field (quiver)')
for ax in axes:
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.set_aspect('equal')
fig.tight_layout()
fig.savefig('gradient_field.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved gradient_field.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-4, 4, 200)
y = np.linspace(-3, 3, 150)
X, Y = np.meshgrid(x, y)
# Two point charges: +1 at (-1,0), -1 at (1,0)
def field(q, x0, y0, X, Y):
dx, dy = X - x0, Y - y0
r3 = (dx**2 + dy**2)**1.5
r3 = np.where(r3 < 0.1, 0.1, r3)
return q*dx/r3, q*dy/r3
Ex1, Ey1 = field(+1, -1, 0, X, Y)
Ex2, Ey2 = field(-1, +1, 0, X, Y)
Ex = Ex1 + Ex2; Ey = Ey1 + Ey2
speed = np.sqrt(Ex**2 + Ey**2)
fig, ax = plt.subplots(figsize=(8, 6))
strm = ax.streamplot(X, Y, Ex, Ey, color=np.log1p(speed),
cmap='coolwarm', density=1.5, linewidth=1.2)
ax.plot(-1, 0, 'bo', markersize=12, label='+q')
ax.plot(+1, 0, 'r^', markersize=12, label='-q')
fig.colorbar(strm.lines, ax=ax, label='log(|E|+1)')
ax.set_xlim(-4,4); ax.set_ylim(-3,3)
ax.set_title('Electric Dipole Field Lines')
ax.legend(); ax.set_aspect('equal')
fig.tight_layout()
fig.savefig('dipole_field.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved dipole_field.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-5, 5, 150)
y = np.linspace(-4, 4, 120)
X, Y = np.meshgrid(x, y)
# Gyre + drift
U = -Y * np.exp(-(X**2 + Y**2)/8) + 0.2
V = X * np.exp(-(X**2 + Y**2)/8) + 0.05*np.cos(Y)
speed = np.sqrt(U**2 + V**2)
fig, ax = plt.subplots(figsize=(10, 7))
strm = ax.streamplot(X, Y, U, V, color=speed, cmap='ocean_r',
density=2.0, linewidth=1.5, arrowsize=1.1)
fig.colorbar(strm.lines, ax=ax, label='Current Speed (m/s)')
# Simulated coastline patches
import matplotlib.patches as mp
coast = mp.Rectangle((3.5,-4), 1.5, 8, facecolor='#c2a267', edgecolor='none', zorder=5)
ax.add_patch(coast)
ax.text(4.25, 0, 'Coast', ha='center', rotation=90, fontsize=10,
fontweight='bold', color='#5a3e1b', zorder=6)
ax.plot(0, 0, 'w*', markersize=14, label='Gyre center', zorder=7)
ax.set_xlim(-5,5); ax.set_ylim(-4,4)
ax.set_xlabel('Longitude'); ax.set_ylabel('Latitude')
ax.set_title('Ocean Surface Current Gyre', fontweight='bold')
ax.legend(loc='upper left')
fig.tight_layout()
fig.savefig('ocean_current.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved ocean_current.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = y = np.linspace(-2, 2, 20)
X, Y = np.meshgrid(x, y)
U = X
V = -Y
speed = np.sqrt(U**2 + V**2)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# TODO: quiver on ax1, colored by speed
# TODO: streamplot on ax2, colored by speed
# TODO: mark (0,0) with a star on both
# TODO: add colorbar, labels, titles
# Hint: saddle point β unstable in x, stable in y
fig.tight_layout()
fig.savefig('saddle_field.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved saddle_field.png')Handle datasets with extreme outliers using a broken y-axis (two subplots with different ylim), and compare two unrelated scales with twinx()/twiny().
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
x = np.arange(10)
y = np.array([2, 3, 4, 3, 5, 4, 6, 5, 4, 3], dtype=float)
y[4] = 95 # outlier
fig, (ax_top, ax_bot) = plt.subplots(2, 1, figsize=(8, 6),
sharex=True, gridspec_kw={'hspace': 0.08, 'height_ratios': [1, 3]})
ax_top.bar(x, y, color='steelblue', alpha=0.8)
ax_bot.bar(x, y, color='steelblue', alpha=0.8)
ax_top.set_ylim(85, 100)
ax_bot.set_ylim(0, 10)
ax_top.spines['bottom'].set_visible(False)
ax_bot.spines['top'].set_visible(False)
ax_top.tick_params(bottom=False)
# Break markers
d = 0.015
kwargs = dict(transform=ax_top.transAxes, color='k', clip_on=False, linewidth=1.5)
ax_top.plot((-d, +d), (-d, +d), **kwargs)
ax_top.plot((1-d, 1+d), (-d, +d), **kwargs)
kwargs.update(transform=ax_bot.transAxes)
ax_bot.plot((-d, +d), (1-d, 1+d), **kwargs)
ax_bot.plot((1-d, 1+d), (1-d, 1+d), **kwargs)
ax_bot.set_xlabel('Category')
fig.text(0.04, 0.5, 'Value', va='center', rotation='vertical')
fig.suptitle('Broken Y-Axis β Outlier Handling', fontweight='bold')
fig.savefig('broken_axis.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved broken_axis.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
months = np.arange(1, 13)
temp = np.array([2,3,8,14,19,24,27,26,20,14,7,3], dtype=float)
precip = np.array([60,50,55,45,55,70,95,110,80,65,70,65], dtype=float)
month_labels = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
fig, ax1 = plt.subplots(figsize=(10, 5))
ax2 = ax1.twinx()
ax1.bar(months, precip, color='steelblue', alpha=0.5, label='Precipitation')
ax2.plot(months, temp, 'ro-', linewidth=2, markersize=6, label='Temperature')
ax1.set_xlabel('Month')
ax1.set_ylabel('Precipitation (mm)', color='steelblue')
ax2.set_ylabel('Temperature (Β°C)', color='tomato')
ax1.tick_params(axis='y', labelcolor='steelblue')
ax2.tick_params(axis='y', labelcolor='tomato')
ax1.set_xticks(months); ax1.set_xticklabels(month_labels, rotation=30)
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1+lines2, labels1+labels2, loc='upper left')
ax1.set_title('Climate Chart β twinx()', fontweight='bold')
ax1.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig('twinx_climate.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved twinx_climate.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
freq = np.linspace(10, 1000, 200) # Hz
period_ms = 1000 / freq # milliseconds
gain = 1 / (1 + (freq/100)**2)
fig, ax1 = plt.subplots(figsize=(9, 4))
ax2 = ax1.twiny()
ax1.semilogx(freq, gain, color='steelblue', linewidth=2)
ax1.set_xlabel('Frequency (Hz)', color='steelblue')
ax1.tick_params(axis='x', labelcolor='steelblue')
ax1.set_ylabel('Gain')
# Top axis: period in ms (nonuniform tick positions in frequency space)
tick_freq = [10, 20, 50, 100, 200, 500, 1000]
tick_labels = [f'{1000/f:.0f}' for f in tick_freq]
ax2.set_xscale('log')
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(tick_freq)
ax2.set_xticklabels(tick_labels)
ax2.set_xlabel('Period (ms)', color='tomato')
ax2.tick_params(axis='x', labelcolor='tomato')
ax1.set_title('Low-Pass Filter β Dual Frequency / Period Axes', fontweight='bold', y=1.15)
ax1.grid(True, which='both', alpha=0.3)
fig.tight_layout()
fig.savefig('twiny_filter.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved twiny_filter.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(5)
t = np.arange(24)
load = np.random.uniform(200, 400, 24)
load[12] = 950 # midday spike
price = 20 + 0.05 * load + np.random.randn(24) * 3
fig = plt.figure(figsize=(11, 7))
ax_t = fig.add_axes([0.1, 0.55, 0.8, 0.22])
ax_b = fig.add_axes([0.1, 0.10, 0.8, 0.40], sharex=ax_t)
ax_r = ax_b.twinx()
# broken axis
ax_t.bar(t, load, color='tomato', alpha=0.7); ax_t.set_ylim(800, 1050)
ax_b.bar(t, load, color='tomato', alpha=0.7); ax_b.set_ylim(0, 500)
ax_t.spines['bottom'].set_visible(False); ax_b.spines['top'].set_visible(False)
ax_t.tick_params(bottom=False)
ax_r.plot(t, price, 'b-o', markersize=4, linewidth=1.5)
ax_r.set_ylabel('Price ($/MWh)', color='steelblue')
ax_r.tick_params(axis='y', labelcolor='steelblue')
ax_b.set_xlabel('Hour of Day')
ax_b.set_ylabel('Load (MW)', color='tomato')
ax_b.tick_params(axis='y', labelcolor='tomato')
fig.suptitle('Grid Load & Price: Broken + Twin Axes', fontweight='bold', y=0.98)
fig.savefig('broken_twin.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved broken_twin.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(33)
days = np.arange(20)
opens = 100 + np.random.randn(20).cumsum()
closes = opens + np.random.randn(20) * 0.5
highs = np.maximum(opens, closes) + np.abs(np.random.randn(20))*0.8
lows = np.minimum(opens, closes) - np.abs(np.random.randn(20))*0.8
volume = np.random.randint(100000, 500000, 20).astype(float)
volume[9] = 1800000 # volume spike
fig, (ax_top, ax_bot) = plt.subplots(2, 1, figsize=(11,6),
sharex=True, gridspec_kw={'hspace':0.1,'height_ratios':[2,1]})
ax_vol = ax_bot.twinx()
# Candlestick style
for d in days:
color = 'seagreen' if closes[d] >= opens[d] else 'tomato'
ax_top.plot([d,d], [lows[d], highs[d]], color='gray', linewidth=1)
ax_top.bar(d, abs(closes[d]-opens[d]), bottom=min(opens[d],closes[d]),
color=color, width=0.6, alpha=0.9)
ax_bot.bar(days, volume, color='steelblue', alpha=0.5, label='Volume')
ax_vol.plot(days, closes, 'k-', linewidth=1.5, label='Close')
ax_vol.set_ylabel('Price ($)')
ax_bot.set_ylabel('Volume')
ax_top.set_ylabel('Price ($)')
ax_top.set_title('Stock Price & Volume Dashboard', fontweight='bold')
ax_bot.set_xlabel('Day')
fig.tight_layout()
fig.savefig('stock_dashboard.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved stock_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
months = np.arange(1, 13)
users = np.linspace(10, 80, 12) + np.random.randn(12)*3
costs = np.linspace(500, 2000, 12) + np.random.randn(12)*50
month_labels = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
fig, ax1 = plt.subplots(figsize=(10, 5))
ax2 = ax1.twinx()
# TODO: fill_between for users on ax1
# TODO: step line for costs on ax2
# TODO: contrasting colors, labels, legend, title
# TODO: save 'users_costs.png'
plt.close()Use imshow() for displaying arrays as images, applying colormaps, performing simple transformations, and visualizing feature maps from neural networks.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import Normalize
np.random.seed(0)
img = np.random.randn(40, 40).cumsum(axis=1)
cmaps_show = ['gray', 'viridis', 'plasma', 'RdBu_r']
fig, axes = plt.subplots(1, 4, figsize=(14, 3.5))
for ax, cmap in zip(axes, cmaps_show):
im = ax.imshow(img, cmap=cmap, aspect='auto')
plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
ax.set_title(cmap, fontsize=10)
ax.axis('off')
fig.suptitle('Same Array β Different Colormaps', fontweight='bold')
fig.tight_layout()
fig.savefig('colormaps_compare.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved colormaps_compare.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
img = np.random.rand(60, 80)
img[20:40, 30:60] = 0.85 # bright rectangle
transforms = {
'Original': img,
'Flipped H': np.fliplr(img),
'Rotated 45': np.rot90(img),
'Cropped': img[10:50, 20:70],
}
fig, axes = plt.subplots(1, 4, figsize=(14, 3.5))
for ax, (title, arr) in zip(axes, transforms.items()):
ax.imshow(arr, cmap='gray', vmin=0, vmax=1)
ax.set_title(title, fontsize=10); ax.axis('off')
fig.suptitle('Image Transformations', fontweight='bold')
fig.tight_layout()
fig.savefig('img_transforms.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved img_transforms.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
n_filters = 8
feature_maps = [np.random.randn(28, 28) for _ in range(n_filters)]
for i, fm in enumerate(feature_maps):
# Simulate different filter responses
x = y = np.linspace(-3, 3, 28)
X, Y = np.meshgrid(x, y)
feature_maps[i] = np.sin(X*(i+1)*0.5) * np.cos(Y*(i+1)*0.3) + np.random.randn(28,28)*0.2
fig, axes = plt.subplots(2, 4, figsize=(12, 6))
for ax, fm in zip(axes.flat, feature_maps):
im = ax.imshow(fm, cmap='RdBu_r', aspect='auto')
plt.colorbar(im, ax=ax, fraction=0.046)
ax.axis('off')
fig.suptitle('CNN Feature Maps (Layer 1)', fontweight='bold')
fig.tight_layout()
fig.savefig('feature_maps.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved feature_maps.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
h, w = 60, 80
bg = np.random.randn(h, w)
signal_x, signal_y = 50, 30
for dy in range(-10, 11):
for dx in range(-15, 16):
if dx**2/225 + dy**2/100 < 1:
bg[signal_y+dy, signal_x+dx] += 3.0
fig, axes = plt.subplots(1, 3, figsize=(14, 4))
# Raw image
axes[0].imshow(bg, cmap='gray'); axes[0].set_title('Raw'); axes[0].axis('off')
# Thresholded mask
mask = (bg > 2.0).astype(float)
axes[1].imshow(bg, cmap='gray')
axes[1].imshow(mask, cmap='Reds', alpha=0.5)
axes[1].set_title('Overlay Mask'); axes[1].axis('off')
# Contour overlay
axes[2].imshow(bg, cmap='gray')
axes[2].contour(bg, levels=[1.5, 2.5], colors=['yellow','red'], linewidths=1.5)
axes[2].annotate('Signal', xy=(signal_x, signal_y), xytext=(signal_x+12, signal_y-12),
arrowprops=dict(arrowstyle='->', color='cyan'),
color='cyan', fontsize=10, fontweight='bold')
axes[2].set_title('Contour Overlay'); axes[2].axis('off')
fig.suptitle('Image Segmentation Visualization', fontweight='bold')
fig.tight_layout()
fig.savefig('img_overlay.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved img_overlay.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import gaussian_filter
np.random.seed(42)
h, w = 80, 100
img = np.zeros((h, w))
for cx, cy, r, v in [(50,40,15,1.0),(35,30,8,0.7),(65,50,10,0.8),(45,60,6,0.6)]:
y_idx, x_idx = np.ogrid[:h,:w]
img += v * np.exp(-((x_idx-cx)**2 + (y_idx-cy)**2)/(2*r**2))
img = gaussian_filter(img + np.random.randn(h,w)*0.05, sigma=1.5)
fig, axes = plt.subplots(1, 4, figsize=(14, 4))
axes[0].imshow(img, cmap='gray'); axes[0].set_title('Raw MRI Slice'); axes[0].axis('off')
mask = img > img.max()*0.5
axes[1].imshow(img, cmap='gray')
axes[1].imshow(np.ma.masked_where(~mask, img), cmap='Reds', alpha=0.6, vmin=0, vmax=1)
axes[1].set_title('Threshold Mask'); axes[1].axis('off')
gy, gx = np.gradient(img)
grad_mag = np.sqrt(gx**2 + gy**2)
axes[2].imshow(grad_mag, cmap='hot'); axes[2].set_title('Gradient Magnitude'); axes[2].axis('off')
axes[3].imshow(img, cmap='plasma')
axes[3].contour(img, levels=[img.max()*0.5], colors='white', linewidths=2)
axes[3].set_title('Pseudo-color + Contour'); axes[3].axis('off')
fig.suptitle('MRI Analysis Dashboard', fontweight='bold')
fig.tight_layout()
fig.savefig('mri_dashboard.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved mri_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
# Build checkerboard
size, block = 50, 5
board = np.zeros((size, size))
for i in range(0, size, block):
for j in range(0, size, block):
if (i//block + j//block) % 2 == 0:
board[i:i+block, j:j+block] = 1
fig, axes = plt.subplots(1, 3, figsize=(11, 4))
# TODO: original gray cmap
# TODO: hot cmap with colorbar
# TODO: blurred version (use gaussian_filter from scipy.ndimage)
# TODO: add titles and axis('off')
# TODO: save 'checkerboard.png'
plt.close()Create publication-quality statistical visualizations: regression plots, residual diagnostics, Q-Q plots, correlation matrices, and bootstrapped confidence intervals.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
n = 80
x = np.linspace(0, 10, n)
y = 2.5*x + 1.0 + np.random.randn(n)*3
# Manual OLS
coeffs = np.polyfit(x, y, 1)
poly = np.poly1d(coeffs)
y_pred = poly(x)
residuals = y - y_pred
se = np.std(residuals) * np.sqrt(1/n + (x - x.mean())**2 / ((x - x.mean())**2).sum())
t_val = 1.99 # ~95% CI for n=80
fig, ax = plt.subplots(figsize=(8, 5))
ax.scatter(x, y, s=25, alpha=0.6, color='steelblue', label='Data')
ax.plot(x, y_pred, 'r-', linewidth=2, label=f'y={coeffs[0]:.2f}x+{coeffs[1]:.2f}')
ax.fill_between(x, y_pred - t_val*se, y_pred + t_val*se,
alpha=0.2, color='red', label='95% CI')
ax.set_xlabel('X'); ax.set_ylabel('Y')
ax.set_title('Linear Regression with Confidence Band')
ax.legend(); ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig('regression_plot.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved regression_plot.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
np.random.seed(1)
fig, axes = plt.subplots(1, 3, figsize=(13, 4))
datasets = {
'Normal': np.random.normal(0, 1, 200),
'Right-Skewed': np.random.exponential(1, 200),
'Heavy-Tailed': np.random.standard_t(df=3, size=200),
}
for ax, (name, data) in zip(axes, datasets.items()):
qq = stats.probplot(data, dist='norm')
theo, sample = qq[0]
ax.scatter(theo, sample, s=15, alpha=0.6, color='steelblue')
ax.plot(theo, theo * qq[1][0] + qq[1][1], 'r-', linewidth=1.5, label='Ideal')
ax.set_title(f'Q-Q Plot: {name}')
ax.set_xlabel('Theoretical Quantiles')
ax.set_ylabel('Sample Quantiles')
ax.grid(True, alpha=0.3); ax.legend(fontsize=8)
fig.tight_layout()
fig.savefig('qq_plots.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved qq_plots.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(2)
n = 200
a = np.random.randn(n)
b = 0.8*a + np.random.randn(n)*0.6
c = -0.5*a + np.random.randn(n)*0.8
d = np.random.randn(n)
e = 0.6*b + 0.4*d + np.random.randn(n)*0.5
data_mat = np.vstack([a,b,c,d,e]).T
labels = ['Feature A','Feature B','Feature C','Feature D','Feature E']
corr = np.corrcoef(data_mat.T)
fig, ax = plt.subplots(figsize=(7, 6))
im = ax.imshow(corr, cmap='RdBu_r', vmin=-1, vmax=1)
plt.colorbar(im, ax=ax, label='Pearson r')
ax.set_xticks(range(5)); ax.set_xticklabels(labels, rotation=30, ha='right', fontsize=9)
ax.set_yticks(range(5)); ax.set_yticklabels(labels, fontsize=9)
for i in range(5):
for j in range(5):
c_val = corr[i,j]
ax.text(j, i, f'{c_val:.2f}', ha='center', va='center', fontsize=8,
color='white' if abs(c_val) > 0.5 else 'black')
ax.set_title('Correlation Matrix', fontweight='bold')
fig.tight_layout()
fig.savefig('corr_matrix.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved corr_matrix.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
data = np.random.exponential(2, 100)
n_boot = 2000
boot_means = [np.mean(np.random.choice(data, len(data), replace=True))
for _ in range(n_boot)]
ci_lo, ci_hi = np.percentile(boot_means, [2.5, 97.5])
true_mean = np.mean(data)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
ax1.hist(data, bins=25, color='steelblue', alpha=0.7, density=True)
ax1.axvline(true_mean, color='red', linewidth=2, label=f'Mean={true_mean:.2f}')
ax1.set_title('Original Data (Exponential)'); ax1.legend(); ax1.grid(True, alpha=0.3)
ax2.hist(boot_means, bins=40, color='seagreen', alpha=0.7, density=True)
ax2.axvline(ci_lo, color='red', linestyle='--', linewidth=2, label=f'95% CI [{ci_lo:.2f}, {ci_hi:.2f}]')
ax2.axvline(ci_hi, color='red', linestyle='--', linewidth=2)
ax2.axvline(true_mean, color='black', linewidth=2, label='Sample mean')
ax2.set_title('Bootstrap Distribution of Mean')
ax2.legend(fontsize=8); ax2.grid(True, alpha=0.3)
fig.suptitle('Bootstrapped 95% Confidence Interval', fontweight='bold')
fig.tight_layout()
fig.savefig('bootstrap_ci.png', dpi=120, bbox_inches='tight')
plt.close()
print('Saved bootstrap_ci.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
np.random.seed(99)
x = np.linspace(0, 10, 100)
y_true = 0.2*x**3 - 3*x**2 + 10*x + 5
y = y_true + np.random.randn(100)*5
coeffs = np.polyfit(x, y, 3)
poly = np.poly1d(coeffs)
y_hat = poly(x)
resid = y - y_hat
fig, axes = plt.subplots(2, 2, figsize=(11, 8))
# Fitted curve
axes[0,0].scatter(x, y, s=20, alpha=0.6, color='steelblue', label='Data')
axes[0,0].plot(x, y_hat, 'r-', linewidth=2, label='Poly-3 fit')
axes[0,0].set_title('Fitted Curve'); axes[0,0].legend(); axes[0,0].grid(True, alpha=0.3)
# Residuals vs fitted
axes[0,1].scatter(y_hat, resid, s=15, alpha=0.6, color='steelblue')
axes[0,1].axhline(0, color='red', linestyle='--', linewidth=1.5)
axes[0,1].set_xlabel('Fitted'); axes[0,1].set_ylabel('Residuals')
axes[0,1].set_title('Residuals vs Fitted'); axes[0,1].grid(True, alpha=0.3)
# Q-Q plot
qq = stats.probplot(resid, dist='norm')
theo, samp = qq[0]
axes[1,0].scatter(theo, samp, s=15, alpha=0.6, color='steelblue')
axes[1,0].plot(theo, theo*qq[1][0]+qq[1][1], 'r-', linewidth=1.5)
axes[1,0].set_title('Q-Q Plot of Residuals')
axes[1,0].set_xlabel('Theoretical'); axes[1,0].set_ylabel('Sample')
axes[1,0].grid(True, alpha=0.3)
# Residual histogram
axes[1,1].hist(resid, bins=20, density=True, color='steelblue', alpha=0.7)
rx = np.linspace(resid.min(), resid.max(), 100)
axes[1,1].plot(rx, stats.norm.pdf(rx, resid.mean(), resid.std()), 'r-', linewidth=2)
axes[1,1].set_title('Residual Distribution'); axes[1,1].grid(True, alpha=0.3)
fig.suptitle('Regression Diagnostic Panel', fontweight='bold')
fig.tight_layout()
fig.savefig('regression_diagnostics.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved regression_diagnostics.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(20)
groups = [np.random.normal(mu, 1, 50) for mu in range(1, 6)]
labels = [f'G{i}' for i in range(1, 6)]
colors = ['#4c72b0','#dd8452','#55a868','#c44e52','#9467bd']
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# TODO: boxplot on ax1 with mean diamond markers
# TODO: violinplot on ax2 with jitter scatter overlay
# TODO: matching colors, labels, titles
# TODO: save 'group_stats.png'
plt.close()Export single figures at various DPIs, save multiple pages to PDF with PdfPages, create figure collections, and control backends for headless rendering.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
np.random.seed(0)
pdf_path = 'multi_page_report.pdf'
with PdfPages(pdf_path) as pdf:
# Page 1: line plot
fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 10, 200)
ax.plot(x, np.sin(x), color='steelblue', linewidth=2)
ax.set_title('Page 1: Sine Wave')
ax.grid(True, alpha=0.3)
fig.tight_layout()
pdf.savefig(fig); plt.close()
# Page 2: bar chart
fig, ax = plt.subplots(figsize=(8, 5))
vals = np.random.randint(10, 100, 8)
ax.bar(range(8), vals, color='tomato', alpha=0.8)
ax.set_title('Page 2: Bar Chart')
fig.tight_layout()
pdf.savefig(fig); plt.close()
# Page 3: scatter
fig, ax = plt.subplots(figsize=(8, 5))
ax.scatter(*np.random.randn(2, 200), s=20, alpha=0.5)
ax.set_title('Page 3: Scatter')
fig.tight_layout()
pdf.savefig(fig); plt.close()
d = pdf.infodict()
d['Title'] = 'Data Science Report'
d['Author'] = 'matplotlib'
print(f'Saved {pdf_path} (3 pages)')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
x = np.linspace(0, 2*np.pi, 200)
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot(x, np.sin(x), linewidth=2, color='steelblue', label='sin')
ax.plot(x, np.cos(x), linewidth=2, color='tomato', linestyle='--', label='cos')
ax.legend(); ax.set_title('Multi-DPI Export Test')
ax.grid(True, alpha=0.3)
fig.tight_layout()
for dpi in [72, 150, 300]:
fname = f'export_dpi{dpi}.png'
fig.savefig(fname, dpi=dpi, bbox_inches='tight')
print(f'Saved {fname} at {dpi} DPI')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
matplotlib.rcParams['svg.fonttype'] = 'none' # editable text in SVG
np.random.seed(2)
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
x = np.linspace(-3, 3, 100)
axes[0].plot(x, stats_curve := 1/(1+np.exp(-x)), color='steelblue', linewidth=2)
axes[0].axhline(0.5, color='red', linestyle='--', linewidth=1)
axes[0].set_title('Sigmoid Function'); axes[0].grid(True, alpha=0.3)
axes[0].set_xlabel('x'); axes[0].set_ylabel('sigma(x)')
np.random.seed(2)
data = np.random.randn(100)
axes[1].hist(data, bins=20, color='seagreen', alpha=0.7, density=True)
axes[1].set_title('Normal Distribution'); axes[1].grid(True, alpha=0.3)
fig.suptitle('SVG Export Example', fontweight='bold')
fig.tight_layout()
fig.savefig('vector_export.svg', format='svg', bbox_inches='tight')
fig.savefig('vector_export.png', dpi=150, bbox_inches='tight')
print('Saved vector_export.svg and vector_export.png')
plt.close()import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(3)
fig = plt.figure(figsize=(10, 7))
fig.set_facecolor('#0f1117')
ax1 = fig.add_subplot(2, 2, (1, 2)) # top row, spans both cols
ax2 = fig.add_subplot(2, 2, 3)
ax3 = fig.add_subplot(2, 2, 4)
x = np.linspace(0, 10, 300)
ax1.plot(x, np.sin(x)*np.exp(-0.1*x), color='#58a6ff', linewidth=2)
ax1.set_facecolor('#1c2128'); ax1.tick_params(colors='white')
for sp in ax1.spines.values(): sp.set_color('#30363d')
ax1.set_title('Damped Oscillation', color='white')
ax2.hist(np.random.randn(500), bins=25, color='#79c0ff', alpha=0.8)
ax2.set_facecolor('#1c2128'); ax2.tick_params(colors='white')
for sp in ax2.spines.values(): sp.set_color('#30363d')
ax2.set_title('Distribution', color='white')
ax3.scatter(*np.random.randn(2,100), s=15, alpha=0.6, color='#ffa657')
ax3.set_facecolor('#1c2128'); ax3.tick_params(colors='white')
for sp in ax3.spines.values(): sp.set_color('#30363d')
ax3.set_title('Scatter', color='white')
fig.suptitle('Dark Theme Dashboard', color='white', fontweight='bold', fontsize=14)
fig.tight_layout()
fig.savefig('dark_dashboard.png', dpi=150, bbox_inches='tight',
facecolor=fig.get_facecolor())
plt.close()
print('Saved dark_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
np.random.seed(77)
with PdfPages('automated_report.pdf') as pdf:
# Page 1: cover
fig = plt.figure(figsize=(8.5, 11))
fig.patch.set_facecolor('#1c2128')
ax = fig.add_axes([0,0,1,1]); ax.axis('off')
ax.text(0.5,0.65,'Data Science
Quarterly Report', ha='center', va='center',
fontsize=28, color='white', fontweight='bold', transform=ax.transAxes)
ax.text(0.5,0.45,'Q1 2025 | Generated by Matplotlib', ha='center',
fontsize=13, color='#8b949e', transform=ax.transAxes)
pdf.savefig(fig, facecolor=fig.get_facecolor()); plt.close()
# Page 2: KPI panel
fig, axes = plt.subplots(1,3, figsize=(11,5))
kpis = [('Revenue','$2.4M','+12%','#4c72b0'),
('Users','84K','+8%','#55a868'),
('NPS','72','+5pt','#dd8452')]
for ax,(label,val,delta,col) in zip(axes,kpis):
ax.set_facecolor(col); ax.axis('off')
ax.text(0.5,0.65,val,ha='center',fontsize=28,fontweight='bold',
color='white',transform=ax.transAxes)
ax.text(0.5,0.35,f'{label}
{delta}',ha='center',fontsize=11,
color='white',transform=ax.transAxes)
fig.suptitle('Key Performance Indicators',fontweight='bold')
fig.tight_layout(); pdf.savefig(fig); plt.close()
# Page 3: trends
fig, ax = plt.subplots(figsize=(10,5))
months = np.arange(12)
for i,(name,col) in enumerate([('Revenue','#4c72b0'),('Costs','tomato'),('Margin','seagreen')]):
y = np.cumsum(np.random.randn(12)*0.5) + 5 + i*1.5
ax.plot(months, y, color=col, linewidth=2, label=name, marker='o', markersize=4)
ax.set_title('12-Month Trend Analysis'); ax.legend(); ax.grid(True, alpha=0.3)
fig.tight_layout(); pdf.savefig(fig); plt.close()
# Page 4: table
fig, ax = plt.subplots(figsize=(10,4))
ax.axis('off')
cols = ['Region','Q1','Q2','Q3','Q4','Total']
rows = [['North','$1.2M','$1.4M','$1.3M','$1.6M','$5.5M'],
['South','$0.9M','$1.0M','$1.1M','$1.3M','$4.3M'],
['East','$0.7M','$0.8M','$0.9M','$1.0M','$3.4M'],
['West','$1.1M','$1.2M','$1.4M','$1.5M','$5.2M']]
tbl = ax.table(cellText=rows, colLabels=cols, loc='center', cellLoc='center')
tbl.auto_set_font_size(False); tbl.set_fontsize(10); tbl.scale(1.2,1.8)
ax.set_title('Regional Revenue Summary', fontweight='bold', pad=20)
fig.tight_layout(); pdf.savefig(fig); plt.close()
print('Saved automated_report.pdf (4 pages)')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
np.random.seed(8)
x = np.linspace(0, 10, 100)
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(13, 4))
ax1.plot(x, np.sin(x)); ax1.set_title('Line')
ax2.bar(range(5), np.random.randint(1,10,5)); ax2.set_title('Bar')
ax3.scatter(*np.random.randn(2,50), s=20, alpha=0.6); ax3.set_title('Scatter')
fig.tight_layout()
# TODO: save PNG at 72 DPI
# TODO: save PNG at 300 DPI
# TODO: save SVG
# TODO: save 2-page PDF with PdfPages
plt.close()
print('Done')Compose production-quality dashboards by combining GridSpec layouts, dual axes, custom patches, annotation, and multi-figure export. Design for clarity, color accessibility, and print quality.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
import matplotlib.patches as mpatches
np.random.seed(42)
fig = plt.figure(figsize=(14, 9), facecolor='#0f1117')
gs = GridSpec(3, 4, figure=fig, hspace=0.45, wspace=0.4)
def dark_ax(ax, title=''):
ax.set_facecolor('#1c2128')
for sp in ax.spines.values(): sp.set_color('#30363d')
ax.tick_params(colors='#c9d1d9', labelsize=8)
if title: ax.set_title(title, color='white', fontsize=9, fontweight='bold')
return ax
# Top row: KPI boxes (4 mini panels)
kpis = [('Revenue', '$2.4M', '+12%', '#4c72b0'),
('DAU', '84K', '+8%', '#55a868'),
('Conv%', '3.7%', '+0.3', '#dd8452'),
('NPS', '72', '+5', '#c44e52')]
for col, (label, val, delta, color) in enumerate(kpis):
ax = fig.add_subplot(gs[0, col])
ax.set_facecolor(color); ax.axis('off')
ax.text(0.5, 0.6, val, ha='center', va='center', fontsize=18,
fontweight='bold', color='white', transform=ax.transAxes)
ax.text(0.5, 0.2, f'{label} {delta}', ha='center', fontsize=9,
color='white', transform=ax.transAxes)
# Mid-left: trend line (spans 2 cols)
ax_trend = dark_ax(fig.add_subplot(gs[1, :2]), 'Monthly Revenue Trend')
months = np.arange(12)
rev = 1.5 + np.cumsum(np.random.randn(12)*0.08) + np.linspace(0,0.9,12)
ax_trend.plot(months, rev, color='#58a6ff', linewidth=2)
ax_trend.fill_between(months, rev.min(), rev, alpha=0.15, color='#58a6ff')
ax_trend.set_xticks(months)
ax_trend.set_xticklabels(['J','F','M','A','M','J','J','A','S','O','N','D'],
color='#8b949e', fontsize=7)
# Mid-right: bar chart (spans 2 cols)
ax_bar = dark_ax(fig.add_subplot(gs[1, 2:]), 'Revenue by Region')
regions = ['North','South','East','West']
vals = [2.4, 1.8, 1.3, 2.1]
colors_r = ['#4c72b0','#55a868','#dd8452','#c44e52']
ax_bar.bar(regions, vals, color=colors_r, alpha=0.85, width=0.6)
for i, (r, v) in enumerate(zip(regions, vals)):
ax_bar.text(i, v+0.05, f'${v}M', ha='center', fontsize=8, color='white')
# Bottom: scatter + right-side donut
ax_scatter = dark_ax(fig.add_subplot(gs[2, :3]), 'User Engagement')
n = 300
sessions = np.random.lognormal(1, 0.5, n)
revenue_pts = sessions * np.random.uniform(5, 30, n)
sc = ax_scatter.scatter(sessions, revenue_pts, c=np.log(sessions),
cmap='plasma', s=20, alpha=0.6)
ax_scatter.set_xlabel('Sessions', color='#8b949e', fontsize=8)
ax_scatter.set_ylabel('Revenue ($)', color='#8b949e', fontsize=8)
ax_pie = dark_ax(fig.add_subplot(gs[2, 3]), 'Traffic Mix')
wedges, _ = ax_pie.pie([35,30,20,15], colors=['#4c72b0','#55a868','#dd8452','#8172b2'],
startangle=90, wedgeprops=dict(width=0.5))
ax_pie.legend(wedges, ['Direct','Organic','Paid','Ref'], loc='lower center',
fontsize=7, labelcolor='white', facecolor='#1c2128',
bbox_to_anchor=(0.5,-0.15), ncol=2)
ax_pie.axis('off'); ax_pie.set_facecolor('#1c2128')
fig.suptitle('Business Intelligence Dashboard', color='white',
fontsize=15, fontweight='bold', y=0.98)
fig.savefig('bi_dashboard.png', dpi=150, bbox_inches='tight',
facecolor=fig.get_facecolor())
plt.close()
print('Saved bi_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
from scipy import stats
np.random.seed(7)
fig = plt.figure(figsize=(13, 8))
gs = GridSpec(2, 3, hspace=0.38, wspace=0.35)
# Time series with confidence band
ax1 = fig.add_subplot(gs[0, :2])
t = np.linspace(0, 20, 200)
signal = np.sin(t) * np.exp(-0.1*t)
noise = np.random.randn(200)*0.15
measured = signal + noise
upper = signal + 0.3; lower = signal - 0.3
ax1.fill_between(t, lower, upper, alpha=0.2, color='steelblue', label='95% CI')
ax1.plot(t, signal, 'steelblue', linewidth=2, label='True')
ax1.plot(t, measured, 'k.', markersize=3, alpha=0.4, label='Measured')
ax1.set_title('Damped Oscillation β Experiment A'); ax1.legend(fontsize=8)
ax1.set_xlabel('Time (s)'); ax1.grid(True, alpha=0.3)
# Q-Q
ax2 = fig.add_subplot(gs[0, 2])
qq = stats.probplot(measured - signal)
ax2.scatter(qq[0][0], qq[0][1], s=10, alpha=0.6, color='steelblue')
ax2.plot(qq[0][0], qq[0][0]*qq[1][0]+qq[1][1], 'r-')
ax2.set_title('Residual Q-Q'); ax2.grid(True, alpha=0.3)
# Frequency spectrum
ax3 = fig.add_subplot(gs[1, :2])
fft = np.abs(np.fft.rfft(measured))
freq = np.fft.rfftfreq(len(measured), d=t[1]-t[0])
ax3.semilogy(freq[1:], fft[1:], color='tomato', linewidth=1.5)
ax3.axvline(1/(2*np.pi), color='navy', linestyle='--', linewidth=1.5,
label=f'Fundamental {1/(2*np.pi):.3f} Hz')
ax3.set_xlabel('Frequency (Hz)'); ax3.set_ylabel('Amplitude')
ax3.set_title('FFT Spectrum'); ax3.legend(fontsize=8); ax3.grid(True, which='both', alpha=0.3)
# Phase portrait
ax4 = fig.add_subplot(gs[1, 2])
vel = np.gradient(measured, t)
ax4.plot(measured, vel, 'purple', alpha=0.6, linewidth=0.8)
ax4.set_xlabel('Displacement'); ax4.set_ylabel('Velocity')
ax4.set_title('Phase Portrait'); ax4.grid(True, alpha=0.3)
fig.suptitle('Experiment Dashboard β Damped Oscillator', fontweight='bold', fontsize=13)
fig.savefig('science_dashboard.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved science_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(21)
n = 60
dates = np.arange(n)
close = 100 + np.cumsum(np.random.randn(n)*1.2)
high = close + np.abs(np.random.randn(n))*1.5
low = close - np.abs(np.random.randn(n))*1.5
opens = close + np.random.randn(n)*0.5
volume = np.random.randint(500, 2000, n).astype(float)
sma20 = np.convolve(close, np.ones(20)/20, mode='valid')
sma_x = dates[19:]
bb_mid = sma20
bb_std = np.array([close[i-20:i].std() for i in range(20, n)])
bb_up = bb_mid + 2*bb_std; bb_lo = bb_mid - 2*bb_std
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(12, 8))
gs = GridSpec(3, 1, height_ratios=[3, 1, 1], hspace=0.12)
ax_price = fig.add_subplot(gs[0]); ax_vol = fig.add_subplot(gs[1], sharex=ax_price)
ax_rsi = fig.add_subplot(gs[2], sharex=ax_price)
for d in dates:
color = 'seagreen' if close[d] >= opens[d] else 'tomato'
ax_price.plot([d,d],[low[d],high[d]], color='gray', linewidth=0.8)
ax_price.bar(d, abs(close[d]-opens[d]), bottom=min(close[d],opens[d]),
color=color, width=0.6)
ax_price.plot(sma_x, sma20, 'navy', linewidth=1.5, label='SMA20')
ax_price.fill_between(sma_x, bb_lo, bb_up, alpha=0.1, color='blue', label='BBΒ±2Ο')
ax_price.set_ylabel('Price'); ax_price.legend(fontsize=8)
ax_price.set_title('OHLC with Bollinger Bands', fontweight='bold')
ax_vol.bar(dates, volume, color='steelblue', alpha=0.6)
ax_vol.set_ylabel('Volume')
delta = np.diff(close); up = np.where(delta>0,delta,0); down = np.where(delta<0,-delta,0)
rs = np.convolve(up,np.ones(14)/14,'valid') / (np.convolve(down,np.ones(14)/14,'valid')+1e-9)
rsi = 100 - 100/(1+rs)
ax_rsi.plot(dates[14:], rsi, color='purple', linewidth=1.5)
ax_rsi.axhline(70, color='red', linestyle='--', linewidth=1)
ax_rsi.axhline(30, color='green', linestyle='--', linewidth=1)
ax_rsi.fill_between(dates[14:], 30, 70, alpha=0.05, color='gray')
ax_rsi.set_ylabel('RSI'); ax_rsi.set_ylim(0,100)
ax_rsi.set_xlabel('Day')
plt.setp(ax_price.get_xticklabels(), visible=False)
plt.setp(ax_vol.get_xticklabels(), visible=False)
fig.savefig('financial_chart.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved financial_chart.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
# Colorblind-safe palette (Wong 2011)
CB_COLORS = ['#000000','#E69F00','#56B4E9','#009E73',
'#F0E442','#0072B2','#D55E00','#CC79A7']
np.random.seed(99)
fig, axes = plt.subplots(2, 2, figsize=(11, 8))
axes = axes.flat
# 1. Line plot
ax = axes[0]
x = np.linspace(0, 10, 100)
for i, col in enumerate(CB_COLORS[:4]):
ax.plot(x, np.sin(x + i*np.pi/4), color=col, linewidth=2,
label=f'Series {i+1}', linestyle=['-','--','-.',':'][i])
ax.set_title('Line Plot β CB Safe'); ax.legend(fontsize=8); ax.grid(True, alpha=0.3)
# 2. Bar chart
ax = axes[1]
vals = np.random.uniform(2, 9, 5)
ax.bar(range(5), vals, color=CB_COLORS[:5], alpha=0.9, width=0.6,
hatch=['', '//', 'xx', '..', '\\']) # hatch for print accessibility
ax.set_title('Bar with Hatch Patterns'); ax.grid(True, axis='y', alpha=0.3)
# 3. Scatter
ax = axes[2]
for i in range(4):
pts = np.random.randn(30, 2)
ax.scatter(pts[:,0], pts[:,1], color=CB_COLORS[i+1], s=40, alpha=0.8,
marker=['o','s','^','D'][i], label=f'Class {i+1}')
ax.set_title('Scatter β Multiple Markers'); ax.legend(fontsize=8)
# 4. Filled area
ax = axes[3]
x_a = np.linspace(0, 8, 80)
for i, col in enumerate(CB_COLORS[1:5]):
y = np.sin(x_a + i) + i*0.8
ax.plot(x_a, y, color=col, linewidth=2)
ax.fill_between(x_a, 0, y, color=col, alpha=0.15)
ax.set_title('Area Chart β CB Safe'); ax.grid(True, alpha=0.3)
fig.suptitle('Colorblind-Safe Dashboard (Wong Palette)', fontweight='bold', fontsize=13)
fig.tight_layout()
fig.savefig('accessible_dashboard.png', dpi=150, bbox_inches='tight')
plt.close()
print('Saved accessible_dashboard.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
import matplotlib.patches as mpatches
np.random.seed(88)
fig = plt.figure(figsize=(14, 10), facecolor='white')
gs = GridSpec(3, 3, figure=fig, hspace=0.45, wspace=0.35)
# Banner
ax_banner = fig.add_subplot(gs[0, :])
ax_banner.set_facecolor('#1c2128'); ax_banner.axis('off')
ax_banner.text(0.5, 0.6, 'Executive Dashboard β Q4 2024',
ha='center', fontsize=18, fontweight='bold', color='white',
transform=ax_banner.transAxes)
ax_banner.text(0.5, 0.2, 'Prepared by Analytics Team | Confidential',
ha='center', fontsize=11, color='#8b949e',
transform=ax_banner.transAxes)
# Revenue trend
ax_rev = fig.add_subplot(gs[1, :2])
months = np.arange(12)
rev = 1.0 + np.cumsum(np.random.randn(12)*0.05) + np.linspace(0,0.8,12)
target = np.linspace(1.0, 2.0, 12)
ax_rev.plot(months, rev, 'steelblue', linewidth=2.5, marker='o', markersize=5, label='Actual')
ax_rev.plot(months, target, 'r--', linewidth=1.5, label='Target')
ax_rev.fill_between(months, rev, target, where=(rev>=target),
alpha=0.15, color='green', label='Ahead')
ax_rev.fill_between(months, rev, target, where=(rev<target),
alpha=0.15, color='red', label='Behind')
ax_rev.set_title('Monthly Revenue vs Target', fontweight='bold')
ax_rev.legend(fontsize=8); ax_rev.grid(True, alpha=0.3)
# Regional bar
ax_geo = fig.add_subplot(gs[1, 2])
regions = ['APAC','EMEA','AMER','LATAM']
rev_r = [4.2, 3.1, 5.8, 1.9]
ax_geo.barh(regions, rev_r, color=['#4c72b0','#dd8452','#55a868','#c44e52'], alpha=0.85)
for i,(r,v) in enumerate(zip(regions,rev_r)):
ax_geo.text(v+0.05, i, f'${v}M', va='center', fontsize=9)
ax_geo.set_title('Revenue by Region', fontweight='bold')
ax_geo.grid(True, axis='x', alpha=0.3)
# Funnel
ax_funnel = fig.add_subplot(gs[2, :2])
stages = ['Visitors','Signups','Activated','Paid','Retained']
counts = [100000, 18000, 9000, 2800, 1900]
colors_f = ['#4c72b0','#5e82c0','#7498d0','#8aaee0','#a0c4f0']
ax_funnel.barh(stages[::-1], counts[::-1], color=colors_f, alpha=0.85)
for i,(s,c) in enumerate(zip(stages[::-1],counts[::-1])):
ax_funnel.text(c+500, i, f'{c:,}', va='center', fontsize=9)
ax_funnel.set_title('User Acquisition Funnel', fontweight='bold')
ax_funnel.grid(True, axis='x', alpha=0.3)
# Table
ax_tbl = fig.add_subplot(gs[2, 2])
ax_tbl.axis('off')
cols = ['Metric','Q3','Q4']
rows = [['Revenue','$18.2M','$22.1M'],
['Users','76K','84K'],
['NPS','67','72']]
tbl = ax_tbl.table(cellText=rows, colLabels=cols, loc='center', cellLoc='center')
tbl.auto_set_font_size(False); tbl.set_fontsize(9); tbl.scale(1.1,1.5)
ax_tbl.set_title('Summary', fontweight='bold', pad=15)
fig.savefig('executive_deck.png', dpi=200, bbox_inches='tight',
facecolor=fig.get_facecolor())
plt.close()
print('Saved executive_deck.png')import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
np.random.seed(42)
fig = plt.figure(figsize=(13, 9))
gs = GridSpec(3, 3, figure=fig, hspace=0.4, wspace=0.35)
# TODO: Banner row (gs[0, :])
# TODO: Main chart spanning 2 cols (gs[1, :2])
# TODO: Side chart (gs[1, 2])
# TODO: Bottom-left chart (gs[2, :2])
# TODO: Bottom-right chart or table (gs[2, 2])
# TODO: At least one twinx or broken axis
# TODO: Title and tight_layout
# TODO: save 'my_dashboard.png' at 150 DPI
plt.close()
print('Dashboard saved!')