1313from ..calculate import calculate_residuals
1414from ..core import get_simulation_df
1515from ..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
2221def 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.15 , 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