| name | matplotlib-visualization |
| description | Create pump performance curves, velocity contours, and engineering plots |
| category | packages |
| domain | general |
| complexity | basic |
| dependencies | ["matplotlib","numpy"] |
Matplotlib Visualization for Engineering
Create professional engineering plots including pump performance curves, CFD results visualization, velocity contours, and publication-quality figures.
Installation and Setup
pip install matplotlib numpy scipy
Basic import pattern:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
plt.style.use('seaborn-v0_8-darkgrid')
Common Plot Types for Engineering
Pump Performance Curves (H-Q, P-Q, η-Q)
Standard pump characteristic curves showing head, power, and efficiency vs flow rate:
import matplotlib.pyplot as plt
import numpy as np
Q = np.linspace(0, 120, 50)
H = 80 - 0.005 * Q**2
P = 5 + 0.08 * Q + 0.0005 * Q**2
eta = (Q * H) / (367 * P) * 100
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(10, 10), sharex=True)
ax1.plot(Q, H, 'b-', linewidth=2, label='Head curve')
ax1.set_ylabel('Head [m]', fontsize=12)
ax1.set_title('Pump Performance Curves', fontsize=14, fontweight='bold')
ax1.grid(True, alpha=0.3)
ax1.legend()
ax2.plot(Q, P, 'r-', linewidth=2, label='Power curve')
ax2.set_ylabel('Power [kW]', fontsize=12)
ax2.grid(True, alpha=0.3)
ax2.legend()
ax3.plot(Q, eta, 'g-', linewidth=2, label='Efficiency curve')
ax3.set_xlabel('Flow Rate [m³/h]', fontsize=12)
ax3.set_ylabel('Efficiency [%]', fontsize=12)
ax3.grid(True, alpha=0.3)
ax3.legend()
plt.tight_layout()
plt.savefig('pump_curves.png', dpi=300, bbox_inches='tight')
plt.show()
System Curves
Plot pump curve with system curve overlay to find operating point:
Q = np.linspace(0, 120, 50)
H_pump = 80 - 0.005 * Q**2
H_static = 20
k = 0.003
H_system = H_static + k * Q**2
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(Q, H_pump, 'b-', linewidth=2, label='Pump curve')
ax.plot(Q, H_system, 'r--', linewidth=2, label='System curve')
idx = np.argmin(np.abs(H_pump - H_system))
ax.plot(Q[idx], H_pump[idx], 'ko', markersize=10, label=f'Operating point\n({Q[idx]:.1f} m³/h, {H_pump[idx]:.1f} m)')
ax.set_xlabel('Flow Rate [m³/h]', fontsize=12)
ax.set_ylabel('Head [m]', fontsize=12)
ax.set_title('Pump and System Curves', fontsize=14, fontweight='bold')
ax.grid(True, alpha=0.3)
ax.legend(fontsize=10)
plt.tight_layout()
plt.savefig('system_curve.png', dpi=300, bbox_inches='tight')
plt.show()
Velocity/Pressure Contours
Visualize CFD results with contour plots:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.linspace(0, 5, 50)
X, Y = np.meshgrid(x, y)
U = 2.0 - 1.5 * np.exp(-((X-3)**2 + (Y-2.5)**2) / 2)
V = 0.5 * np.sin(np.pi * X / 5) * np.exp(-((X-3)**2 + (Y-2.5)**2) / 4)
velocity = np.sqrt(U**2 + V**2)
fig, ax = plt.subplots(figsize=(12, 6))
levels = np.linspace(velocity.min(), velocity.max(), 20)
contourf = ax.contourf(X, Y, velocity, levels=levels, cmap='jet')
cbar = plt.colorbar(contourf, ax=ax, label='Velocity [m/s]')
contour = ax.contour(X, Y, velocity, levels=10, colors='k', linewidths=0.5, alpha=0.4)
ax.clabel(contour, inline=True, fontsize=8, fmt='%.2f')
ax.set_xlabel('x [m]', fontsize=12)
ax.set_ylabel('y [m]', fontsize=12)
ax.set_title('Velocity Contour Plot', fontsize=14, fontweight='bold')
ax.set_aspect('equal')
plt.tight_layout()
plt.savefig('velocity_contour.png', dpi=300, bbox_inches='tight')
plt.show()
Vector Fields
Display flow direction and magnitude:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 20)
y = np.linspace(0, 5, 10)
X, Y = np.meshgrid(x, y)
U = 2.0 - 1.5 * np.exp(-((X-3)**2 + (Y-2.5)**2) / 2)
V = 0.5 * np.sin(np.pi * X / 5) * np.exp(-((X-3)**2 + (Y-2.5)**2) / 4)
velocity = np.sqrt(U**2 + V**2)
fig, ax = plt.subplots(figsize=(12, 6))
quiver = ax.quiver(X, Y, U, V, velocity, cmap='viridis', scale=30, width=0.003)
cbar = plt.colorbar(quiver, ax=ax, label='Velocity magnitude [m/s]')
ax.set_xlabel('x [m]', fontsize=12)
ax.set_ylabel('y [m]', fontsize=12)
ax.set_title('Velocity Vector Field', fontsize=14, fontweight='bold')
ax.set_aspect('equal')
plt.tight_layout()
plt.savefig('velocity_vectors.png', dpi=300, bbox_inches='tight')
plt.show()
3D Surface Plots
Visualize pressure or temperature distributions:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = 100 + 10 * np.exp(-0.1 * (X**2 + Y**2)) * np.cos(0.5 * np.sqrt(X**2 + Y**2))
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap='coolwarm', linewidth=0, antialiased=True, alpha=0.9)
ax.set_xlabel('x [m]', fontsize=11)
ax.set_ylabel('y [m]', fontsize=11)
ax.set_zlabel('Pressure [kPa]', fontsize=11)
ax.set_title('Pressure Distribution', fontsize=14, fontweight='bold', pad=20)
cbar = fig.colorbar(surf, ax=ax, shrink=0.5, aspect=5, label='Pressure [kPa]')
ax.view_init(elev=25, azim=45)
plt.tight_layout()
plt.savefig('pressure_3d.png', dpi=300, bbox_inches='tight')
plt.show()
Subplots and Multi-Panel Figures
Complex layouts for comprehensive analysis:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(14, 10))
gs = fig.add_gridspec(2, 2, hspace=0.3, wspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
x = np.linspace(0, 100, 100)
y1 = 80 - 0.005 * x**2
ax1.plot(x, y1, 'b-', linewidth=2)
ax1.set_xlabel('Flow Rate [m³/h]')
ax1.set_ylabel('Head [m]')
ax1.set_title('(a) Pump Curve')
ax1.grid(True, alpha=0.3)
ax2 = fig.add_subplot(gs[0, 1])
x = np.linspace(0, 10, 50)
y = np.linspace(0, 5, 25)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
contourf = ax2.contourf(X, Y, Z, levels=15, cmap='RdBu_r')
plt.colorbar(contourf, ax=ax2, label='Value')
ax2.set_xlabel('x [m]')
ax2.set_ylabel('y [m]')
ax2.set_title('(b) Contour Plot')
ax3 = fig.add_subplot(gs[1, 0])
categories = ['Case 1', 'Case 2', 'Case 3', 'Case 4']
values = [75, 82, 68, 91]
bars = ax3.bar(categories, values, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])
ax3.set_ylabel('Efficiency [%]')
ax3.set_title('(c) Performance Comparison')
ax3.grid(True, axis='y', alpha=0.3)
ax4 = fig.add_subplot(gs[1, 1])
x_data = np.random.rand(50) * 100
y_data = 30 + 0.5 * x_data + np.random.randn(50) * 5
ax4.scatter(x_data, y_data, alpha=0.6, s=50)
z = np.polyfit(x_data, y_data, 1)
p = np.poly1d(z)
ax4.plot(x_data, p(x_data), 'r--', linewidth=2, label=f'y={z[0]:.2f}x+{z[1]:.2f}')
ax4.set_xlabel('Parameter X')
ax4.set_ylabel('Parameter Y')
ax4.set_title('(d) Correlation Analysis')
ax4.legend()
ax4.grid(True, alpha=0.3)
plt.suptitle('Multi-Panel Engineering Analysis', fontsize=16, fontweight='bold', y=0.995)
plt.savefig('multipanel.png', dpi=300, bbox_inches='tight')
plt.show()
Styling for Professional Figures
Using Style Sheets
import matplotlib.pyplot as plt
print(plt.style.available)
plt.style.use('seaborn-v0_8-whitegrid')
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.size'] = 11
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['grid.alpha'] = 0.3
Custom Colors and Styling
colors_engineering = {
'blue': '#0072BD',
'red': '#D95319',
'yellow': '#EDB120',
'purple': '#7E2F8E',
'green': '#77AC30',
'cyan': '#4DBEEE',
'maroon': '#A2142F'
}
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y1, color=colors_engineering['blue'], linewidth=2.5, label='Series 1')
ax.plot(x, y2, color=colors_engineering['red'], linewidth=2.5, label='Series 2')
LaTeX in Labels
Enable LaTeX rendering for mathematical expressions:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['text.usetex'] = False
plt.rcParams['mathtext.fontset'] = 'cm'
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 100, 100)
y = 80 - 0.005 * x**2
ax.plot(x, y, 'b-', linewidth=2)
ax.set_xlabel(r'Flow Rate $Q$ [m$^3$/h]', fontsize=13)
ax.set_ylabel(r'Head $H$ [m]', fontsize=13)
ax.set_title(r'Pump Curve: $H = H_0 - k Q^2$', fontsize=14, fontweight='bold')
ax.text(50, 60, r'$\eta = \frac{Q \cdot H \cdot \rho \cdot g}{P_{shaft}}$',
fontsize=16, bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Common Engineering Symbols
Saving High-Resolution Plots
Different Formats
plt.savefig('figure.png', dpi=300, bbox_inches='tight', facecolor='white')
plt.savefig('figure.pdf', bbox_inches='tight', facecolor='white')
plt.savefig('figure.svg', bbox_inches='tight', facecolor='white')
plt.savefig('figure.eps', format='eps', bbox_inches='tight')
plt.savefig('figure.tiff', dpi=600, bbox_inches='tight', facecolor='white')
DPI Recommendations
- Screen display: 72-96 DPI
- Presentations: 150 DPI
- Print/Publication: 300-600 DPI
- Posters: 150-300 DPI (depends on viewing distance)
Figure Size Guidelines
fig, ax = plt.subplots(figsize=(3.5, 2.5))
fig, ax = plt.subplots(figsize=(7, 5))
fig, ax = plt.subplots(figsize=(12, 6.75))
fig, ax = plt.subplots(figsize=(10, 7.5))
fig, ax = plt.subplots(figsize=(14, 10))
Best Practices
- Always label axes with units in square brackets:
[m/s], [kPa], [°C]
- Use consistent colors across related figures
- Add legends when plotting multiple series
- Use grid lines with low alpha (0.3) for readability
- Set appropriate line widths (2-2.5 for main plots)
- Choose appropriate colormaps:
- Sequential:
viridis, plasma, inferno (general data)
- Diverging:
RdBu_r, coolwarm (data with critical midpoint)
- Qualitative:
tab10, Set1 (categorical data)
- Use
tight_layout() or bbox_inches='tight' to avoid clipped labels
- Save before show() - showing might clear the figure
- Close figures after saving to free memory:
plt.close()
- For CFD results, consider logarithmic scales for quantities spanning orders of magnitude
Quick Reference
fig, ax = plt.subplots(figsize=(width, height))
ax.plot(x, y, 'b-', linewidth=2, label='Label', marker='o', markersize=5)
ax.scatter(x, y, c=colors, s=sizes, alpha=0.6, cmap='viridis')
contourf = ax.contourf(X, Y, Z, levels=20, cmap='jet')
plt.colorbar(contourf, ax=ax, label='Label')
quiver = ax.quiver(X, Y, U, V, scale=50)
ax.set_xlabel('Label [unit]', fontsize=12)
ax.set_ylabel('Label [unit]', fontsize=12)
ax.set_title('Title', fontsize=14, fontweight='bold')
ax.grid(True, alpha=0.3)
ax.legend(loc='best', fontsize=10)
ax.set_xlim([xmin, xmax])
ax.set_ylim([ymin, ymax])
ax.set_xscale('log')
ax.set_yscale('log')
plt.tight_layout()
plt.savefig('figure.png', dpi=300, bbox_inches='tight')
plt.show()
See Also