Skip to content

Commit 57af072

Browse files
committed
Dataframe caching, should reduce calls to proxy by ~50%
1 parent 0035d8c commit 57af072

1 file changed

Lines changed: 78 additions & 6 deletions

File tree

src/petab_gui/views/simple_plot_view.py

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ def __init__(self, parent=None):
7777
self.observable_to_subplot = {}
7878
self.no_plotting_rn = False
7979

80+
# DataFrame caching system for performance optimization
81+
self._df_cache = {
82+
"measurements": None,
83+
"simulations": None,
84+
"conditions": None,
85+
"visualization": None,
86+
}
87+
self._cache_valid = {
88+
"measurements": False,
89+
"simulations": False,
90+
"conditions": False,
91+
"visualization": False,
92+
}
93+
94+
def _invalidate_cache(self, table_name):
95+
"""Invalidate cache for specific table."""
96+
self._cache_valid[table_name] = False
97+
98+
def _get_cached_df(self, table_name, proxy_model):
99+
"""Get cached DataFrame or convert if invalid."""
100+
if not self._cache_valid[table_name]:
101+
self._df_cache[table_name] = proxy_to_dataframe(proxy_model)
102+
self._cache_valid[table_name] = True
103+
return self._df_cache[table_name]
104+
80105
def initialize(
81106
self, meas_proxy, sim_proxy, cond_proxy, vis_proxy, petab_model
82107
):
@@ -86,20 +111,65 @@ def initialize(
86111
self.vis_proxy = vis_proxy
87112
self.petab_model = petab_model
88113

89-
# Connect data changes
114+
# Connect cache invalidation and data changes
90115
self.options_manager.option_changed.connect(self._debounced_plot)
116+
117+
# Measurements cache invalidation
118+
self.meas_proxy.dataChanged.connect(
119+
lambda: self._invalidate_cache("measurements")
120+
)
121+
self.meas_proxy.rowsInserted.connect(
122+
lambda: self._invalidate_cache("measurements")
123+
)
124+
self.meas_proxy.rowsRemoved.connect(
125+
lambda: self._invalidate_cache("measurements")
126+
)
91127
self.meas_proxy.dataChanged.connect(self._debounced_plot)
92128
self.meas_proxy.rowsInserted.connect(self._debounced_plot)
93129
self.meas_proxy.rowsRemoved.connect(self._debounced_plot)
130+
131+
# Conditions cache invalidation
132+
self.cond_proxy.dataChanged.connect(
133+
lambda: self._invalidate_cache("conditions")
134+
)
135+
self.cond_proxy.rowsInserted.connect(
136+
lambda: self._invalidate_cache("conditions")
137+
)
138+
self.cond_proxy.rowsRemoved.connect(
139+
lambda: self._invalidate_cache("conditions")
140+
)
94141
self.cond_proxy.dataChanged.connect(self._debounced_plot)
95142
self.cond_proxy.rowsInserted.connect(self._debounced_plot)
96143
self.cond_proxy.rowsRemoved.connect(self._debounced_plot)
144+
145+
# Simulations cache invalidation
146+
self.sim_proxy.dataChanged.connect(
147+
lambda: self._invalidate_cache("simulations")
148+
)
149+
self.sim_proxy.rowsInserted.connect(
150+
lambda: self._invalidate_cache("simulations")
151+
)
152+
self.sim_proxy.rowsRemoved.connect(
153+
lambda: self._invalidate_cache("simulations")
154+
)
97155
self.sim_proxy.dataChanged.connect(self._debounced_plot)
98156
self.sim_proxy.rowsInserted.connect(self._debounced_plot)
99157
self.sim_proxy.rowsRemoved.connect(self._debounced_plot)
158+
159+
# Visualization cache invalidation
160+
self.vis_proxy.dataChanged.connect(
161+
lambda: self._invalidate_cache("visualization")
162+
)
163+
self.vis_proxy.rowsInserted.connect(
164+
lambda: self._invalidate_cache("visualization")
165+
)
166+
self.vis_proxy.rowsRemoved.connect(
167+
lambda: self._invalidate_cache("visualization")
168+
)
100169
self.vis_proxy.dataChanged.connect(self._debounced_plot)
101170
self.vis_proxy.rowsInserted.connect(self._debounced_plot)
102171
self.vis_proxy.rowsRemoved.connect(self._debounced_plot)
172+
103173
self.visibilityChanged.connect(self._debounced_plot)
104174

105175
self.plot_it()
@@ -113,10 +183,11 @@ def plot_it(self):
113183
# If the dock is not visible, do not plot
114184
return
115185

116-
measurements_df = proxy_to_dataframe(self.meas_proxy)
117-
simulations_df = proxy_to_dataframe(self.sim_proxy)
118-
conditions_df = proxy_to_dataframe(self.cond_proxy)
119-
visualisation_df = proxy_to_dataframe(self.vis_proxy)
186+
# Use cached DataFrames for performance
187+
measurements_df = self._get_cached_df("measurements", self.meas_proxy)
188+
simulations_df = self._get_cached_df("simulations", self.sim_proxy)
189+
conditions_df = self._get_cached_df("conditions", self.cond_proxy)
190+
visualisation_df = self._get_cached_df("visualization", self.vis_proxy)
120191
group_by = self.options_manager.get_option()
121192
# group_by different value in petab.visualize
122193
if group_by == "condition":
@@ -308,7 +379,8 @@ def plot_residuals(self):
308379
return
309380

310381
problem = self.petab_model.current_petab_problem
311-
simulations_df = proxy_to_dataframe(self.sim_proxy)
382+
# Reuse cached DataFrame instead of converting again
383+
simulations_df = self._get_cached_df("simulations", self.sim_proxy)
312384

313385
if simulations_df.empty:
314386
return

0 commit comments

Comments
 (0)