Plots

compute_diagnostics

openpkpd.plots.diagnostics.compute_diagnostics(population_model, result)[source]

Compute diagnostic DataFrame from a fitted model.

Parameters:
  • population_model (PopulationModel) – Assembled PopulationModel with dataset.

  • result (EstimationResult) – EstimationResult from model.fit().

Return type:

DataFrame

Returns:

DataFrame with ID, TIME, DV, PRED, IPRED, RES, IRES, WRES, IWRES, CWRES, ETA1..ETAn, MDV, EVID, and any covariate columns. Only rows with EVID=0 and MDV=0 are included.

GOF plots

openpkpd.plots.gof.diagnostic_panel(diag_df, *, figsize=(18, 9), title='Diagnostic Panel')[source]

2×4 combined panel of all 7 GOF plots (includes CWRES histogram).

Parameters:
openpkpd.plots.gof.dv_vs_ipred(diag_df, *, log_scale=False, ax=None, title='DV vs IPRED')[source]

Scatter plot of DV vs IPRED with identity line.

Parameters:
openpkpd.plots.gof.dv_vs_pred(diag_df, *, log_scale=False, ax=None, title='DV vs PRED')[source]

Scatter plot of DV vs PRED with identity line.

Parameters:
openpkpd.plots.gof.cwres_vs_time(diag_df, *, ax=None, title='CWRES vs TIME')[source]

CWRES scatter vs TIME with zero line and ±2 bands.

Parameters:
openpkpd.plots.gof.cwres_vs_pred(diag_df, *, ax=None, title='CWRES vs PRED')[source]

CWRES scatter vs PRED with zero line and ±2 bands.

Parameters:
openpkpd.plots.gof.cwres_qq(diag_df, *, ax=None, title='CWRES Q-Q Plot')[source]

Q-Q normal probability plot of CWRES.

Parameters:
openpkpd.plots.gof.abs_iwres_vs_ipred(diag_df, *, ax=None, title='|IWRES| vs IPRED')[source]

Absolute IWRES scatter versus IPRED.

Parameters:

openpkpd.plots.gof_panel is a convenience alias for diagnostic_panel(), the seven-panel goodness-of-fit figure.

PK plots

openpkpd.plots.pk.spaghetti_plot(diag_df, *, log_y=False, mean_overlay=True, alpha=0.35, ax=None, title='Spaghetti Plot')[source]

Overlaid individual IPRED profiles.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame.

  • log_y (bool) – Log scale on y-axis.

  • mean_overlay (bool) – Overlay mean profile in bold.

  • alpha (float) – Transparency for individual lines.

  • ax – Existing axes to plot into.

  • title (str) – Plot title.

openpkpd.plots.pk.concentration_time(diag_df, *, log_y=False, individual=True, mean_overlay=True, highlight_ids=None, ax=None, title='Concentration-Time Profile')[source]

Individual and/or mean concentration-time plot.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame from compute_diagnostics().

  • log_y (bool) – Use log scale on y-axis.

  • individual (bool) – Plot individual IPRED lines.

  • mean_overlay (bool) – Overlay the mean IPRED profile.

  • highlight_ids (list[int] | None) – Subject IDs to highlight with distinct color.

  • ax – Existing axes to plot into.

  • title (str) – Plot title.

openpkpd.plots.pk.mean_profile(diag_df, *, log_y=False, sd_band=True, ax=None, title='Mean Concentration Profile')[source]

Mean IPRED profile with optional ± SD band.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame.

  • log_y (bool) – Log scale on y-axis.

  • sd_band (bool) – Show mean ± 1 SD shaded band.

  • ax – Existing axes to plot into.

  • title (str) – Plot title.

PD plots

openpkpd.plots.pd.effect_time(diag_df, effect_col, *, individual=True, mean_overlay=True, ax=None, title='Effect-Time Profile')[source]

Effect vs time plot.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame with an effect column.

  • effect_col (str) – Column name for the effect variable.

  • individual (bool) – Plot individual profiles.

  • mean_overlay (bool) – Overlay mean profile.

  • ax – Existing axes.

  • title (str) – Plot title.

openpkpd.plots.pd.emax_curve(diag_df, conc_col, effect_col, *, emax=None, ec50=None, gamma=1.0, e0=0.0, ax=None, title='Emax Curve')[source]

Observed E vs C scatter with optional Emax model overlay.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame.

  • conc_col (str) – Column for concentration.

  • effect_col (str) – Column for effect.

  • emax (float | None) – Emax parameter (skip overlay if None).

  • ec50 (float | None) – EC50 parameter (skip overlay if None).

  • gamma (float) – Hill exponent (default 1.0).

  • e0 (float) – Baseline effect.

  • ax – Existing axes.

  • title (str) – Plot title.

openpkpd.plots.pd.hysteresis_loop(diag_df, conc_col, effect_col, *, color_by_time=True, ax=None, title='Hysteresis Loop')[source]

C–E loop colored by time (one loop per subject, then mean).

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame.

  • conc_col (str) – Concentration column.

  • effect_col (str) – Effect column.

  • color_by_time (bool) – Color scatter points by time value.

  • ax – Existing axes.

  • title (str) – Plot title.

openpkpd.plots.pd.pd_individual(diag_df, conc_col, effect_col, *, subject_ids=None, n_cols=3, title='Individual PK+PD Profiles')[source]

Per-subject dual-panel (PK and PD) plot.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame.

  • conc_col (str) – Concentration column.

  • effect_col (str) – Effect column.

  • subject_ids (list[int] | None) – Subset of IDs (default: all).

  • n_cols (int) – Number of columns in the grid.

  • title (str) – Overall figure title.

ETA plots

openpkpd.plots.eta.eta_histograms(diag_df, omega, *, n_cols=3, bins=20, overlay_normal=True, title='ETA Distributions')[source]

Histogram of each ETA with optional N(0, omega_kk) overlay.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame with ETAn columns.

  • omega (ndarray) – Final Omega matrix (n_eta × n_eta).

  • n_cols (int) – Number of columns in the grid.

  • bins (int) – Number of histogram bins.

  • overlay_normal (bool) – Overlay N(0, omega_kk) density curve.

  • title (str) – Figure title.

openpkpd.plots.eta.eta_pairs(diag_df, *, alpha=0.6, title='ETA Pairs')[source]

Pairs scatter matrix of all ETA columns.

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame with ETAn columns.

  • alpha (float) – Scatter point transparency.

  • title (str) – Figure title.

openpkpd.plots.eta.eta_vs_covariate(diag_df, covariate, eta_col, *, categorical=False, ax=None, title=None)[source]

ETA vs covariate scatter (continuous) or boxplot (categorical).

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame.

  • covariate (str) – Covariate column name.

  • eta_col (str) – ETA column name (e.g. “ETA1”).

  • categorical (bool) – If True, produce a boxplot instead of scatter.

  • ax – Existing axes.

  • title (str | None) – Plot title.

Model performance

openpkpd.plots.model_perf.ofv_history(result, *, log_scale=False, ax=None, title='OFV History')[source]

Line plot of OFV across outer iterations.

Parameters:
  • result (EstimationResult) – EstimationResult with ofv_history list.

  • log_scale (bool) – Use log scale on y-axis.

  • ax – Existing axes.

  • title (str) – Plot title.

openpkpd.plots.model_perf.vpc(diag_df, population_model=None, result=None, *, vpc_result=None, n_sim=200, percentiles=(5.0, 50.0, 95.0), stratify_col=None, ax=None, title='Visual Predictive Check')[source]

VPC: overlay observed vs simulated percentile bands.

Simulated percentile bands are shown as shaded areas; observed percentiles are plotted as lines over observed data scatter.

Can be called in two ways:

  1. With a VPCResult object (from VPCEngine.compute()):

    vpc(diag_df, vpc_result=my_vpc_result)

  2. With raw PopulationModel + EstimationResult (runs simulation internally):

    vpc(diag_df, population_model, result, n_sim=200)

Parameters:
  • diag_df (DataFrame) – Diagnostic DataFrame (from compute_diagnostics()).

  • population_model (PopulationModel | None) – Assembled PopulationModel (required if vpc_result is None).

  • result (EstimationResult | None) – EstimationResult (required if vpc_result is None).

  • vpc_result (Any | None) – Pre-computed VPCResult from VPCEngine (optional). If provided, population_model and result are ignored.

  • n_sim (int) – Number of Monte Carlo simulations (used when vpc_result is None). Must be > 0.

  • percentiles (tuple[float, float, float]) – Three percentile values (low, mid, high) as (5, 50, 95).

  • stratify_col (str | None) – Column to stratify on (single plot if None).

  • ax – Existing matplotlib Axes to draw on.

  • title (str) – Plot title.

Returns:

matplotlib.figure.Figure.

Raises:

ValueError – If n_sim <= 0 or if neither vpc_result nor population_model is provided.

Simulation-based plots

openpkpd.plots.simulation.vpc_plot(vpc_result, title='Visual Predictive Check', obs_color='#333333', sim_pi_color='#3498DB', sim_median_color='#E74C3C', figsize=(10, 6), log_y=False, ax=None)[source]

VPC plot: observed data overlaid with simulated prediction intervals.

Produces a standard VPC figure with:
  • Grey dots: individual observed DV values

  • Blue shaded regions: 90% PI bands for simulated 5th and 95th percentiles

  • Red shaded region: 90% PI band for simulated median (50th percentile)

  • Solid colored lines: medians of simulated percentile bands

  • Dashed black lines: observed 5th, 50th, 95th percentiles (binned by time)

Accepts either a VPCResult object (from openpkpd.simulation.vpc.VPCEngine) or any object with observed_df, simulated_df, obs_percentiles, and sim_percentiles attributes.

Parameters:
  • vpc_result (Any) – VPCResult from VPCEngine.compute(), or object with observed_df, obs_percentiles, sim_percentiles attributes.

  • title (str) – Plot title string.

  • obs_color (str) – Color for observed data points and observed percentile lines.

  • sim_pi_color (str) – Color for simulated PI shaded regions.

  • sim_median_color (str) – Color for simulated median shaded region.

  • figsize (tuple[float, float]) – Figure size (width, height) in inches.

  • log_y (bool) – If True, use log scale on the y-axis.

  • ax (Any | None) – Existing matplotlib Axes to draw on (creates new figure if None).

Return type:

Any

Returns:

matplotlib.figure.Figure object.

Raises:

ImportError – If matplotlib is not installed.

openpkpd.plots.simulation.pcvpc_plot(diag_df, vpc_result, *, percentiles=(5.0, 50.0, 95.0), log_y=False, figsize=(10, 6), title='Prediction-Corrected VPC')[source]

Prediction-corrected VPC (pcVPC).

Observed and simulated concentrations are normalized by the population prediction (PRED) at each time point, removing the influence of dose and design heterogeneity.

Correction: DV_pc = DV * median(PRED_sim_bin) / PRED_obs

Parameters:
  • diag_df (Any) – Diagnostic DataFrame with columns DV, PRED, TIME.

  • vpc_result (Any) – VPCResult from VPCEngine.

  • percentiles (tuple[float, float, float]) – Percentile triplet (low, median, high).

  • log_y (bool) – Log scale on y-axis.

  • figsize (tuple[float, float]) – Figure size.

  • title (str) – Plot title.

Return type:

Any

Returns:

matplotlib.figure.Figure.

openpkpd.plots.simulation.stratified_vpc_plot(diag_df, vpc_result, stratify_col, *, percentiles=(5.0, 50.0, 95.0), log_y=False, n_cols=2, title='Stratified VPC')[source]

Multi-panel VPC stratified by a covariate column.

One VPC panel is drawn per unique value of stratify_col. Each panel uses the same vpc_plot style (observed scatter + simulated PI bands). Subsets of diag_df are used for the observed data in each panel; the simulated percentiles from vpc_result are applied to the matching stratum rows.

Parameters:
  • diag_df (Any) – Diagnostic DataFrame with stratify_col present.

  • vpc_result (Any) – VPCResult from VPCEngine.

  • stratify_col (str) – Column name to stratify on.

  • percentiles (tuple[float, float, float]) – Percentile triplet.

  • log_y (bool) – Log scale on y-axis.

  • n_cols (int) – Number of columns.

  • title (str) – Overall figure title.

Return type:

Any

Returns:

matplotlib.figure.Figure.

openpkpd.plots.simulation.npde_plot(diagnostic_df, title='NPDE Diagnostics', figsize=(12, 8))[source]

Four-panel NPDE diagnostic plot.

Produces a 2x2 figure panel showing:
  1. NPDE vs TIME — scatter with zero line and +/-1.96 bands

  2. NPDE vs PRED — scatter with zero line and +/-1.96 bands

  3. NPDE histogram — bar chart with standard normal N(0,1) overlay

  4. NPDE Q-Q plot — quantile-quantile plot against standard normal

The NPDE column must be present in diagnostic_df. Use compute_npde() from openpkpd.plots.diagnostics to compute NPDEs from a fitted model.

Parameters:
  • diagnostic_df (Any) – DataFrame with at minimum columns: TIME, PRED, NPDE. Additional columns CWRES, DV, IPRED are used if present.

  • title (str) – Overall figure title.

  • figsize (tuple[float, float]) – Figure size (width, height) in inches.

Return type:

Any

Returns:

matplotlib.figure.Figure with 4 axes.

Raises:
  • ImportError – If matplotlib is not installed.

  • ValueError – If the NPDE column is not found in diagnostic_df.

openpkpd.plots.simulation.simulation_panel(simulated_df, observed_df=None, n_subjects=9, figsize=(15, 12), title='Simulated Profiles')[source]

Panel of simulated individual concentration-time profiles.

Shows up to n_subjects individual simulated profiles in a grid layout. Each panel displays all replicate profiles for that subject as thin translucent lines. If observed_df is provided, observed data points are overlaid as solid markers.

The simulated_df must contain columns: ID, TIME, DV, REP. The observed_df (optional) must contain columns: ID, TIME, DV.

Parameters:
  • simulated_df (Any) – DataFrame with simulated data (columns: ID, TIME, DV, REP). REP=0 is treated as the observed reference; REP>=1 are simulation replicates.

  • observed_df (Any | None) – Optional DataFrame with observed data (columns: ID, TIME, DV). If None, uses REP=0 rows from simulated_df if present.

  • n_subjects (int) – Maximum number of subjects to display (default 9).

  • figsize (tuple[float, float]) – Figure size (width, height) in inches.

  • title (str) – Overall figure title.

Return type:

Any

Returns:

matplotlib.figure.Figure with a grid of individual profile panels.

Raises:

ImportError – If matplotlib is not installed.

openpkpd.plots.vpc_plot is re-exported from the top-level openpkpd.plots namespace as a convenience alias for vpc_plot().