|
|
@@ -293,7 +293,17 @@ app_ui = ui.page_fluid(
|
|
|
ui.nav_panel(
|
|
|
"Hot voxels",
|
|
|
ui.output_ui("selected_summary_hot"),
|
|
|
- ui.output_ui("hot_voxel_tabs"),
|
|
|
+ ui.p(
|
|
|
+ "Hot-voxel plots are shown in fixed output slots to avoid "
|
|
|
+ "recreating Plotly widget containers after each computation."
|
|
|
+ ),
|
|
|
+ ui.navset_tab(
|
|
|
+ ui.nav_panel("Hot 1", output_widget("hot_voxel_plot_0", height="760px")),
|
|
|
+ ui.nav_panel("Hot 2", output_widget("hot_voxel_plot_1", height="760px")),
|
|
|
+ ui.nav_panel("Hot 3", output_widget("hot_voxel_plot_2", height="760px")),
|
|
|
+ ui.nav_panel("Hot 4", output_widget("hot_voxel_plot_3", height="760px")),
|
|
|
+ ui.nav_panel("Hot 5", output_widget("hot_voxel_plot_4", height="760px")),
|
|
|
+ ),
|
|
|
),
|
|
|
ui.nav_panel(
|
|
|
"Spatial features",
|
|
|
@@ -508,28 +518,10 @@ def server(input: Inputs, output: Outputs, session: Session):
|
|
|
return pd.DataFrame()
|
|
|
return render.DataGrid(result["suv_percentiles"], height="250px")
|
|
|
|
|
|
- @render.ui
|
|
|
- def hot_voxel_tabs():
|
|
|
- result = analysis_result()
|
|
|
- if not result.get("ok"):
|
|
|
- return ui.div(ui.em("Select a row and compute to show hot-voxel plots."))
|
|
|
-
|
|
|
- probs = list(result["probs"])
|
|
|
- max_plots = 5
|
|
|
-
|
|
|
- if len(probs) > max_plots:
|
|
|
- probs = probs[:max_plots]
|
|
|
-
|
|
|
- tabs = []
|
|
|
- for i, p in enumerate(probs):
|
|
|
- tabs.append(
|
|
|
- ui.nav_panel(
|
|
|
- f"p{p:g}",
|
|
|
- output_widget(f"hot_voxel_plot_{i}", height="760px"),
|
|
|
- )
|
|
|
- )
|
|
|
-
|
|
|
- return ui.navset_tab(*tabs)
|
|
|
+ # Important: hot-voxel output widgets are defined statically in the UI.
|
|
|
+ # Do not recreate Plotly widget containers dynamically after every run; doing
|
|
|
+ # so can trigger shinywidgets/Plotly JavaScript state errors on subsequent
|
|
|
+ # row selections.
|
|
|
|
|
|
def _hot_voxel_figure_by_index(index: int):
|
|
|
result = analysis_result()
|