webviz-subsurface 0.2.35__py3-none-any.whl → 0.2.37__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. webviz_subsurface/__init__.py +1 -1
  2. webviz_subsurface/_components/color_picker.py +1 -1
  3. webviz_subsurface/_providers/ensemble_polygon_provider/__init__.py +3 -0
  4. webviz_subsurface/_providers/ensemble_polygon_provider/_polygon_discovery.py +97 -0
  5. webviz_subsurface/_providers/ensemble_polygon_provider/_provider_impl_file.py +226 -0
  6. webviz_subsurface/_providers/ensemble_polygon_provider/ensemble_polygon_provider.py +53 -0
  7. webviz_subsurface/_providers/ensemble_polygon_provider/ensemble_polygon_provider_factory.py +99 -0
  8. webviz_subsurface/_providers/ensemble_polygon_provider/polygon_server.py +125 -0
  9. webviz_subsurface/_providers/ensemble_summary_provider/_provider_impl_arrow_lazy.py +1 -1
  10. webviz_subsurface/plugins/_co2_leakage/_plugin.py +531 -377
  11. webviz_subsurface/plugins/_co2_leakage/_utilities/_misc.py +9 -0
  12. webviz_subsurface/plugins/_co2_leakage/_utilities/callbacks.py +169 -173
  13. webviz_subsurface/plugins/_co2_leakage/_utilities/co2volume.py +329 -84
  14. webviz_subsurface/plugins/_co2_leakage/_utilities/containment_data_provider.py +147 -0
  15. webviz_subsurface/plugins/_co2_leakage/_utilities/ensemble_well_picks.py +105 -0
  16. webviz_subsurface/plugins/_co2_leakage/_utilities/generic.py +170 -2
  17. webviz_subsurface/plugins/_co2_leakage/_utilities/initialization.py +189 -96
  18. webviz_subsurface/plugins/_co2_leakage/_utilities/polygon_handler.py +60 -0
  19. webviz_subsurface/plugins/_co2_leakage/_utilities/summary_graphs.py +77 -173
  20. webviz_subsurface/plugins/_co2_leakage/_utilities/surface_publishing.py +29 -21
  21. webviz_subsurface/plugins/_co2_leakage/_utilities/unsmry_data_provider.py +108 -0
  22. webviz_subsurface/plugins/_co2_leakage/views/mainview/mainview.py +30 -18
  23. webviz_subsurface/plugins/_co2_leakage/views/mainview/settings.py +805 -343
  24. webviz_subsurface/plugins/_relative_permeability.py +1 -1
  25. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/METADATA +2 -2
  26. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/RECORD +32 -21
  27. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/WHEEL +1 -1
  28. /webviz_subsurface/plugins/_co2_leakage/_utilities/{fault_polygons.py → fault_polygons_handler.py} +0 -0
  29. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/LICENSE +0 -0
  30. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/LICENSE.chromedriver +0 -0
  31. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/entry_points.txt +0 -0
  32. {webviz_subsurface-0.2.35.dist-info → webviz_subsurface-0.2.37.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ from webviz_config import WebvizPluginABC, WebvizSettings
8
8
  from webviz_config.utils import StrEnum, callback_typecheck
9
9
 
10
10
  from webviz_subsurface._providers import FaultPolygonsServer, SurfaceImageServer
11
+ from webviz_subsurface._providers.ensemble_polygon_provider import PolygonServer
11
12
  from webviz_subsurface.plugins._co2_leakage._utilities.callbacks import (
12
13
  SurfaceData,
13
14
  create_map_annotations,
@@ -17,6 +18,7 @@ from webviz_subsurface.plugins._co2_leakage._utilities.callbacks import (
17
18
  generate_containment_figures,
18
19
  generate_unsmry_figures,
19
20
  get_plume_polygon,
21
+ make_plot_ids,
20
22
  process_containment_info,
21
23
  process_summed_mass,
22
24
  process_visualization_info,
@@ -24,22 +26,28 @@ from webviz_subsurface.plugins._co2_leakage._utilities.callbacks import (
24
26
  readable_name,
25
27
  set_plot_ids,
26
28
  )
27
- from webviz_subsurface.plugins._co2_leakage._utilities.fault_polygons import (
29
+ from webviz_subsurface.plugins._co2_leakage._utilities.fault_polygons_handler import (
28
30
  FaultPolygonsHandler,
29
31
  )
30
32
  from webviz_subsurface.plugins._co2_leakage._utilities.generic import (
33
+ BoundarySettings,
31
34
  Co2MassScale,
32
35
  Co2VolumeScale,
33
36
  GraphSource,
34
37
  MapAttribute,
38
+ MapThresholds,
39
+ MapType,
35
40
  )
36
41
  from webviz_subsurface.plugins._co2_leakage._utilities.initialization import (
42
+ init_containment_data_providers,
43
+ init_dictionary_of_content,
37
44
  init_map_attribute_names,
38
45
  init_menu_options,
46
+ init_polygon_provider_handlers,
47
+ init_realizations,
39
48
  init_surface_providers,
40
- init_table_provider,
49
+ init_unsmry_data_providers,
41
50
  init_well_pick_provider,
42
- process_files,
43
51
  )
44
52
  from webviz_subsurface.plugins._co2_leakage.views.mainview.mainview import (
45
53
  MainView,
@@ -61,8 +69,6 @@ class CO2Leakage(WebvizPluginABC):
61
69
  ensemble
62
70
 
63
71
  * **`ensembles`:** Which ensembles in `shared_settings` to visualize.
64
- * **`file_containment_boundary`:** Path to a polygon representing the containment area
65
- * **`file_hazardous_boundary`:** Path to a polygon representing the hazardous area
66
72
  * **`well_pick_file`:** Path to a file containing well picks
67
73
  * **`plume_mass_relpath`:** Path to a table of co2 containment data (amount of
68
74
  CO2 outside/inside a boundary), for co2 mass. Relative to each realization.
@@ -81,6 +87,8 @@ class CO2Leakage(WebvizPluginABC):
81
87
  names and surface names used in the well pick file
82
88
  * **`map_surface_names_to_fault_polygons`:** Optional mapping between surface map
83
89
  names and surface names used by the fault polygons
90
+ * **`boundary_settings`:** Settings (paths etc) for polygons representing the
91
+ containment and hazardous areas
84
92
  """
85
93
 
86
94
  class Ids(StrEnum):
@@ -94,8 +102,6 @@ class CO2Leakage(WebvizPluginABC):
94
102
  app: Dash,
95
103
  webviz_settings: WebvizSettings,
96
104
  ensembles: List[str],
97
- file_containment_boundary: Optional[str] = None,
98
- file_hazardous_boundary: Optional[str] = None,
99
105
  well_pick_file: Optional[str] = None,
100
106
  plume_mass_relpath: str = TABLES_PATH + "/plume_mass.csv",
101
107
  plume_actual_volume_relpath: str = TABLES_PATH + "/plume_actual_volume.csv",
@@ -105,6 +111,7 @@ class CO2Leakage(WebvizPluginABC):
105
111
  map_attribute_names: Optional[Dict[str, str]] = None,
106
112
  map_surface_names_to_well_pick_names: Optional[Dict[str, str]] = None,
107
113
  map_surface_names_to_fault_polygons: Optional[Dict[str, str]] = None,
114
+ boundary_settings: Optional[BoundarySettings] = None,
108
115
  ):
109
116
  super().__init__()
110
117
  self._error_message = ""
@@ -115,21 +122,14 @@ class CO2Leakage(WebvizPluginABC):
115
122
  ]
116
123
  for ensemble_name in ensembles
117
124
  }
118
- (
119
- containment_poly_dict,
120
- hazardous_poly_dict,
121
- well_pick_dict,
122
- ) = process_files(
123
- file_containment_boundary,
124
- file_hazardous_boundary,
125
- well_pick_file,
126
- ensemble_paths,
127
- )
128
- self._polygon_files = [containment_poly_dict, hazardous_poly_dict]
125
+ self._realizations_per_ensemble = init_realizations(ensemble_paths)
129
126
  self._surface_server = SurfaceImageServer.instance(app)
130
127
  self._polygons_server = FaultPolygonsServer.instance(app)
131
-
132
- self._map_attribute_names = init_map_attribute_names(map_attribute_names)
128
+ self._map_attribute_names = init_map_attribute_names(
129
+ webviz_settings, ensembles, map_attribute_names
130
+ )
131
+ self._map_thresholds = MapThresholds(self._map_attribute_names)
132
+ self._threshold_ids = list(self._map_thresholds.standard_thresholds.keys())
133
133
  # Surfaces
134
134
  self._ensemble_surface_providers = init_surface_providers(
135
135
  webviz_settings, ensembles
@@ -145,25 +145,27 @@ class CO2Leakage(WebvizPluginABC):
145
145
  for ens in ensembles
146
146
  }
147
147
  # CO2 containment
148
- self._co2_table_providers = init_table_provider(
148
+ self._co2_table_providers = init_containment_data_providers(
149
149
  ensemble_paths,
150
150
  plume_mass_relpath,
151
151
  )
152
- self._co2_actual_volume_table_providers = init_table_provider(
152
+ self._co2_actual_volume_table_providers = init_containment_data_providers(
153
153
  ensemble_paths,
154
154
  plume_actual_volume_relpath,
155
155
  )
156
- self._unsmry_providers = (
157
- init_table_provider(
158
- ensemble_paths,
159
- unsmry_relpath,
160
- )
161
- if unsmry_relpath is not None
162
- else None
156
+ self._unsmry_providers = init_unsmry_data_providers(
157
+ ensemble_paths,
158
+ unsmry_relpath,
159
+ )
160
+ self._polygon_handlers = init_polygon_provider_handlers(
161
+ PolygonServer.instance(app),
162
+ ensemble_paths,
163
+ boundary_settings,
163
164
  )
164
165
  # Well picks
165
166
  self._well_pick_provider = init_well_pick_provider(
166
- well_pick_dict,
167
+ ensemble_paths,
168
+ well_pick_file,
167
169
  map_surface_names_to_well_pick_names,
168
170
  )
169
171
  # Phase (in case of residual trapping), zone and region options
@@ -171,8 +173,11 @@ class CO2Leakage(WebvizPluginABC):
171
173
  ensemble_paths,
172
174
  self._co2_table_providers,
173
175
  self._co2_actual_volume_table_providers,
174
- plume_mass_relpath,
175
- plume_actual_volume_relpath,
176
+ self._unsmry_providers,
177
+ )
178
+ self._content = init_dictionary_of_content(
179
+ self._menu_options,
180
+ len(self._map_attribute_names.mapping) > 0,
176
181
  )
177
182
  except Exception as err:
178
183
  self._error_message = f"Plugin initialization failed: {err}"
@@ -180,29 +185,37 @@ class CO2Leakage(WebvizPluginABC):
180
185
 
181
186
  self._summed_co2: Dict[str, Any] = {}
182
187
  self._visualization_info = {
183
- "threshold": -1.0,
188
+ "thresholds": self._map_thresholds.standard_thresholds,
184
189
  "n_clicks": 0,
185
190
  "change": False,
186
- "unit": "kg",
191
+ "unit": "tons",
187
192
  }
193
+ self._plot_id = ""
188
194
  self._color_tables = co2leakage_color_tables()
189
- self._well_pick_names = {
190
- ens: prov.well_names() if prov is not None else []
191
- for ens, prov in self._well_pick_provider.items()
195
+ self._well_pick_names: Dict[str, List[str]] = {
196
+ ens: (
197
+ self._well_pick_provider[ens].well_names
198
+ if ens in self._well_pick_provider
199
+ else []
200
+ )
201
+ for ens in ensembles
192
202
  }
193
203
  self.add_shared_settings_group(
194
204
  ViewSettings(
195
205
  ensemble_paths,
206
+ self._realizations_per_ensemble,
196
207
  self._ensemble_surface_providers,
197
208
  initial_surface,
198
209
  self._map_attribute_names,
210
+ self._map_thresholds,
199
211
  [c["name"] for c in self._color_tables], # type: ignore
200
212
  self._well_pick_names,
201
213
  self._menu_options,
214
+ self._content,
202
215
  ),
203
216
  self.Ids.MAIN_SETTINGS,
204
217
  )
205
- self.add_view(MainView(self._color_tables), self.Ids.MAIN_VIEW)
218
+ self.add_view(MainView(self._color_tables, self._content), self.Ids.MAIN_VIEW)
206
219
 
207
220
  @property
208
221
  def layout(self) -> html.Div:
@@ -225,8 +238,24 @@ class CO2Leakage(WebvizPluginABC):
225
238
 
226
239
  def _ensemble_dates(self, ens: str) -> List[str]:
227
240
  surface_provider = self._ensemble_surface_providers[ens]
228
- att_name = self._map_attribute_names[MapAttribute.MAX_SGAS]
229
- dates = surface_provider.surface_dates_for_attribute(att_name)
241
+ date_map_attribute = next(
242
+ (
243
+ k
244
+ for k in self._map_attribute_names.filtered_values
245
+ if MapType[k.name].value != "MIGRATION_TIME"
246
+ ),
247
+ None,
248
+ )
249
+ att_name = (
250
+ self._map_attribute_names[date_map_attribute]
251
+ if date_map_attribute is not None
252
+ else None
253
+ )
254
+ dates = (
255
+ None
256
+ if att_name is None
257
+ else surface_provider.surface_dates_for_attribute(att_name)
258
+ )
230
259
  if dates is None:
231
260
  raise ValueError(f"Failed to fetch dates for attribute '{att_name}'")
232
261
  return dates
@@ -236,329 +265,450 @@ class CO2Leakage(WebvizPluginABC):
236
265
  def _set_callbacks(self) -> None:
237
266
  # Cannot avoid many arguments since all the parameters are needed
238
267
  # to determine what to plot
239
- # pylint: disable=too-many-arguments
240
- @callback(
241
- Output(self._view_component(MapViewElement.Ids.BAR_PLOT), "figure"),
242
- Output(self._view_component(MapViewElement.Ids.TIME_PLOT), "figure"),
243
- Output(
244
- self._view_component(MapViewElement.Ids.TIME_PLOT_ONE_REAL), "figure"
245
- ),
246
- Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
247
- Input(self._settings_component(ViewSettings.Ids.GRAPH_SOURCE), "value"),
248
- Input(self._settings_component(ViewSettings.Ids.CO2_SCALE), "value"),
249
- Input(self._settings_component(ViewSettings.Ids.REALIZATION), "value"),
250
- Input(self._settings_component(ViewSettings.Ids.Y_MIN_AUTO_GRAPH), "value"),
251
- Input(self._settings_component(ViewSettings.Ids.Y_MIN_GRAPH), "value"),
252
- Input(self._settings_component(ViewSettings.Ids.Y_MAX_AUTO_GRAPH), "value"),
253
- Input(self._settings_component(ViewSettings.Ids.Y_MAX_GRAPH), "value"),
254
- Input(self._settings_component(ViewSettings.Ids.ZONE), "value"),
255
- Input(self._settings_component(ViewSettings.Ids.REGION), "value"),
256
- Input(self._settings_component(ViewSettings.Ids.PHASE), "value"),
257
- Input(self._settings_component(ViewSettings.Ids.CONTAINMENT), "value"),
258
- Input(self._settings_component(ViewSettings.Ids.COLOR_BY), "value"),
259
- Input(self._settings_component(ViewSettings.Ids.MARK_BY), "value"),
260
- Input(self._settings_component(ViewSettings.Ids.SORT_PLOT), "value"),
261
- )
262
- @callback_typecheck
263
- def update_graphs(
264
- ensemble: str,
265
- source: GraphSource,
266
- co2_scale: Union[Co2MassScale, Co2VolumeScale],
267
- realizations: List[int],
268
- y_min_auto: List[str],
269
- y_min_val: Optional[float],
270
- y_max_auto: List[str],
271
- y_max_val: Optional[float],
272
- zone: Optional[str],
273
- region: Optional[str],
274
- phase: str,
275
- containment: str,
276
- color_choice: str,
277
- mark_choice: Optional[str],
278
- sorting: str,
279
- ) -> Tuple[Dict, go.Figure, go.Figure, go.Figure]:
280
- # pylint: disable=too-many-locals
281
- figs = [no_update] * 3
282
- cont_info = process_containment_info(
283
- zone,
284
- region,
285
- phase,
286
- containment,
287
- color_choice,
288
- mark_choice,
289
- sorting,
290
- self._menu_options[ensemble][source],
268
+ if self._content["any_table"]:
269
+ # pylint: disable=too-many-arguments
270
+ @callback(
271
+ Output(self._view_component(MapViewElement.Ids.BAR_PLOT), "figure"),
272
+ Output(self._view_component(MapViewElement.Ids.TIME_PLOT), "figure"),
273
+ Output(
274
+ self._view_component(MapViewElement.Ids.STATISTICS_PLOT),
275
+ "figure",
276
+ ),
277
+ Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
278
+ Input(self._settings_component(ViewSettings.Ids.GRAPH_SOURCE), "value"),
279
+ Input(self._settings_component(ViewSettings.Ids.CO2_SCALE), "value"),
280
+ Input(self._settings_component(ViewSettings.Ids.REALIZATION), "value"),
281
+ Input(
282
+ self._settings_component(ViewSettings.Ids.Y_MIN_AUTO_GRAPH), "value"
283
+ ),
284
+ Input(self._settings_component(ViewSettings.Ids.Y_MIN_GRAPH), "value"),
285
+ Input(
286
+ self._settings_component(ViewSettings.Ids.Y_MAX_AUTO_GRAPH), "value"
287
+ ),
288
+ Input(self._settings_component(ViewSettings.Ids.Y_MAX_GRAPH), "value"),
289
+ Input(self._settings_component(ViewSettings.Ids.ZONE), "value"),
290
+ Input(self._settings_component(ViewSettings.Ids.REGION), "value"),
291
+ Input(self._settings_component(ViewSettings.Ids.PHASE), "value"),
292
+ Input(self._settings_component(ViewSettings.Ids.CONTAINMENT), "value"),
293
+ Input(self._settings_component(ViewSettings.Ids.PLUME_GROUP), "value"),
294
+ Input(self._settings_component(ViewSettings.Ids.COLOR_BY), "value"),
295
+ Input(self._settings_component(ViewSettings.Ids.MARK_BY), "value"),
296
+ Input(self._settings_component(ViewSettings.Ids.SORT_PLOT), "value"),
297
+ Input(self._settings_component(ViewSettings.Ids.REAL_OR_STAT), "value"),
298
+ Input(self._settings_component(ViewSettings.Ids.DATE_OPTION), "value"),
291
299
  )
292
- if source in [
293
- GraphSource.CONTAINMENT_MASS,
294
- GraphSource.CONTAINMENT_ACTUAL_VOLUME,
295
- ]:
296
- y_limits = [
297
- y_min_val if len(y_min_auto) == 0 else None,
298
- y_max_val if len(y_max_auto) == 0 else None,
299
- ]
300
- if (
301
- source == GraphSource.CONTAINMENT_MASS
302
- and ensemble in self._co2_table_providers
303
- ):
304
- figs[: len(figs)] = generate_containment_figures(
305
- self._co2_table_providers[ensemble],
306
- co2_scale,
307
- realizations[0],
308
- y_limits,
309
- cont_info,
310
- )
311
- elif (
312
- source == GraphSource.CONTAINMENT_ACTUAL_VOLUME
313
- and ensemble in self._co2_actual_volume_table_providers
314
- ):
315
- figs[: len(figs)] = generate_containment_figures(
316
- self._co2_actual_volume_table_providers[ensemble],
300
+ @callback_typecheck
301
+ def update_graphs(
302
+ ensemble: str,
303
+ source: GraphSource,
304
+ co2_scale: Union[Co2MassScale, Co2VolumeScale],
305
+ realizations: List[int],
306
+ y_min_auto: List[str],
307
+ y_min_val: Optional[float],
308
+ y_max_auto: List[str],
309
+ y_max_val: Optional[float],
310
+ zone: Optional[str],
311
+ region: Optional[str],
312
+ phase: str,
313
+ containment: str,
314
+ plume_group: str,
315
+ color_choice: str,
316
+ mark_choice: Optional[str],
317
+ sorting: str,
318
+ lines_to_show: str,
319
+ date_option: str,
320
+ ) -> Tuple[Dict, go.Figure, go.Figure, go.Figure]:
321
+ # pylint: disable=too-many-locals
322
+ figs = [no_update] * 3
323
+ cont_info = process_containment_info(
324
+ zone,
325
+ region,
326
+ phase,
327
+ containment,
328
+ plume_group,
329
+ color_choice,
330
+ mark_choice,
331
+ sorting,
332
+ lines_to_show,
333
+ date_option,
334
+ self._menu_options[ensemble][source],
335
+ )
336
+ if source in [
337
+ GraphSource.CONTAINMENT_MASS,
338
+ GraphSource.CONTAINMENT_ACTUAL_VOLUME,
339
+ ]:
340
+ plot_ids = make_plot_ids(
341
+ ensemble,
342
+ source,
317
343
  co2_scale,
318
- realizations[0],
319
- y_limits,
320
344
  cont_info,
345
+ realizations,
346
+ lines_to_show,
347
+ len(figs),
321
348
  )
322
- set_plot_ids(figs, source, co2_scale, cont_info, realizations)
323
- elif source == GraphSource.UNSMRY:
324
- if self._unsmry_providers is not None:
325
- if ensemble in self._unsmry_providers:
326
- u_figs = generate_unsmry_figures(
327
- self._unsmry_providers[ensemble],
328
- co2_scale,
349
+ cont_info["update_first_figure"] = self._plot_id != plot_ids[0]
350
+ self._plot_id = plot_ids[0]
351
+ y_limits = [
352
+ y_min_val if len(y_min_auto) == 0 else None,
353
+ y_max_val if len(y_max_auto) == 0 else None,
354
+ ]
355
+ if (
356
+ source == GraphSource.CONTAINMENT_MASS
357
+ and ensemble in self._co2_table_providers
358
+ ):
359
+ figs[: len(figs)] = generate_containment_figures(
329
360
  self._co2_table_providers[ensemble],
361
+ co2_scale,
362
+ realizations,
363
+ y_limits,
364
+ cont_info,
330
365
  )
331
- figs = list(u_figs)
332
- else:
333
- LOGGER.warning(
334
- """UNSMRY file has not been specified as input.
335
- Please use unsmry_relpath in the configuration."""
336
- )
337
- return figs # type: ignore
338
-
339
- @callback(
340
- Output(self._view_component(MapViewElement.Ids.DATE_SLIDER), "marks"),
341
- Output(self._view_component(MapViewElement.Ids.DATE_SLIDER), "value"),
342
- Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
343
- )
344
- def set_dates(ensemble: str) -> Tuple[Dict[int, Dict[str, Any]], Optional[int]]:
345
- if ensemble is None:
346
- return {}, None
347
- # Dates
348
- date_list = self._ensemble_dates(ensemble)
349
- dates = {
350
- i: {
351
- "label": f"{d[:4]}",
352
- "style": {"writingMode": "vertical-rl"},
353
- }
354
- for i, d in enumerate(date_list)
355
- }
356
- return dates, max(dates.keys())
366
+ elif (
367
+ source == GraphSource.CONTAINMENT_ACTUAL_VOLUME
368
+ and ensemble in self._co2_actual_volume_table_providers
369
+ ):
370
+ figs[: len(figs)] = generate_containment_figures(
371
+ self._co2_actual_volume_table_providers[ensemble],
372
+ co2_scale,
373
+ realizations,
374
+ y_limits,
375
+ cont_info,
376
+ )
377
+ set_plot_ids(figs, plot_ids)
378
+ elif source == GraphSource.UNSMRY:
379
+ if self._unsmry_providers is not None:
380
+ if ensemble in self._unsmry_providers:
381
+ figs[0] = go.Figure()
382
+ figs[1] = generate_unsmry_figures(
383
+ self._unsmry_providers[ensemble],
384
+ co2_scale,
385
+ self._co2_table_providers[ensemble],
386
+ )
387
+ figs[2] = go.Figure()
388
+ else:
389
+ LOGGER.warning(
390
+ """UNSMRY file has not been specified as input.
391
+ Please use unsmry_relpath in the configuration."""
392
+ )
393
+ return figs # type: ignore
357
394
 
358
- @callback(
359
- Output(self._view_component(MapViewElement.Ids.DATE_WRAPPER), "style"),
360
- Input(self._settings_component(ViewSettings.Ids.PROPERTY), "value"),
361
- )
362
- def toggle_date_slider(attribute: str) -> Dict[str, str]:
363
- if MapAttribute(attribute) in [
364
- MapAttribute.MIGRATION_TIME_SGAS,
365
- MapAttribute.MIGRATION_TIME_AMFG,
395
+ @callback(
396
+ Output(self._settings_component(ViewSettings.Ids.CO2_SCALE), "options"),
397
+ Output(self._settings_component(ViewSettings.Ids.CO2_SCALE), "value"),
398
+ Input(self._settings_component(ViewSettings.Ids.GRAPH_SOURCE), "value"),
399
+ )
400
+ def make_unit_list(
401
+ attribute: str,
402
+ ) -> Union[
403
+ Tuple[List[Any], Co2MassScale],
404
+ Tuple[List[Any], Co2VolumeScale],
366
405
  ]:
367
- return {"display": "none"}
368
- return {}
369
-
370
- @callback(
371
- Output(self._settings_component(ViewSettings.Ids.CO2_SCALE), "options"),
372
- Output(self._settings_component(ViewSettings.Ids.CO2_SCALE), "value"),
373
- Input(self._settings_component(ViewSettings.Ids.GRAPH_SOURCE), "value"),
374
- )
375
- def make_unit_list(
376
- attribute: str,
377
- ) -> Union[Tuple[List[Any], Co2MassScale], Tuple[List[Any], Co2VolumeScale],]:
378
- if attribute == GraphSource.CONTAINMENT_ACTUAL_VOLUME:
379
- return list(Co2VolumeScale), Co2VolumeScale.BILLION_CUBIC_METERS
380
- return list(Co2MassScale), Co2MassScale.MTONS
406
+ if attribute == GraphSource.CONTAINMENT_ACTUAL_VOLUME:
407
+ return list(Co2VolumeScale), Co2VolumeScale.BILLION_CUBIC_METERS
408
+ return list(Co2MassScale), Co2MassScale.MTONS
381
409
 
382
- @callback(
383
- Output(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "options"),
384
- Output(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "value"),
385
- Output(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "style"),
386
- Output(ViewSettings.Ids.WELL_FILTER_HEADER, "style"),
387
- Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
388
- )
389
- def set_well_options(
390
- ensemble: str,
391
- ) -> Tuple[List[Any], List[str], Dict[Any, Any], Dict[Any, Any]]:
392
- return (
393
- [{"label": i, "value": i} for i in self._well_pick_names[ensemble]],
394
- self._well_pick_names[ensemble],
395
- {
396
- "display": "block" if self._well_pick_names[ensemble] else "none",
397
- "height": f"{len(self._well_pick_names[ensemble]) * 22}px",
398
- },
399
- {
400
- "flex": 3,
401
- "minWidth": "20px",
402
- "display": "block" if self._well_pick_names[ensemble] else "none",
403
- },
410
+ @callback(
411
+ Output(
412
+ self._settings_component(ViewSettings.Ids.REAL_OR_STAT), "style"
413
+ ),
414
+ Output(
415
+ self._settings_component(ViewSettings.Ids.Y_LIM_OPTIONS), "style"
416
+ ),
417
+ Input(self._settings_component(ViewSettings.Ids.REALIZATION), "value"),
404
418
  )
419
+ def toggle_time_plot_options_visibility(
420
+ realizations: List[int],
421
+ ) -> Tuple[Dict[str, str], Dict[str, str]]:
422
+ if len(realizations) == 1:
423
+ return (
424
+ {"display": "none"},
425
+ {"display": "flex", "flex-direction": "column"},
426
+ )
427
+ return (
428
+ {"display": "flex", "flex-direction": "row"},
429
+ {"display": "none"},
430
+ )
405
431
 
406
- # Cannot avoid many arguments and/or locals since all layers of the DeckGL map
407
- # need to be updated simultaneously
408
- # pylint: disable=too-many-arguments,too-many-locals
409
- @callback(
410
- Output(self._view_component(MapViewElement.Ids.DECKGL_MAP), "layers"),
411
- Output(self._view_component(MapViewElement.Ids.DECKGL_MAP), "children"),
412
- Output(self._view_component(MapViewElement.Ids.DECKGL_MAP), "views"),
413
- Input(self._settings_component(ViewSettings.Ids.PROPERTY), "value"),
414
- Input(self._view_component(MapViewElement.Ids.DATE_SLIDER), "value"),
415
- Input(self._settings_component(ViewSettings.Ids.FORMATION), "value"),
416
- Input(self._settings_component(ViewSettings.Ids.REALIZATION), "value"),
417
- Input(self._settings_component(ViewSettings.Ids.STATISTIC), "value"),
418
- Input(self._settings_component(ViewSettings.Ids.COLOR_SCALE), "value"),
419
- Input(self._settings_component(ViewSettings.Ids.CM_MIN_AUTO), "value"),
420
- Input(self._settings_component(ViewSettings.Ids.CM_MIN), "value"),
421
- Input(self._settings_component(ViewSettings.Ids.CM_MAX_AUTO), "value"),
422
- Input(self._settings_component(ViewSettings.Ids.CM_MAX), "value"),
423
- Input(self._settings_component(ViewSettings.Ids.PLUME_THRESHOLD), "value"),
424
- Input(self._settings_component(ViewSettings.Ids.PLUME_SMOOTHING), "value"),
425
- Input(
426
- self._settings_component(ViewSettings.Ids.VISUALIZATION_THRESHOLD),
427
- "value",
428
- ),
429
- Input(
430
- self._settings_component(ViewSettings.Ids.VISUALIZATION_UPDATE),
431
- "n_clicks",
432
- ),
433
- Input(self._settings_component(ViewSettings.Ids.MASS_UNIT), "value"),
434
- Input(ViewSettings.Ids.OPTIONS_DIALOG_OPTIONS, "value"),
435
- Input(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "value"),
436
- Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
437
- State(self._view_component(MapViewElement.Ids.DECKGL_MAP), "views"),
438
- )
439
- def update_map_attribute(
440
- attribute: MapAttribute,
441
- date: int,
442
- formation: str,
443
- realization: List[int],
444
- statistic: str,
445
- color_map_name: str,
446
- cm_min_auto: List[str],
447
- cm_min_val: Optional[float],
448
- cm_max_auto: List[str],
449
- cm_max_val: Optional[float],
450
- plume_threshold: Optional[float],
451
- plume_smoothing: Optional[float],
452
- visualization_threshold: Optional[float],
453
- visualization_update: int,
454
- mass_unit: str,
455
- options_dialog_options: List[int],
456
- selected_wells: List[str],
457
- ensemble: str,
458
- current_views: List[Any],
459
- ) -> Tuple[List[Dict[Any, Any]], List[Any], Dict[Any, Any]]:
460
- # Unable to clear cache (when needed) without the protected member
461
- # pylint: disable=protected-access
462
- self._visualization_info = process_visualization_info(
463
- visualization_update,
464
- visualization_threshold,
465
- mass_unit,
466
- self._visualization_info,
467
- self._surface_server._image_cache,
432
+ if self._content["maps"]:
433
+
434
+ @callback(
435
+ Output(self._view_component(MapViewElement.Ids.DATE_SLIDER), "marks"),
436
+ Output(self._view_component(MapViewElement.Ids.DATE_SLIDER), "value"),
437
+ Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
468
438
  )
469
- if self._visualization_info["change"]:
470
- return [], no_update, no_update
471
- attribute = MapAttribute(attribute)
472
- if len(realization) == 0 or ensemble is None:
473
- raise PreventUpdate
474
- datestr = self._ensemble_dates(ensemble)[date]
475
- # Contour data
476
- contour_data = None
477
- if attribute in (MapAttribute.SGAS_PLUME, MapAttribute.AMFG_PLUME):
478
- contour_data = {
479
- "property": property_origin(attribute, self._map_attribute_names),
480
- "threshold": plume_threshold,
481
- "smoothing": plume_smoothing,
439
+ def set_dates(
440
+ ensemble: str,
441
+ ) -> Tuple[Dict[int, Dict[str, Any]], Optional[int]]:
442
+ if ensemble is None:
443
+ return {}, None
444
+ # Dates
445
+ date_list = self._ensemble_dates(ensemble)
446
+ dates = {
447
+ i: {
448
+ "label": f"{d[:4]}",
449
+ "style": {"writingMode": "vertical-rl"},
450
+ }
451
+ for i, d in enumerate(date_list)
482
452
  }
483
- # Surface
484
- surf_data, summed_mass = None, None
485
- if formation is not None and len(realization) > 0:
486
- surf_data, summed_mass = SurfaceData.from_server(
487
- server=self._surface_server,
488
- provider=self._ensemble_surface_providers[ensemble],
489
- address=derive_surface_address(
490
- formation,
491
- attribute,
492
- datestr,
493
- realization,
494
- self._map_attribute_names,
495
- statistic,
496
- contour_data,
453
+ if len(dates.keys()) > 0:
454
+ return dates, max(dates.keys())
455
+ return dates, None
456
+
457
+ @callback(
458
+ Output(self._view_component(MapViewElement.Ids.DATE_WRAPPER), "style"),
459
+ Input(self._settings_component(ViewSettings.Ids.PROPERTY), "value"),
460
+ )
461
+ def toggle_date_slider(attribute: str) -> Dict[str, str]:
462
+ if MapType[MapAttribute(attribute).name].value == "MIGRATION_TIME":
463
+ return {"display": "none"}
464
+ return {}
465
+
466
+ @callback(
467
+ Output(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "options"),
468
+ Output(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "value"),
469
+ Output(ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "style"),
470
+ Output(ViewSettings.Ids.WELL_FILTER_HEADER, "style"),
471
+ Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
472
+ )
473
+ def set_well_options(
474
+ ensemble: str,
475
+ ) -> Tuple[List[Any], List[str], Dict[Any, Any], Dict[Any, Any]]:
476
+ return (
477
+ [{"label": i, "value": i} for i in self._well_pick_names[ensemble]],
478
+ self._well_pick_names[ensemble],
479
+ {
480
+ "display": (
481
+ "block" if self._well_pick_names[ensemble] else "none"
482
+ ),
483
+ "height": f"{len(self._well_pick_names[ensemble]) * 22}px",
484
+ },
485
+ {
486
+ "flex": 3,
487
+ "minWidth": "20px",
488
+ "display": (
489
+ "block" if self._well_pick_names[ensemble] else "none"
490
+ ),
491
+ },
492
+ )
493
+
494
+ # Cannot avoid many arguments and/or locals since all layers of the DeckGL map
495
+ # need to be updated simultaneously
496
+ # pylint: disable=too-many-arguments,too-many-locals
497
+ @callback(
498
+ Output(self._view_component(MapViewElement.Ids.DECKGL_MAP), "layers"),
499
+ Output(self._view_component(MapViewElement.Ids.DECKGL_MAP), "children"),
500
+ Output(self._view_component(MapViewElement.Ids.DECKGL_MAP), "views"),
501
+ inputs={
502
+ "attribute": Input(
503
+ self._settings_component(ViewSettings.Ids.PROPERTY), "value"
497
504
  ),
498
- color_map_range=(
499
- cm_min_val if len(cm_min_auto) == 0 else None,
500
- cm_max_val if len(cm_max_auto) == 0 else None,
505
+ "date": Input(
506
+ self._view_component(MapViewElement.Ids.DATE_SLIDER), "value"
501
507
  ),
502
- color_map_name=color_map_name,
503
- readable_name_=readable_name(attribute),
504
- visualization_info=self._visualization_info,
505
- map_attribute_names=self._map_attribute_names,
506
- )
507
- assert isinstance(self._visualization_info["unit"], str)
508
- surf_data, self._summed_co2 = process_summed_mass(
509
- formation,
510
- realization,
511
- datestr,
512
- attribute,
513
- summed_mass,
514
- surf_data,
515
- self._summed_co2,
516
- self._visualization_info["unit"],
508
+ "formation": Input(
509
+ self._settings_component(ViewSettings.Ids.FORMATION), "value"
510
+ ),
511
+ "realization": Input(
512
+ self._settings_component(ViewSettings.Ids.REALIZATION), "value"
513
+ ),
514
+ "statistic": Input(
515
+ self._settings_component(ViewSettings.Ids.STATISTIC), "value"
516
+ ),
517
+ "color_map_name": Input(
518
+ self._settings_component(ViewSettings.Ids.COLOR_SCALE), "value"
519
+ ),
520
+ "cm_min_auto": Input(
521
+ self._settings_component(ViewSettings.Ids.CM_MIN_AUTO), "value"
522
+ ),
523
+ "cm_min_val": Input(
524
+ self._settings_component(ViewSettings.Ids.CM_MIN), "value"
525
+ ),
526
+ "cm_max_auto": Input(
527
+ self._settings_component(ViewSettings.Ids.CM_MAX_AUTO), "value"
528
+ ),
529
+ "cm_max_val": Input(
530
+ self._settings_component(ViewSettings.Ids.CM_MAX), "value"
531
+ ),
532
+ "plume_threshold": Input(
533
+ self._settings_component(ViewSettings.Ids.PLUME_THRESHOLD),
534
+ "value",
535
+ ),
536
+ "plume_smoothing": Input(
537
+ self._settings_component(ViewSettings.Ids.PLUME_SMOOTHING),
538
+ "value",
539
+ ),
540
+ "visualization_update": Input(
541
+ self._settings_component(ViewSettings.Ids.VISUALIZATION_UPDATE),
542
+ "n_clicks",
543
+ ),
544
+ "mass_unit": Input(
545
+ self._settings_component(ViewSettings.Ids.MASS_UNIT), "value"
546
+ ),
547
+ "mass_unit_update": Input(
548
+ self._settings_component(ViewSettings.Ids.MASS_UNIT_UPDATE),
549
+ "n_clicks",
550
+ ),
551
+ "options_dialog_options": Input(
552
+ ViewSettings.Ids.OPTIONS_DIALOG_OPTIONS, "value"
553
+ ),
554
+ "selected_wells": Input(
555
+ ViewSettings.Ids.OPTIONS_DIALOG_WELL_FILTER, "value"
556
+ ),
557
+ "ensemble": Input(
558
+ self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"
559
+ ),
560
+ "current_views": State(
561
+ self._view_component(MapViewElement.Ids.DECKGL_MAP), "views"
562
+ ),
563
+ "thresholds": [Input(id, "value") for id in self._threshold_ids],
564
+ },
517
565
  )
518
- plume_polygon = None
519
- if contour_data is not None:
520
- plume_polygon = get_plume_polygon(
521
- self._ensemble_surface_providers[ensemble],
522
- realization,
566
+ def update_map_attribute(
567
+ attribute: MapAttribute,
568
+ date: int,
569
+ formation: str,
570
+ realization: List[int],
571
+ statistic: str,
572
+ color_map_name: str,
573
+ cm_min_auto: List[str],
574
+ cm_min_val: Optional[float],
575
+ cm_max_auto: List[str],
576
+ cm_max_val: Optional[float],
577
+ plume_threshold: Optional[float],
578
+ plume_smoothing: Optional[float],
579
+ visualization_update: int,
580
+ mass_unit: str,
581
+ mass_unit_update: int,
582
+ options_dialog_options: List[int],
583
+ selected_wells: List[str],
584
+ ensemble: str,
585
+ current_views: List[Any],
586
+ thresholds: List[float],
587
+ ) -> Tuple[List[Dict[Any, Any]], Optional[List[Any]], Dict[Any, Any]]:
588
+ # Unable to clear cache (when needed) without the protected member
589
+ # pylint: disable=protected-access
590
+ current_thresholds = dict(zip(self._threshold_ids, thresholds))
591
+ assert visualization_update >= 0 # Need the input to trigger callback
592
+ assert mass_unit_update >= 0 # These are just to silence pylint
593
+ self._visualization_info = process_visualization_info(
594
+ attribute,
595
+ current_thresholds,
596
+ mass_unit,
597
+ self._visualization_info,
598
+ self._surface_server._image_cache,
599
+ )
600
+ if self._visualization_info["change"]:
601
+ return [], None, no_update
602
+ attribute = MapAttribute(attribute)
603
+ if len(realization) == 0 or ensemble is None:
604
+ raise PreventUpdate
605
+ if isinstance(date, int):
606
+ datestr = self._ensemble_dates(ensemble)[date]
607
+ elif date is None:
608
+ datestr = None
609
+ # Contour data
610
+ contour_data = None
611
+ if MapType[MapAttribute(attribute).name].value == "PLUME":
612
+ contour_data = {
613
+ "property": property_origin(
614
+ attribute, self._map_attribute_names
615
+ ),
616
+ "threshold": plume_threshold,
617
+ "smoothing": plume_smoothing,
618
+ }
619
+ # Surface
620
+ surf_data, summed_mass = None, None
621
+ if formation is not None and len(realization) > 0:
622
+ surf_data, summed_mass = SurfaceData.from_server(
623
+ server=self._surface_server,
624
+ provider=self._ensemble_surface_providers[ensemble],
625
+ address=derive_surface_address(
626
+ formation,
627
+ attribute,
628
+ datestr,
629
+ realization,
630
+ self._map_attribute_names,
631
+ statistic,
632
+ contour_data,
633
+ ),
634
+ color_map_range=(
635
+ cm_min_val if len(cm_min_auto) == 0 else None,
636
+ cm_max_val if len(cm_max_auto) == 0 else None,
637
+ ),
638
+ color_map_name=color_map_name,
639
+ readable_name_=readable_name(attribute),
640
+ visualization_info=self._visualization_info,
641
+ map_attribute_names=self._map_attribute_names,
642
+ )
643
+ assert isinstance(self._visualization_info["unit"], str)
644
+ surf_data, self._summed_co2 = process_summed_mass(
523
645
  formation,
646
+ realization,
524
647
  datestr,
525
- contour_data,
648
+ attribute,
649
+ summed_mass,
650
+ surf_data,
651
+ self._summed_co2,
652
+ self._visualization_info["unit"],
526
653
  )
527
- # Create layers and view bounds
528
- layers = create_map_layers(
529
- formation=formation,
530
- surface_data=surf_data,
531
- fault_polygon_url=(
532
- self._fault_polygon_handlers[ensemble].extract_fault_polygon_url(
533
- formation,
654
+ plume_polygon = None
655
+ if contour_data is not None:
656
+ plume_polygon = get_plume_polygon(
657
+ self._ensemble_surface_providers[ensemble],
534
658
  realization,
659
+ formation,
660
+ datestr,
661
+ contour_data,
535
662
  )
536
- ),
537
- file_containment_boundary=self._polygon_files[0][ensemble],
538
- file_hazardous_boundary=self._polygon_files[1][ensemble],
539
- well_pick_provider=self._well_pick_provider[ensemble],
540
- plume_extent_data=plume_polygon,
541
- options_dialog_options=options_dialog_options,
542
- selected_wells=selected_wells,
543
- )
544
- annotations = create_map_annotations(
545
- formation=formation,
546
- surface_data=surf_data,
547
- colortables=self._color_tables,
548
- attribute=attribute,
549
- unit=self._visualization_info["unit"],
663
+ # Create layers and view bounds
664
+ fault_polygon_url = self._fault_polygon_handlers[
665
+ ensemble
666
+ ].extract_fault_polygon_url(formation, realization)
667
+ hazardous_polygon_url = self._polygon_handlers[
668
+ ensemble
669
+ ].extract_hazardous_poly_url(realization)
670
+ containment_polygon_url = self._polygon_handlers[
671
+ ensemble
672
+ ].extract_containment_poly_url(realization)
673
+ layers = create_map_layers(
674
+ realizations=realization,
675
+ formation=formation,
676
+ surface_data=surf_data,
677
+ fault_polygon_url=fault_polygon_url,
678
+ containment_bounds_url=containment_polygon_url,
679
+ haz_bounds_url=hazardous_polygon_url,
680
+ well_pick_provider=self._well_pick_provider.get(ensemble, None),
681
+ plume_extent_data=plume_polygon,
682
+ options_dialog_options=options_dialog_options,
683
+ selected_wells=selected_wells,
684
+ )
685
+ annotations = create_map_annotations(
686
+ formation=formation,
687
+ surface_data=surf_data,
688
+ colortables=self._color_tables,
689
+ attribute=attribute,
690
+ unit=self._visualization_info["unit"],
691
+ )
692
+ viewports = no_update if current_views else create_map_viewports()
693
+ return layers, annotations, viewports
694
+
695
+ @callback(
696
+ Output(ViewSettings.Ids.OPTIONS_DIALOG, "open"),
697
+ Input(ViewSettings.Ids.OPTIONS_DIALOG_BUTTON, "n_clicks"),
550
698
  )
551
- viewports = no_update if current_views else create_map_viewports()
552
- return layers, annotations, viewports
699
+ def open_close_options_dialog(_n_clicks: Optional[int]) -> bool:
700
+ if _n_clicks is not None:
701
+ return _n_clicks > 0
702
+ raise PreventUpdate
553
703
 
554
- @callback(
555
- Output(ViewSettings.Ids.OPTIONS_DIALOG, "open"),
556
- Input(ViewSettings.Ids.OPTIONS_DIALOG_BUTTON, "n_clicks"),
557
- )
558
- def open_close_options_dialog(_n_clicks: Optional[int]) -> bool:
559
- if _n_clicks is not None:
560
- return _n_clicks > 0
561
- raise PreventUpdate
704
+ @callback(
705
+ Output(ViewSettings.Ids.VISUALIZATION_THRESHOLD_DIALOG, "open"),
706
+ Input(ViewSettings.Ids.VISUALIZATION_THRESHOLD_BUTTON, "n_clicks"),
707
+ )
708
+ def open_close_thresholds(_n_clicks: Optional[int]) -> bool:
709
+ if _n_clicks is not None:
710
+ return _n_clicks > 0
711
+ raise PreventUpdate
562
712
 
563
713
  @callback(
564
714
  Output(ViewSettings.Ids.FEEDBACK, "open"),
@@ -569,42 +719,46 @@ class CO2Leakage(WebvizPluginABC):
569
719
  return _n_clicks > 0
570
720
  raise PreventUpdate
571
721
 
572
- @callback(
573
- Output(self._view_component(MapViewElement.Ids.TOP_ELEMENT), "style"),
574
- Output(self._view_component(MapViewElement.Ids.BOTTOM_ELEMENT), "style"),
575
- Output(self._view_component(MapViewElement.Ids.BAR_PLOT), "style"),
576
- Output(self._view_component(MapViewElement.Ids.TIME_PLOT), "style"),
577
- Output(
578
- self._view_component(MapViewElement.Ids.TIME_PLOT_ONE_REAL), "style"
579
- ),
580
- Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
581
- Input(self._view_component(MapViewElement.Ids.SIZE_SLIDER), "value"),
582
- State(self._view_component(MapViewElement.Ids.TOP_ELEMENT), "style"),
583
- State(self._view_component(MapViewElement.Ids.BOTTOM_ELEMENT), "style"),
584
- Input(self._settings_component(ViewSettings.Ids.GRAPH_SOURCE), "value"),
585
- )
586
- def resize_plots(
587
- ensemble: str,
588
- slider_value: float,
589
- top_style: Dict,
590
- bottom_style: Dict,
591
- source: GraphSource,
592
- ) -> List[Dict]:
593
- bottom_style["height"] = f"{slider_value}vh"
594
- top_style["height"] = f"{80 - slider_value}vh"
722
+ if self._content["maps"] and self._content["any_table"]:
723
+
724
+ @callback(
725
+ Output(self._view_component(MapViewElement.Ids.TOP_ELEMENT), "style"),
726
+ Output(
727
+ self._view_component(MapViewElement.Ids.BOTTOM_ELEMENT), "style"
728
+ ),
729
+ Output(self._view_component(MapViewElement.Ids.BAR_PLOT), "style"),
730
+ Output(self._view_component(MapViewElement.Ids.TIME_PLOT), "style"),
731
+ Output(
732
+ self._view_component(MapViewElement.Ids.STATISTICS_PLOT), "style"
733
+ ),
734
+ Input(self._settings_component(ViewSettings.Ids.ENSEMBLE), "value"),
735
+ Input(self._view_component(MapViewElement.Ids.SIZE_SLIDER), "value"),
736
+ State(self._view_component(MapViewElement.Ids.TOP_ELEMENT), "style"),
737
+ State(self._view_component(MapViewElement.Ids.BOTTOM_ELEMENT), "style"),
738
+ Input(self._settings_component(ViewSettings.Ids.GRAPH_SOURCE), "value"),
739
+ )
740
+ def resize_plots(
741
+ ensemble: str,
742
+ slider_value: float,
743
+ top_style: Dict,
744
+ bottom_style: Dict,
745
+ source: GraphSource,
746
+ ) -> List[Dict]:
747
+ bottom_style["height"] = f"{slider_value}vh"
748
+ top_style["height"] = f"{80 - slider_value}vh"
595
749
 
596
- styles = [{"height": f"{slider_value * 0.9 - 4}vh", "width": "90%"}] * 3
597
- if source == GraphSource.UNSMRY and self._unsmry_providers is None:
598
- styles = [{"display": "none"}] * 3
599
- elif (
600
- source == GraphSource.CONTAINMENT_MASS
601
- and ensemble not in self._co2_table_providers
602
- ):
603
- styles = [{"display": "none"}] * 3
604
- elif (
605
- source == GraphSource.CONTAINMENT_ACTUAL_VOLUME
606
- and ensemble not in self._co2_actual_volume_table_providers
607
- ):
608
- styles = [{"display": "none"}] * 3
750
+ styles = [{"height": f"{slider_value * 0.9 - 4}vh", "width": "90%"}] * 3
751
+ if source == GraphSource.UNSMRY and self._unsmry_providers is None:
752
+ styles = [{"display": "none"}] * 3
753
+ elif (
754
+ source == GraphSource.CONTAINMENT_MASS
755
+ and ensemble not in self._co2_table_providers
756
+ ):
757
+ styles = [{"display": "none"}] * 3
758
+ elif (
759
+ source == GraphSource.CONTAINMENT_ACTUAL_VOLUME
760
+ and ensemble not in self._co2_actual_volume_table_providers
761
+ ):
762
+ styles = [{"display": "none"}] * 3
609
763
 
610
- return [top_style, bottom_style] + styles
764
+ return [top_style, bottom_style] + styles