From 4629b6c1939f13c702ce267a1fe92406ce55d3b8 Mon Sep 17 00:00:00 2001 From: corentinlger Date: Wed, 28 Aug 2024 17:53:13 +0200 Subject: [PATCH] Update panel app documentation --- vivarium/interface/panel_app.py | 70 +++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/vivarium/interface/panel_app.py b/vivarium/interface/panel_app.py index db89e99..102db0d 100644 --- a/vivarium/interface/panel_app.py +++ b/vivarium/interface/panel_app.py @@ -41,23 +41,43 @@ def __init__(self, config, panel_configs, panel_simulator_config, selected, etyp self.config[i].param.watch(self.hide_non_existing, "exists", onlychanged=True) def drag_cb(self, attr, old, new): + """Callback for the drag & drop of entities + + :param attr: (unused) + :param old: (unused) + :param new: The event containing the new positions of the entities + """ for i, c in enumerate(self.config): c.x_position = new['x'][i] c.y_position = new['y'][i] @contextmanager def no_drag_cb(self): + """Prevent the CDS from updating the configs when the change comes from the server""" self.cds.remove_on_change('data', self.drag_cb) yield self.cds.on_change('data', self.drag_cb) def get_cds_data(self, state): + """Update the ColumnDataSource with the new data + + :param state: The state coming from the server + :return: Data dictionary for the ColumnDataSource + """ raise NotImplementedError() def update_cds(self, state): + """Updates the ColumnDataSource with new data from server + + :param state: The state coming from the server + """ self.cds.data.update(self.get_cds_data(state)) def create_cds_view(self): + """Creates a ColumnDataSource view for each visibility attribute + + :return: A dictionary of ColumnDataSource views for each visibility attribute + """ # For each attribute in the panel config, create a filter # that is a logical AND of the visibility and the attribute return { @@ -67,20 +87,40 @@ def create_cds_view(self): } def update_cds_view(self, event): + """Updates the view of the ColumnDataSource if the visibility of an entity + changes + + :param event: The event containing the changed value + """ n = event.name for attr in [n] if n != "visible" else self.panel_configs[0].param_names(): f = [getattr(pc, attr) and pc.visible for pc in self.panel_configs] self.cds_view[attr].filter = BooleanFilter(f) def update_selected_plot(self, event): + """Updates the selected entities in the plot + + :param event: The event containing the new selected entities + """ self.cds.selected.indices = event.new def hide_all_non_existing(self, event): + """Hides or shows all the entities that do not exist according to the global + visibility of non-existing entities + + :param event: The event containing the new global "visibility of non-existing + entities" value + """ for i, pc in enumerate(self.panel_configs): if not self.config[i].exists: pc.visible = not event.new def hide_non_existing(self, event): + """Hides or shows an entity that does not exist depending on the global + visibility of non-existing entities + + :param event: The event containing the new existence value + """ if not self.panel_simulator_config.hide_non_existing: return idx = self.config.index(event.obj) @@ -88,11 +128,17 @@ def hide_non_existing(self, event): def update_selected_simulator(self): + """Updates the list of selected entities in the Selection list""" indices = self.cds.selected.indices if len(indices) > 0 and indices != self.selected.selection: self.selected.selection = indices def plot(self, fig: figure): + """Plot the objects on the bokeh figure + + :param fig: A bokeh figure + :return: The figure with the objects plotted + """ raise NotImplementedError() @@ -224,6 +270,10 @@ def __init__(self, **kwargs): self.set_callbacks() def start_toggle_cb(self, event): + """Callback for the start/stop button + + :param event: The event for the new value of the button + """ if event.new != self.controller.is_started(): if event.new: self.controller.start() @@ -237,9 +287,14 @@ def entity_toggle_cb(self, event): cc.visible = cc.name in event.new def update_timestep_cb(self, event): + """Callback for the timestep of the plot update + + :param event: The event for the new value of the timestep + """ self.pcb_plot.period = event.new def update_plot_cb(self): + """Periodic callback for the plot update""" for em in self.entity_managers.values(): em.update_selected_simulator() state = self.controller.update_state() @@ -251,12 +306,20 @@ def update_plot_cb(self): em.update_cds(state) def update_switch_cb(self, event): + """Callback for the plot update switch + + :param event: The event for the new value of the switch + """ if event.new and not self.pcb_plot.running: self.pcb_plot.start() elif not event.new and self.pcb_plot.running: self.pcb_plot.stop() def create_plot(self): + """Creates a bokeh plot for the simulator + + :return: A bokeh plot + """ p_tools = "crosshair,pan,wheel_zoom,box_zoom,reset,tap,box_select,lasso_select" p = figure(tools=p_tools, active_drag="box_select") p.axis.major_label_text_font_size = "24px" @@ -270,6 +333,10 @@ def create_plot(self): return p def create_app(self): + """Creates a panel app + + :return: the panel app + """ self.config_columns = pn.Row(* [pn.Column( pn.pane.Markdown("### SIMULATOR", align="center"), @@ -296,6 +363,9 @@ def create_app(self): return app def set_callbacks(self): + """ + Set the callbacks for all the widgets in the app + """ # putting directly the slider value causes bugs on some OS self.pcb_plot = pn.state.add_periodic_callback(self.update_plot_cb, self.update_timestep.value)