Visualization (rheojax.visualization)¶
The visualization module provides publication-quality plotting functions for rheological data.
Plotting Functions¶
Core plotting functions for rheological data visualization.
This module provides publication-quality plotting utilities for rheological data, with automatic plot type selection based on data characteristics.
- rheojax.visualization.plotter.plot_rheo_data(data, style='default', **kwargs)[source]¶
Plot RheoData with automatic plot type selection.
This function automatically selects the appropriate plot type based on the data domain, test mode, and data characteristics.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes) or (Figure, array of Axes)
Examples
>>> time = np.linspace(0, 10, 100) >>> stress = 1000 * np.exp(-time / 2) >>> data = RheoData(x=time, y=stress, domain="time") >>> fig, ax = plot_rheo_data(data)
- rheojax.visualization.plotter.plot_time_domain(x, y, x_units=None, y_units=None, log_x=False, log_y=False, style='default', **kwargs)[source]¶
Plot time-domain rheological data.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes)
- rheojax.visualization.plotter.plot_frequency_domain(x, y, x_units=None, y_units=None, style='default', **kwargs)[source]¶
Plot frequency-domain rheological data (complex modulus).
For complex data, creates two subplots for G’ (storage modulus) and G’’ (loss modulus). For real data, creates a single plot.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, np.ndarray of Axes). For complex data the array has shape (2,); for real data it has shape (1,) so callers can always index the result uniformly (e.g.
axes[0]).
- rheojax.visualization.plotter.plot_flow_curve(x, y, x_units=None, y_units=None, x_label=None, y_label=None, style='default', **kwargs)[source]¶
Plot flow curve (viscosity or stress vs shear rate).
- rheojax.visualization.plotter.plot_residuals(x, residuals, y_true=None, y_pred=None, x_units=None, style='default', **kwargs)[source]¶
Plot residuals from model fitting.
If y_true and y_pred are provided, creates two subplots: one with data and predictions, and one with residuals. Otherwise, plots only residuals.
- rheojax.visualization.plotter.compute_uncertainty_band(model_fn, x_pred, popt, pcov, confidence=0.95)[source]¶
Compute prediction uncertainty band via error propagation.
Uses the formula: sigma_y(x) = sqrt(diag(J @ pcov @ J.T)) where J is the Jacobian of the model with respect to parameters.
For 95% confidence interval, the band is +/-1.96 * sigma_y(x).
- Parameters:
model_fn (
Any) – Model function that takes (x, params) and returns predictions. Must be compatible with JAX autodiff for Jacobian computation.x_pred (
ndarray) – X values for prediction (n_points,)popt (
ndarray) – Optimal parameter values (n_params,)pcov (
ndarray) – Parameter covariance matrix (n_params x n_params)confidence (
float) – Confidence level (default: 0.95 for 95% CI)
- Returns:
y_fit: Fitted values at x_pred
y_lower: Lower bound of confidence interval
y_upper: Upper bound of confidence interval
- Return type:
Example
>>> def model(x, params): ... a, b = params ... return a * x + b >>> x = np.linspace(0, 10, 50) >>> popt = np.array([2.0, 1.0]) >>> pcov = np.array([[0.01, 0.0], [0.0, 0.05]]) >>> y_fit, y_lo, y_hi = compute_uncertainty_band(model, x, popt, pcov)
Note
Complex-valued
y_fitis not supported for uncertainty bands. Ify_fitis complex, the function returns(y_fit, None, None)and logs a debug message. Callers should check forNonebefore usingy_lowerandy_upper.
- rheojax.visualization.plotter.plot_fit_with_uncertainty(x_data, y_data, x_fit, y_fit, y_lower=None, y_upper=None, log_x=True, log_y=True, data_label='Data', fit_label='Fit', band_label='95% CI', x_label=None, y_label=None, style='default', ax=None, **kwargs)[source]¶
Plot data with fitted curve and optional uncertainty band.
Creates publication-quality fit plots with: - Scatter data points - Solid fitted curve - Shaded uncertainty band (if y_lower/y_upper provided) - Legend with customizable labels
- Parameters:
x_data (
ndarray) – Experimental x valuesy_data (
ndarray) – Experimental y valuesx_fit (
ndarray) – X values for fitted curve (can be denser than data)y_fit (
ndarray) – Fitted y valuesy_lower (
ndarray|None) – Lower bound of uncertainty band (optional)y_upper (
ndarray|None) – Upper bound of uncertainty band (optional)log_x (
bool) – Use log scale for x-axis (default: True)log_y (
bool) – Use log scale for y-axis (default: True)data_label (
str) – Legend label for data pointsfit_label (
str) – Legend label for fitted curveband_label (
str) – Legend label for uncertainty bandstyle (
str) – Plot style (‘default’, ‘publication’, ‘presentation’)**kwargs (
Any) – Additional arguments passed to scatter/plot
- Return type:
- Returns:
Tuple of (Figure, Axes). Figure is None if ax was provided.
Example
>>> x = np.logspace(-1, 2, 20) >>> y = 100 * x ** -0.5 + np.random.randn(20) * 5 >>> x_fit = np.logspace(-1, 2, 100) >>> y_fit = 100 * x_fit ** -0.5 >>> fig, ax = plot_fit_with_uncertainty(x, y, x_fit, y_fit)
- rheojax.visualization.plotter.save_figure(fig, filepath, format=None, dpi=300, bbox_inches='tight', **kwargs)[source]¶
Save matplotlib figure to file with publication-quality defaults.
This convenience function wraps matplotlib’s savefig() with sensible defaults for publication-quality figures, automatic format detection, and path validation.
- Parameters:
fig (
Figure) – Figure object to savefilepath (
str|Path) – Output file path. Format inferred from extension if not specified.format (
str|None) – File format. Supported: ‘pdf’, ‘svg’, ‘png’, ‘eps’, ‘tiff’, ‘jpg’, ‘webp’. Auto-detected from file extension if None.dpi (
int) – Resolution for raster formats (PNG). Ignored for vector formats (PDF, SVG, EPS). Common values: - 150: Draft quality - 300: Publication quality (default) - 600: High-resolution printbbox_inches (
str) – Bounding box adjustment. ‘tight’ removes extra whitespace around figure.**kwargs (
Any) – Additional keyword arguments passed to matplotlib’s savefig(). Common options: - transparent : bool - Transparent background (default False) - facecolor : color - Figure background color - edgecolor : color - Figure edge color - pad_inches : float - Padding around figure
- Returns:
Absolute path to saved file (for confirmation/logging)
- Return type:
- Raises:
ValueError – If format cannot be inferred from filepath or is unsupported
OSError – If filepath directory doesn’t exist or lacks write permissions
Examples
Save figure to PDF with defaults:
>>> fig, ax = plot_rheo_data(data) >>> save_figure(fig, 'analysis.pdf') PosixPath('/path/to/analysis.pdf')
Save PNG with high resolution:
>>> save_figure(fig, 'figure.png', dpi=600) PosixPath('/path/to/figure.png')
Save SVG with transparent background:
>>> save_figure(fig, 'diagram.svg', transparent=True) PosixPath('/path/to/diagram.svg')
Explicit format specification:
>>> save_figure(fig, 'output', format='pdf') PosixPath('/path/to/output.pdf')
See also
plot_rheo_dataAutomatic plot type selection
Pipeline.save_figureFluent API integration
Notes
Supported formats: - PDF: Vector format, ideal for publications and LaTeX documents - SVG: Vector format, editable in Inkscape/Illustrator - PNG: Raster format, good for presentations and web - EPS: Vector format, legacy publication format - TIFF: Raster format, lossless, common in scientific publishing - JPG/JPEG: Raster format, lossy, good for photos - WEBP: Raster format, modern lossy/lossless, good for web
DPI only affects raster formats (PNG, TIFF, JPG, WEBP). Vector formats (PDF, SVG, EPS) are resolution-independent.
Main Plotting Function¶
- rheojax.visualization.plotter.plot_rheo_data(data, style='default', **kwargs)[source]
Plot RheoData with automatic plot type selection.
This function automatically selects the appropriate plot type based on the data domain, test mode, and data characteristics.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes) or (Figure, array of Axes)
Examples
>>> time = np.linspace(0, 10, 100) >>> stress = 1000 * np.exp(-time / 2) >>> data = RheoData(x=time, y=stress, domain="time") >>> fig, ax = plot_rheo_data(data)
Main entry point for plotting RheoData with automatic plot type selection.
Plot type selection logic:
Frequency domain or oscillation test ->
plot_frequency_domain()Rotation test or shear rate units ->
plot_flow_curve()Time domain ->
plot_time_domain()
Specialized Plot Types¶
- rheojax.visualization.plotter.plot_time_domain(x, y, x_units=None, y_units=None, log_x=False, log_y=False, style='default', **kwargs)[source]
Plot time-domain rheological data.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes)
Plot time-domain data (relaxation, creep).
- rheojax.visualization.plotter.plot_frequency_domain(x, y, x_units=None, y_units=None, style='default', **kwargs)[source]
Plot frequency-domain rheological data (complex modulus).
For complex data, creates two subplots for G’ (storage modulus) and G’’ (loss modulus). For real data, creates a single plot.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, np.ndarray of Axes). For complex data the array has shape (2,); for real data it has shape (1,) so callers can always index the result uniformly (e.g.
axes[0]).
Plot frequency-domain data (oscillatory tests).
For complex data (G*), creates two subplots for \(G'\) and \(G''\). For real data, creates a single plot.
- rheojax.visualization.plotter.plot_flow_curve(x, y, x_units=None, y_units=None, x_label=None, y_label=None, style='default', **kwargs)[source]
Plot flow curve (viscosity or stress vs shear rate).
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes)
Plot flow curves (viscosity or stress vs shear rate).
- rheojax.visualization.plotter.plot_residuals(x, residuals, y_true=None, y_pred=None, x_units=None, style='default', **kwargs)[source]
Plot residuals from model fitting.
If y_true and y_pred are provided, creates two subplots: one with data and predictions, and one with residuals. Otherwise, plots only residuals.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes) or (Figure, array of Axes)
Plot residuals from model fitting.
If y_true and y_pred are provided, creates two subplots. Otherwise, plots residuals only.
Plotting Styles¶
Three built-in styles for different contexts:
- rheojax.visualization.plotter.DEFAULT_STYLE¶
General-purpose style for interactive work.
Figure size: 8x6 inches
Font size: 11 pt
Line width: 1.5 pt
- rheojax.visualization.plotter.PUBLICATION_STYLE¶
Optimized for journal publications.
Figure size: 6x4.5 inches
Font size: 10 pt
Line width: 1.2 pt
Smaller markers
- rheojax.visualization.plotter.PRESENTATION_STYLE¶
Large, clear plots for presentations.
Figure size: 10x7 inches
Font size: 14 pt
Line width: 2.0 pt
Larger markers
Templates¶
Plot templates for common rheological visualizations.
This module provides template-based plotting functions for standard rheological plots including stress-strain, modulus-frequency, and mastercurve plots.
- rheojax.visualization.templates.plot_stress_strain(data, style='default', **kwargs)[source]¶
Plot stress-strain or time-dependent rheological data.
This template is designed for relaxation and creep tests, plotting stress or strain versus time.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes)
Examples
>>> time = np.linspace(0, 100, 200) >>> stress = 1000 * np.exp(-time / 20) >>> data = RheoData(x=time, y=stress, domain="time") >>> fig, ax = plot_stress_strain(data)
- rheojax.visualization.templates.plot_modulus_frequency(data, separate_axes=True, style='default', **kwargs)[source]¶
Plot storage and loss modulus versus frequency.
This template is designed for oscillatory (SAOS) test data, plotting G’ and G’’ versus frequency on log-log axes.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes) or (Figure, array of Axes)
Examples
>>> frequency = np.logspace(-2, 2, 50) >>> G_complex = 1e5 / (1 + 1j * frequency) >>> data = RheoData(x=frequency, y=G_complex, domain="frequency") >>> fig, axes = plot_modulus_frequency(data)
- rheojax.visualization.templates.plot_mastercurve(datasets, reference_temp=None, shift_factors=None, show_shifts=False, style='default', **kwargs)[source]¶
Plot mastercurve from multiple temperature datasets.
This template creates a time-temperature superposition plot, overlaying data from multiple temperatures with optional shift factors.
- Parameters:
datasets (
list[RheoData]) – List of RheoData objects at different temperaturesreference_temp (
float|None) – Reference temperature (if None, uses first dataset)shift_factors (
dict[float,float] |None) – Dictionary mapping temperature to shift factorshow_shifts (
bool) – If True, display shift factors in legendstyle (
str) – Plotting style**kwargs (
Any) – Additional keyword arguments for matplotlib
- Return type:
- Returns:
Tuple of (Figure, Axes)
Examples
>>> datasets = [] >>> for temp in [20, 25, 30]: ... freq = np.logspace(-2, 2, 50) ... G = 1e5 / (1 + 1j * freq) ... datasets.append(RheoData(x=freq, y=G, metadata={'temperature': temp})) >>> fig, ax = plot_mastercurve(datasets)
- rheojax.visualization.templates.plot_model_fit(data, predictions, show_residuals=True, style='default', model_name=None, **kwargs)[source]¶
Plot experimental data with model predictions and residuals.
This template creates a standard model fitting visualization showing data, model predictions, and optionally residuals.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes) or (Figure, array of Axes)
Examples
>>> freq = np.logspace(-2, 2, 50) >>> G_data = 1e5 / (1 + 1j * freq) >>> G_pred = G_data * 1.02 # Slight variation >>> data = RheoData(x=freq, y=G_data, domain="frequency") >>> fig, axes = plot_model_fit(data, G_pred)
- rheojax.visualization.templates.apply_template_style(ax, style='default', **kwargs)[source]¶
Apply template styling to an existing axis.
This function applies consistent styling to matplotlib axes based on the selected template style.
- Parameters:
- Return type:
Examples
>>> fig, ax = plt.subplots() >>> ax.plot([1, 2, 3], [1, 2, 3]) >>> apply_template_style(ax, style='publication')
The templates module provides reusable plot templates for common visualization tasks.
EPM Visualization¶
Visualization tools for Lattice Elasto-Plastic Models.
- rheojax.visualization.epm_plots.plot_lattice_fields(stress, thresholds, title=None, figsize=None, cmap_stress='coolwarm', cmap_thresh='viridis')[source]¶
Plot EPM lattice fields with auto-detection of scalar vs tensorial stress.
Automatically detects whether stress is scalar (L, L) or tensorial (3, L, L) and dispatches to the appropriate plotting function.
- Parameters:
stress (
ndarray|Array) – Either (L, L) scalar or (3, L, L) tensorial stress field.thresholds (
ndarray|Array) – 2D array of local yield thresholds (L, L).title (
str|None) – Overall figure title (auto-generated if None).figsize (
tuple[int,int] |None) – Figure size (width, height) (auto-selected if None).cmap_stress (
str) – Colormap for stress field (diverging).cmap_thresh (
str) – Colormap for threshold field (sequential).
- Return type:
- Returns:
Matplotlib Figure object.
- Raises:
ValueError – If stress shape is invalid.
- rheojax.visualization.epm_plots.animate_stress_evolution(stress_history, interval=50, cmap='coolwarm', save_path=None)[source]¶
Create an animation of the stress field evolution.
- Parameters:
- Return type:
- Returns:
Matplotlib FuncAnimation object.
- rheojax.visualization.epm_plots.plot_tensorial_fields(stress, figsize=(15, 4), cmap='coolwarm', ax=None, **kwargs)[source]¶
Plot all three stress tensor components in a 3-panel layout.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, list of 3 Axes).
- rheojax.visualization.epm_plots.plot_normal_stress_field(stress, nu=0.5, figsize=(6, 5), cmap='coolwarm', ax=None, **kwargs)[source]¶
Plot first normal stress difference field N₁ = σ_xx - σ_yy.
- Parameters:
- Return type:
- Returns:
Tuple of (Figure, Axes).
- rheojax.visualization.epm_plots.plot_von_mises_field(stress, thresholds, nu=0.5, figsize=(12, 5), ax=None, **kwargs)[source]¶
Plot von Mises effective stress and normalized yield map.
Creates a 2-panel figure:
Left: σ_eff with viridis (sequential)
Right: σ_eff/σ_c with RdYlGn_r centered at 1 (Green <1: elastic, Yellow ≈1: near yield, Red >1: plastic)
- Parameters:
stress (
ndarray|Array) – Stress tensor of shape (3, L, L) with [σ_xx, σ_yy, σ_xy].thresholds (
ndarray|Array) – Yield thresholds of shape (L, L).nu (
float) – Poisson’s ratio for plane strain constraint.ax (
Axes|list[Axes] |None) – Optional pre-existing axes (2 axes required).**kwargs – Additional arguments passed to imshow.
- Return type:
- Returns:
Tuple of (Figure, list of 2 Axes).
- rheojax.visualization.epm_plots.plot_normal_stress_ratio(shear_rates, N1, sigma_xy, figsize=(8, 6), ax=None, **kwargs)[source]¶
Plot log-log of N₁/σ_xy vs shear rate.
- rheojax.visualization.epm_plots.animate_tensorial_evolution(history, component='all', interval=50, save_path=None, **kwargs)[source]¶
Create animation of tensorial stress field evolution.
- Parameters:
history (
dict[str,ndarray|Array]) – Dictionary with keys: - ‘stress’: Stress history of shape (T, 3, L, L) - ‘time’: Time array of shape (T,)component (
str) – Component to animate: - ‘all’: All 3 components (3-panel animation) - ‘xx’, ‘yy’, ‘xy’: Individual components - ‘N1’: First normal stress difference - ‘vm’: von Mises effective stressinterval (
int) – Delay between frames in milliseconds.save_path (
str|None) – If provided, save animation to this path.**kwargs – Additional arguments (e.g., nu for von Mises).
- Return type:
- Returns:
Matplotlib FuncAnimation object.
Tools for visualizing spatially heterogeneous fields in Lattice EPM simulations.
Functions¶
- rheojax.visualization.epm_plots.plot_lattice_fields(stress, thresholds, title=None, figsize=None, cmap_stress='coolwarm', cmap_thresh='viridis')[source]
Plot EPM lattice fields with auto-detection of scalar vs tensorial stress.
Automatically detects whether stress is scalar (L, L) or tensorial (3, L, L) and dispatches to the appropriate plotting function.
- Parameters:
stress (
ndarray|Array) – Either (L, L) scalar or (3, L, L) tensorial stress field.thresholds (
ndarray|Array) – 2D array of local yield thresholds (L, L).title (
str|None) – Overall figure title (auto-generated if None).figsize (
tuple[int,int] |None) – Figure size (width, height) (auto-selected if None).cmap_stress (
str) – Colormap for stress field (diverging).cmap_thresh (
str) – Colormap for threshold field (sequential).
- Return type:
- Returns:
Matplotlib Figure object.
- Raises:
ValueError – If stress shape is invalid.
Plots stress and yield threshold fields side-by-side.
- rheojax.visualization.epm_plots.animate_stress_evolution(stress_history, interval=50, cmap='coolwarm', save_path=None)[source]
Create an animation of the stress field evolution.
- Parameters:
- Return type:
- Returns:
Matplotlib FuncAnimation object.
Creates an animation of the stress field evolution over time.
Examples¶
Basic Plotting¶
Auto-Detection¶
from rheojax.core import RheoData
from rheojax.visualization import plot_rheo_data
import matplotlib.pyplot as plt
import numpy as np
# Create data
time = np.logspace(-1, 2, 50)
stress = 1000 * np.exp(-time / 5)
data = RheoData(x=time, y=stress, x_units="s", y_units="Pa", domain="time")
# Plot with automatic type detection
fig, ax = plot_rheo_data(data)
plt.show()
Using Styles¶
# Default style
fig, ax = plot_rheo_data(data, style='default')
# Publication style
fig, ax = plot_rheo_data(data, style='publication')
fig.savefig('figure.pdf', bbox_inches='tight')
# Presentation style
fig, ax = plot_rheo_data(data, style='presentation')
Time-Domain Plots¶
Stress Relaxation¶
from rheojax.visualization import plot_time_domain
time = np.logspace(-1, 2, 50)
stress = 1000 * np.exp(-time / 5)
fig, ax = plot_time_domain(
x=time,
y=stress,
x_units="s",
y_units="Pa",
log_x=True,
log_y=False,
style='publication'
)
ax.set_title("Stress Relaxation")
plt.show()
Creep Compliance¶
time = np.logspace(-1, 2, 50)
compliance = 1e-4 * (1 + time**0.5)
fig, ax = plot_time_domain(
x=time,
y=compliance,
x_units="s",
y_units="1/Pa",
log_x=True,
log_y=True,
style='publication'
)
ax.set_title("Creep Compliance")
ax.set_ylabel("J(t) (1/Pa)")
plt.show()
Frequency-Domain Plots¶
Complex Modulus¶
from rheojax.visualization import plot_frequency_domain
# Complex modulus
omega = np.logspace(-2, 2, 50)
Gp = 1000 * omega**0.5 # G'
Gpp = 500 * omega**0.3 # G"
G_star = Gp + 1j * Gpp
fig, axes = plot_frequency_domain(
x=omega,
y=G_star,
x_units="rad/s",
y_units="Pa",
style='publication'
)
# axes[0] is for G', axes[1] is for G"
axes[0].set_title("Storage Modulus")
axes[1].set_title("Loss Modulus")
plt.show()
Single Modulus¶
# Plot only G'
fig, axes = plot_frequency_domain(
x=omega,
y=Gp, # Real values
x_units="rad/s",
y_units="Pa"
)
# axes is a list with single element
axes[0].set_title("Storage Modulus")
plt.show()
Flow Curves¶
Viscosity vs Shear Rate¶
from rheojax.visualization import plot_flow_curve
shear_rate = np.logspace(-2, 3, 50)
viscosity = 100 * shear_rate**(-0.7) # Shear thinning
fig, ax = plot_flow_curve(
x=shear_rate,
y=viscosity,
x_units="1/s",
y_units="Pa.s",
x_label="Shear Rate (1/s)",
y_label="Viscosity (Pa·s)",
style='publication'
)
ax.set_title("Flow Curve")
plt.show()
Stress vs Shear Rate¶
stress = 50 * shear_rate**0.5 # Shear thickening
fig, ax = plot_flow_curve(
x=shear_rate,
y=stress,
x_units="1/s",
y_units="Pa",
y_label="Shear Stress (Pa)",
style='publication'
)
Residual Plots¶
With Data Comparison¶
from rheojax.visualization import plot_residuals
# Experimental and predicted data
time = np.linspace(0, 10, 50)
stress_true = 1000 * np.exp(-time / 5)
stress_pred = 980 * np.exp(-time / 4.8)
residuals = stress_true - stress_pred
fig, axes = plot_residuals(
x=time,
residuals=residuals,
y_true=stress_true,
y_pred=stress_pred,
x_units="s",
style='publication'
)
# axes[0]: Data and predictions
# axes[1]: Residuals
axes[0].set_title("Model Fit")
axes[1].set_title("Residuals")
plt.show()
Residuals Only¶
fig, ax = plot_residuals(
x=time,
residuals=residuals,
x_units="s"
)
ax.set_title("Residuals")
plt.show()
Customization¶
Matplotlib Keyword Arguments¶
All plotting functions accept matplotlib kwargs:
fig, ax = plot_time_domain(
x=time,
y=stress,
color='red',
marker='s',
markersize=8,
linestyle='--',
label='Experimental',
alpha=0.7
)
ax.legend()
Advanced Styling¶
import matplotlib.pyplot as plt
# Custom figure size
fig, ax = plt.subplots(figsize=(10, 6))
# Manual plotting with rheojax data
ax.semilogy(data.x, data.y, 'o-', label='Data')
# Customize
ax.set_xlabel('Time (s)', fontsize=14, fontweight='bold')
ax.set_ylabel('Stress (Pa)', fontsize=14, fontweight='bold')
ax.set_title('Custom Plot', fontsize=16)
ax.grid(True, which='both', linestyle=':', alpha=0.5)
ax.legend(fontsize=12)
fig.tight_layout()
Multi-Panel Figures¶
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Top-left: Relaxation
axes[0, 0].semilogx(time, stress, 'o-')
axes[0, 0].set_ylabel('Stress (Pa)')
axes[0, 0].set_title('Relaxation')
# Top-right: Creep
axes[0, 1].loglog(time, compliance, 's-')
axes[0, 1].set_ylabel('Compliance (1/Pa)')
axes[0, 1].set_title('Creep')
# Bottom-left: Oscillatory
axes[1, 0].loglog(omega, Gp, 'o-', label="G'")
axes[1, 0].loglog(omega, Gpp, 's-', label='G"')
axes[1, 0].set_xlabel('omega (rad/s)')
axes[1, 0].set_ylabel('Modulus (Pa)')
axes[1, 0].legend()
# Bottom-right: Flow curve
axes[1, 1].loglog(shear_rate, viscosity, '^-')
axes[1, 1].set_xlabel('Shear Rate (1/s)')
axes[1, 1].set_ylabel('Viscosity (Pa·s)')
fig.tight_layout()
Saving Figures¶
Raster Formats¶
# PNG - high resolution
fig.savefig('figure.png', dpi=300, bbox_inches='tight')
# JPEG - smaller file
fig.savefig('figure.jpg', dpi=150, quality=95)
Vector Formats¶
# PDF - best for publications
fig.savefig('figure.pdf', bbox_inches='tight')
# SVG - editable
fig.savefig('figure.svg', bbox_inches='tight')
# EPS - for some journals
fig.savefig('figure.eps', bbox_inches='tight')
Multiple Formats¶
# Save in all formats
for fmt in ['png', 'pdf', 'svg']:
fig.savefig(f'figure.{fmt}', dpi=300, bbox_inches='tight')
Color and Markers¶
Colors¶
# Matplotlib colors
ax.plot(x, y, color='C0') # Default color cycle
ax.plot(x, y, color='red') # Named color
ax.plot(x, y, color='#1f77b4') # Hex color
ax.plot(x, y, color=(0.2, 0.4, 0.6)) # RGB tuple
# Colormaps
colors = plt.cm.viridis(np.linspace(0, 1, n_datasets))
Markers¶
# Common markers
ax.plot(x, y, 'o-') # Circles
ax.plot(x, y, 's-') # Squares
ax.plot(x, y, '^-') # Triangles
ax.plot(x, y, 'D-') # Diamonds
# Empty markers
ax.plot(x, y, 'o', markerfacecolor='none', markeredgecolor='blue')
Annotations¶
# Text
ax.text(x=5, y=500, s='Important region',
fontsize=12, ha='center', va='center')
# Arrow annotation
ax.annotate(
text='Transition',
xy=(10, 800),
xytext=(15, 900),
arrowprops=dict(arrowstyle='->', color='red')
)
# Lines
ax.axhline(y=500, color='r', linestyle='--')
ax.axvline(x=10, color='g', linestyle=':')
# Regions
ax.axvspan(xmin=5, xmax=15, alpha=0.2, color='yellow')
Best Practices¶
Publication Quality¶
# Use publication style
fig, ax = plot_rheo_data(data, style='publication')
# Save at 300 DPI
fig.savefig('figure.pdf', dpi=300, bbox_inches='tight')
# Use consistent fonts
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = ['Arial']
plt.rcParams['pdf.fonttype'] = 42 # TrueType fonts
Readability¶
# Clear labels with units
ax.set_xlabel('Time (s)', fontsize=12)
ax.set_ylabel('Stress (Pa)', fontsize=12)
# Grid for easier reading
ax.grid(True, which='both', alpha=0.3, linestyle='--')
# Legend when multiple series
ax.legend(fontsize=10, framealpha=0.9)
Colorblind-Friendly¶
# Use distinguishable colors
colors = ['#0173B2', '#DE8F05', '#029E73'] # Blue, orange, green
# Or use different markers
markers = ['o', 's', '^']
for i, (x, y) in enumerate(datasets):
ax.plot(x, y, marker=markers[i], color=colors[i])
See Also¶
../user_guide/visualization_guide - Comprehensive visualization guide
Core Module (rheojax.core) - RheoData structure
Matplotlib documentation - Advanced plotting
Matplotlib gallery - Examples