Matplotlib figure gallery

Six ways to show scientific evidence

Author

Soorathep Kheawhom

Back to the course · Week 9 slides · Download the notebook and complete code

These Chemical Engineering examples use synthetic data. Choose a plot that answers your question, then make the observations, units and uncertainty easy to read. The gallery uses different data from the main reaction-case lab.

You do not need to write every plot from scratch. Open the supplied notebook, run one example, change a label or axis limit, and see what happens. The full Matplotlib code is included.

1. Time series with an SD band

Compare how a response evolves and show between-run spread without hiding the time course.

Two synthetic conversion curves rise from zero. The modified condition rises faster and approaches a higher plateau than the baseline. Sand bands show one standard deviation across eight runs.

Synthetic step responses. Lines show the mean of eight independent simulated runs per condition; sand bands show ±1 sample SD at each time. They are not confidence intervals.

fig, metadata = gallery.make_time_response(output_dir=output)
plt.show()

X(t) = X_inf [1 - exp(-t/tau)]. Baseline X_inf=78%, tau=13 min; modified X_inf=92%, tau=9 min. Each run perturbs X_inf (2.5% SD), tau (6% SD), and adds 0.55-percentage-point observation noise scaled to zero at t=0.

2. Raw observations and a summary

Show replicate counts, spread, possible unusual observations, and the summary on one chart.

Eight dots at each of four temperatures with overlaid mean diamonds and standard-deviation whiskers. Synthetic conversion increases from approximately 40% to 80%.

Synthetic conversion at four temperature settings, eight runs per setting. Horizontal dot jitter only prevents overlap; diamonds show means and whiskers show ±1 sample SD.

fig, metadata = gallery.make_raw_points_sd(output_dir=output)
plt.show()

Eight normal draws at each setting: mean conversion=[40,55,70,80]% and generating SD=[2,2.5,3,3.5] percentage points at T=[300,325,350,375] °C. Displayed statistics are computed from the draws.

3. Predictions against observations

Inspect prediction errors and whether they vary with an operating condition. A high correlation alone does not establish agreement.

Predicted versus observed synthetic conversion with equal zero-to-100 axes, a dashed identity line, and points colored continuously by temperature from 300 to 400 degrees Celsius.

Synthetic observed and predicted conversion for 52 operating points. Equal axis scales and the graphite identity line reveal agreement. Point color encodes temperature on a continuous ramp; this is an illustration, not model validation. RMSE is the root mean squared prediction error, shown in percentage points (pp).

fig, metadata = gallery.make_parity_temperature(output_dir=output)
plt.show()

Latent X=100[1-exp(-k(T)*tau)], k(T)=0.20 exp(0.015(T-350)) min^-1. Observed X adds N(0,2.2) percentage points. Predicted X=0.97X+1.5+N(0,1.4), clipped to physical bounds. T~U(300,400) °C and tau~U(1,8) min.

4. A heatmap of operating conditions

Compare a measured or calculated grid and locate broad patterns across two factors without hiding exact values.

An amber sequential heatmap of synthetic conversion across six temperature settings and eight residence times. Conversion increases toward the high-temperature, long-residence corner.

Synthetic conversion at 48 operating settings. Cell labels round the model output to whole percentages; the color scale is fixed at 0–100%. The six temperature rows and eight residence-time columns are discrete settings.

fig, metadata = gallery.make_operating_heatmap(output_dir=output)
plt.show()

X(T,tau)=100[1-exp(-0.20 exp(0.015(T-350))*tau)]. Temperature: 300,320,…,400 °C; residence time: 1,2,…,8 min. Illustrative model with no experimental noise.

5. Contours of equal response

Explore tradeoffs between two continuous operating variables and follow equal-response combinations within a justified model domain.

A smooth amber contour map with labeled lines at 20%, 40%, 60%, 80%, and 90% synthetic conversion. Higher temperature can produce the same model conversion at shorter residence time.

The same synthetic model and 0–100% color scale as the heatmap, evaluated on a fine grid. Labeled contours connect equal conversion. Smooth regions reflect the assumed model, not additional measurements.

fig, metadata = gallery.make_response_contours(output_dir=output)
plt.show()

Identical equation to 04_operating_heatmap, evaluated at 101 temperatures from 300 to 400 °C and 113 residence times from 1 to 8 min. No extrapolation beyond that displayed domain.

6. Distributions beyond the mean

Compare centers, spread, and distribution shape while keeping sample sizes and observations visible. A violin is descriptive, not a test of significance.

Three catalyst distributions, shown as teal, amber, and rust violins with raw points and small box plots. The modified group is relatively narrow; the alternative group has a broader synthetic spread.

Thirty synthetic selectivity values per catalyst. Dots are individual runs; violin width is a smoothed density. Boxes span the interquartile range with a median line; whiskers extend to the most extreme points within 1.5 IQR. The y-axis starts at 45%, as labeled.

fig, metadata = gallery.make_catalyst_distributions(output_dir=output)
plt.show()

Thirty draws from normal distributions with mean=[72,81,83]% and SD=[5,3,7] percentage points for A/B/C, clipped to 0–100%. Gaussian KDE bandwidth factor 0.55; horizontal jitter has no scientific meaning.

Your first change

Run the setup cell in the supplied notebook, then try this:

fig, metadata = gallery.make_time_response(output_dir=output)
ax = fig.axes[0]
ax.set_title("My process-response figure", loc="left")
ax.set_xlim(0, 40)
fig.savefig(output / "my_response.pdf", bbox_inches="tight")
plt.show()

The axis change does not change the data. Check how it changes what the reader notices.

Download all six reproducible examples