Plotting¶
Four helpers built on matplotlib and lifelines. All of them return
(figure, axes), so you can keep styling, annotating and saving afterwards.
Both libraries are hard dependencies — nothing extra to install.
Kaplan-Meier curves¶
import matplotlib.pyplot as plt
from gen_surv import generate, plot_survival_curve
df = generate(model="cphm", n=2000, beta=0.5, covariate_range=2.0,
model_cens="uniform", cens_par=1.0, seed=42)
fig, ax = plot_survival_curve(df, title="CPHM, n=2000")
fig.savefig("km.png", dpi=200, bbox_inches="tight")
| Parameter | Default | Effect |
|---|---|---|
time_col, status_col |
"time", "status" |
column names |
group_col |
None |
draw one curve per level of this column |
confidence_intervals |
True |
shade pointwise confidence bands |
title |
"Kaplan-Meier Survival Curve" |
plot title |
figsize |
(10, 6) |
figure size in inches |
ci_alpha |
0.2 |
opacity of the confidence band |
Stratified curves¶
group_col needs a discrete column. Generated covariates are usually
continuous, so bin one first:
import pandas as pd
df["X0_group"] = pd.qcut(df["X0"], q=3, labels=["low", "mid", "high"])
fig, ax = plot_survival_curve(df, group_col="X0_group",
title="Survival by covariate tertile")
Or use a model with a binary covariate — see Covariates.
Covariate effects¶
plot_covariate_effect
does that binning for you:
from gen_surv import plot_covariate_effect
fig, ax = plot_covariate_effect(df, covariate_col="X0", n_groups=3)
| Parameter | Default | Effect |
|---|---|---|
covariate_col |
— | the continuous covariate to split |
n_groups |
3 |
number of equal-sized groups |
title |
"Effect of Covariate on Survival" |
plot title |
With a positive beta, higher covariate values mean a higher hazard, so the
curves should fan out in order. If they cross or fail to separate, either the
effect is small relative to n or something upstream is wrong — which is
exactly the kind of check simulated data is for.
Comparing models¶
plot_hazard_comparison
takes a dict of datasets and overlays their smoothed hazards:
from gen_surv import generate, plot_hazard_comparison
models = {
f"shape={s}": generate(model="aft_weibull", n=2000, beta=[0.5, -0.3],
shape=s, scale=2.0, model_cens="uniform",
cens_par=5.0, seed=42)
for s in (0.5, 1.0, 2.0)
}
fig, ax = plot_hazard_comparison(models, title="Weibull hazard by shape",
bandwidth=0.5)
The falling, flat and rising hazards should be visibly distinct. bandwidth
controls the kernel smoother: too small is noisy, too large flattens real
structure.
This is also the way to see the difference between families — put a cphm
sample, a aft_log_logistic sample and a piecewise_exponential sample in one
dict.
Descriptive statistics¶
describe_survival
returns a frame rather than a plot, and pairs naturally with these figures. See
Summarising a dataset.
Practical notes¶
Saving instead of showing. In scripts and CI there is no display; use a non-interactive backend and save:
Styling after the fact. The returned axes is a normal matplotlib object:
fig, ax = plot_survival_curve(df)
ax.set_xlabel("Years since randomisation")
ax.set_ylim(0, 1)
ax.grid(alpha=0.3)
Several panels. The helpers create their own figure, so to arrange them side by side, save separately or re-plot onto your own axes with lifelines directly.
Column names. For tdcm, pass time_col="stop". For thmm there is no
single event indicator — derive one first, as in THMM.
From the command line¶
See Command line.