44from src .l_roadrunner import LRoadrunner , NULL_L_ROADRUNNER # type: ignore
55import src .utils as utils
66from src .plot_options import PlotOptions # type: ignore
7+ from src .score import Score # type: ignore
78
89import collections
910import matplotlib .axes as maxes # type: ignore
@@ -169,10 +170,6 @@ def max_cv(self) -> float:
169170 cv_arr [~ np .isfinite (cv_arr )] = 0.0
170171 return np .max (cv_arr )
171172
172- @property
173- def timecourse (self ) -> pd .DataFrame :
174- return self .l_roadrunner .timecourse
175-
176173 # ------------------------------------------------------------------
177174 # Public methods (alphabetical)
178175 # ------------------------------------------------------------------
@@ -277,7 +274,7 @@ def _calculateResiduals(params: Parameters, ispecies:int) -> np.ndarray:
277274 for i in range (self .num_species ):
278275 jacobian_arr [ispecies , i ] = params [f'd{ i } ' ].value
279276 prediction_arr = self ._predict (jacobian_arr = jacobian_arr )[:, ispecies ]
280- residual_arr = self .timecourse .iloc [:, ispecies ].values - prediction_arr
277+ residual_arr = self .timecourse_df .iloc [:, ispecies ].values - prediction_arr
281278 return residual_arr [1 :] # Exclude timepoint 0 to avoid issues with initial state
282279 ##
283280 for ispecies , _ in enumerate (self .l_roadrunner .species_names ):
@@ -305,6 +302,11 @@ def fromArrays(cls, jacobian_arr: np.ndarray, timepoint_arr: np.ndarray,
305302 jc ._initialize (l_roadrunner , eigenvalues_collection_arr ,
306303 eigenvector_collection_arr , ** kwargs )
307304 jc ._sortArrays ()
305+ if l_roadrunner is not NULL_L_ROADRUNNER :
306+ try :
307+ jc .timecourse_df = l_roadrunner .timecourse_df .loc [jc .timepoint_arr ]
308+ except KeyError :
309+ pass # timepoint_arr not a subset of timecourse_df; keep full timecourse
308310 return jc
309311
310312 def getCost (self , istart : int , iend : int ) -> float :
@@ -557,23 +559,19 @@ def plot(self,
557559 plt .show ()
558560 return PlotInfo (top_ax = ax1 , bottom_ax = ax2 , fig = fig )
559561
560- def plotPredictions (self ,
561- ax : Optional [plt .Axes ] = None , # type: ignore
562- ylim : Optional [Tuple [float , float ]]= None ,
563- xlim : Optional [Tuple [float , float ]]= None ,
564- model_name : str = "" ,
565- legend : bool = True ,
566- ) -> PlotOptions :
562+ def plotPrediction (self , ** kwargs ) -> PlotOptions :
567563 """
568564 Plot the predicted timecourse of simulation species concentrations.
569565 The first plot shows how the Jacobian changes over time relative to the centroid.
570566 The second plot shows the dynamics of the model's species concentrations
571- over time.
567+ over time. Does not plot the first value since this is the initial state and not a prediction.
572568
573569 Parameters
574570 ----------
575571 ax : Optional[plt.Axes]
576572 An optional matplotlib Axes
573+ title: str
574+ The title for the plot
577575 fig : Optional[plt.Figure]
578576 An optional matplotlib Figure object to use. If None, a new figure will be created.
579577 is_legend : bool
@@ -586,29 +584,29 @@ def plotPredictions(self,
586584 The model name
587585 """
588586 if hasattr (self .l_roadrunner , "getRoadrunner" ):
589- roadrunner = self .l_roadrunner .getRoadrunner ()
590- species_ids = roadrunner .getFloatingSpeciesIds ()
591- data_arr = self .l_roadrunner .simulate (is_with_timepoints = True )
592- species_data = data_arr [:, 1 :] # Exclude time column
593- species_times = data_arr [:, 0 ] # Extract time column
587+ species_ids = self .l_roadrunner .species_names
588+ species_times = self .timecourse_df .index .values
589+ species_data = self .timecourse_df .values
594590 else :
595591 raise ValueError ("Cannot plot species timecourse has a NULL LRoadrunner instance." )
596- prediction_df = self .predict ()
592+ pred_df = self .predict ()
593+ # Extract model_name before passing kwargs to PlotOptions (not a PlotOptions param)
594+ model_name = kwargs .pop ("model_name" , "" )
595+ if model_name and "title" not in kwargs :
596+ kwargs ["title" ] = f"{ model_name } : Species Timecourse"
597597 # Timecourse plot
598- plot_options = PlotOptions (ax = ax ,
599- legend = legend ,
600- ylim = ylim ,
601- xlim = xlim , title = f"{ model_name } : Species Timecourse" )
602- ax = plot_options .ax
598+ plt_opt = PlotOptions (** kwargs )
599+ ax = plt_opt .ax
603600 colors = [sns .color_palette ("tab10" )[i % 10 ] for i in range (len (species_ids ))]
601+ # Do separate loops so that legend works out correctly
602+ for i , species_id in enumerate (species_ids ):
603+ ax .plot (species_times , species_data [:, i ], # type: ignore
604+ label = species_id , color = colors [i ], alpha = 0.7 )
604605 for i , species_id in enumerate (species_ids ):
605- ax .plot (species_times , species_data [:, i ], label = species_id , color = colors [i ], alpha = 0.7 )
606- ax .scatter (species_times , prediction_df [species_id ], s = 8 , alpha = 0.7 , color = colors [i ])
607- ax .set_xlabel ("Time" )
608- ax .set_ylabel ("Concentration" )
609- ax .set_title (f"{ model_name } : Species Timecourse" )
610- plot_options .apply ()
611- return plot_options
606+ ax .scatter (species_times [1 :], pred_df [species_id ].values [1 :], # type: ignore
607+ s = 8 , alpha = 0.7 , color = colors [i ])
608+ plt_opt .apply ()
609+ return plt_opt
612610
613611 def predict (self , ** kwargs ) -> pd .DataFrame :
614612 """
@@ -761,6 +759,7 @@ def _initialize(self, l_roadrunner: LRoadrunner,
761759 self ._fitted_jacobian_arr = cn .NULL_ARRAY
762760 self ._num_fit = num_fit
763761 self ._jacobian_selection = jacobian_selection
762+ self .timecourse_df = self .l_roadrunner .timecourse_df .copy ()
764763
765764 @staticmethod
766765 def _ivp (_ : float , x : np .ndarray , jacobian_arr : np .ndarray ) -> np .ndarray :
@@ -819,12 +818,12 @@ def ode(t: float, x: np.ndarray) -> np.ndarray:
819818 n_time = len (self .timepoint_arr )
820819 n_species = len (forcing_input_arr )
821820 result_arr = np .full ((n_time , n_species ), np .nan )
822- result_arr [0 ] = self .l_roadrunner .timecourse . iloc [ 0 , : ].values # type: ignore
821+ result_arr [0 ] = self .l_roadrunner .timecourse_df . loc [ self . timepoint_arr [ 0 ] ].values # type: ignore
823822 try :
824823 with warnings .catch_warnings ():
825824 warnings .simplefilter ("ignore" , RuntimeWarning )
826825 for itime , timepoint in enumerate (self .timepoint_arr [:- 1 ]):
827- initial_state_arr = self .l_roadrunner .timecourse .loc [timepoint ].values # type: ignore
826+ initial_state_arr = self .l_roadrunner .timecourse_df .loc [timepoint ].values # type: ignore
828827 sol = solve_ivp (ode ,
829828 (timepoint , self .timepoint_arr [itime + 1 ]),
830829 initial_state_arr ,
@@ -833,7 +832,7 @@ def ode(t: float, x: np.ndarray) -> np.ndarray:
833832 if sol .success and sol .y .shape == (n_species , 1 ):
834833 result_arr [itime + 1 ] = sol .y .T
835834 return result_arr
836- except Exception :
835+ except Exception as e :
837836 return np .full ((n_time , n_species ), np .nan )
838837
839838 def _sortArrays (self ) -> None :
0 commit comments