Plotting and reporting#

This tutorial turns fitted IC₅₀ results into compact tables and diagnostic figures. Plotting is Axes-first: create Matplotlib axes, then ask bindcurve to draw into them.

import matplotlib.pyplot as plt

import bindcurve as bc
all_data = bc.DoseResponseData.from_csv(
    "data/competitive-binding.csv",
    format="wide",
)
data = all_data.keep_only(["ic50_a", "ic50_b"])
results = bc.fit(
    data,
    model="ic50",
    fixed={"ymin": 5.0, "ymax": 95.0},
)

Summary and manuscript-ready report#

summary() exposes numerical statistics, while report() formats a selected concentration parameter for direct use in a report or manuscript.

results.summary()[
    ["compound_id", "N_exp", "N_fit_successful", "IC50", "IC50_SD_lower", "IC50_SD_upper"]
]
compound_id N_exp N_fit_successful IC50 IC50_SD_lower IC50_SD_upper
0 ic50_a 2 2 0.029872 0.027723 0.032187
1 ic50_b 2 2 0.297373 0.271715 0.325455
results.report(unit="concentration units", include_n_exp=True)
compound_id report N_fit_successful N_fit_failed
0 ic50_a 0.030 [0.03, 0.03] concentration units, N_exp = 2 2 0
1 ic50_b 0.30 [0.3, 0.3] concentration units, N_exp = 2 2 0

Individual experiments with confidence bands#

plot_fits() draws one curve per independent experiment. Confidence bands are pointwise intervals derived from each fit covariance matrix.

fig, ax = plt.subplots(figsize=(6, 4))
bc.plot_fits(
    data,
    results,
    compounds="ic50_a",
    confidence_band=True,
    ax=ax,
)
ax.set_xlabel("concentration")
ax.set_ylabel("response")
ax.legend()
plt.show()
../_images/e72e29a28eed98c071d813c3a1d776c2c3f6bba821fe0248b64ff2e053f724f4.png

Compound summaries#

plot_compounds() combines experiments into one visual series per compound and shows inter-experiment variation with error bars.

fig, ax = plt.subplots(figsize=(6, 4))
bc.plot_compounds(data, results, ax=ax, errorbar_kind="sd")
ax.set_xlabel("concentration")
ax.set_ylabel("response")
ax.legend()
plt.show()
../_images/235ab04fe4accaee3f83e281e9d8d265b594d4e77a7f1fa02bf5548d6fa8bdba.png

Residuals#

Residual plots reveal concentration-dependent structure that a summary statistic can hide.

fig, ax = plt.subplots(figsize=(6, 3))
bc.plot_residuals(data, results, compound_id="ic50_a", ax=ax)
ax.set_xlabel("concentration")
ax.set_ylabel("observed - predicted")
ax.legend()
plt.show()
../_images/858cf4d46965750ec32eef89c151287748cba37b1ad7c0e3cf68ca6182da5a67.png