Skip to content

Commit 272583a

Browse files
committed
add histogram to residuals plot and center zero
1 parent 05067d6 commit 272583a

File tree

1 file changed

+35
-25
lines changed

1 file changed

+35
-25
lines changed

petab/visualize/plot_residuals.py

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@
1313
from ..calculate import calculate_residuals
1414
from ..core import get_simulation_df
1515
from ..problem import Problem
16-
from ..C import NOISE_DISTRIBUTION, NORMAL, LIN, OBSERVABLE_TRANSFORMATION, \
17-
OBSERVABLE_ID
16+
from ..C import *
1817

1918
__all__ = ['plot_residuals_vs_simulation']
2019

2120

2221
def plot_residuals_vs_simulation(
2322
petab_problem: Problem,
2423
simulations_df: Union[str, Path, pd.DataFrame],
25-
size: Tuple = (10, 7),
26-
ax: Optional[plt.Axes] = None
24+
size: Optional[Tuple] = (10, 7),
25+
axes: Optional[Tuple[plt.Axes, plt.Axes]] = None
2726
) -> matplotlib.axes.Axes:
2827
"""
2928
Plot residuals versus simulation values for measurements with normal noise
@@ -38,7 +37,7 @@ def plot_residuals_vs_simulation(
3837
output data file.
3938
size:
4039
Figure size.
41-
ax:
40+
axes:
4241
Axis object.
4342
4443
Returns
@@ -66,9 +65,11 @@ def plot_residuals_vs_simulation(
6665
raise ValueError("Residuals plot is only applicable for normal "
6766
"additive noise assumption")
6867

69-
if ax is None:
70-
fig, ax = plt.subplots(figsize=size)
68+
if axes is None:
69+
fig, axes = plt.subplots(1, 2, sharey=True, figsize=size,
70+
width_ratios=[2, 1])
7171
fig.set_layout_engine("tight")
72+
fig.suptitle("Residuals")
7273

7374
residual_df = calculate_residuals(
7475
measurement_dfs=petab_problem.measurement_df,
@@ -82,21 +83,30 @@ def plot_residuals_vs_simulation(
8283
simulations_df[OBSERVABLE_ID].isin(observable_ids)]
8384

8485
# compare to standard normal distribution
85-
ks_result = stats.kstest(normal_residuals['residual'], stats.norm.cdf)
86-
87-
ax.hlines(y=0, xmin=min(simulations_normal['simulation']),
88-
xmax=max(simulations_normal['simulation']), ls='--',
89-
color='gray')
90-
ax.scatter(simulations_normal['simulation'],
91-
normal_residuals['residual'])
92-
ax.text(0.3, 0.85,
93-
f'Kolmogorov-Smirnov test results:\n'
94-
f'statistic: {ks_result[0]:.2f}\n'
95-
f'pvalue: {ks_result[1]:.2e} ', transform=ax.transAxes)
96-
97-
ax.set_title("Residuals")
98-
ax.set_xlabel('simulated values')
99-
ax.set_ylabel('residuals')
100-
101-
plt.tight_layout()
102-
return ax
86+
ks_result = stats.kstest(normal_residuals[RESIDUAL], stats.norm.cdf)
87+
88+
# plot the residuals plot
89+
axes[0].hlines(y=0, xmin=min(simulations_normal[SIMULATION]),
90+
xmax=max(simulations_normal[SIMULATION]), ls='--',
91+
color='gray')
92+
axes[0].scatter(simulations_normal[SIMULATION],
93+
normal_residuals[RESIDUAL])
94+
axes[0].text(0.3, 0.85,
95+
f'Kolmogorov-Smirnov test results:\n'
96+
f'statistic: {ks_result[0]:.2f}\n'
97+
f'pvalue: {ks_result[1]:.2e} ', transform=axes[0].transAxes)
98+
axes[0].set_xlabel('simulated values')
99+
axes[0].set_ylabel('residuals')
100+
101+
# plot histogram
102+
axes[1].hist(normal_residuals[RESIDUAL], density=True,
103+
orientation='horizontal')
104+
axes[1].set_xlabel('distribution')
105+
106+
ymin, ymax = axes[0].get_ylim()
107+
ylim = max(abs(ymin), abs(ymax))
108+
axes[0].set_ylim(-ylim, ylim)
109+
axes[1].tick_params(left=False, labelleft=False, right=True,
110+
labelright=True)
111+
112+
return axes

0 commit comments

Comments
 (0)