webviz-subsurface 0.2.44__py3-none-any.whl → 0.2.46__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.
@@ -33,7 +33,8 @@ class Col:
33
33
 
34
34
  class PolygonType(StrEnum):
35
35
  SIMULATED = "simulated"
36
- HAZARDUOUS_BOUNDARY = "hazarduous_boundary"
36
+ HAZARDOUS_BOUNDARY = "hazardous_boundary" # Keep for backward compatibility
37
+ NOGO_BOUNDARY = "nogo_boundary"
37
38
  CONTAINMENT_BOUNDARY = "containment_boundary"
38
39
 
39
40
 
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.44'
32
- __version_tuple__ = version_tuple = (0, 2, 44)
31
+ __version__ = version = '0.2.46'
32
+ __version_tuple__ = version_tuple = (0, 2, 46)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -40,6 +40,8 @@ from webviz_subsurface.plugins._co2_migration._utilities.generic import (
40
40
  MapAttribute,
41
41
  MapThresholds,
42
42
  MapType,
43
+ check_hazardous_polygon,
44
+ deactivate_polygon_warnings,
43
45
  )
44
46
  from webviz_subsurface.plugins._co2_migration._utilities.initialization import (
45
47
  init_containment_data_providers,
@@ -95,7 +97,7 @@ class CO2Migration(WebvizPluginABC):
95
97
  * **`map_surface_names_to_fault_polygons`:** Mapping between surface map names and
96
98
  surface names used by the fault polygons
97
99
  * **`boundary_settings`:** Settings for polygons representing the containment and
98
- hazardous areas
100
+ nogo areas
99
101
  ---
100
102
 
101
103
  This plugin is tightly linked to the FMU CCS post-process available in the ccs-scripts
@@ -141,17 +143,17 @@ class CO2Migration(WebvizPluginABC):
141
143
  Similar for `map_surface_names_to_fault_polygons`.
142
144
 
143
145
  `boundary_settings` is the final override option, and it can be used to specify
144
- polygons representing the containment and hazardous areas. By default, the polygons are
146
+ polygons representing the containment and nogo areas. By default, the polygons are
145
147
  expected to be named:
146
148
  - `share/results/polygons/containment--boundary.csv`
147
- - `share/results/polygons/hazarduous--boundary.csv`
149
+ - `share/results/polygons/nogo--boundary.csv`
148
150
 
149
151
  This corresponds to the following input:
150
152
  ```
151
153
  boundary_settings:
152
154
  polygon_file_pattern: share/results/polygons/*.csv
153
155
  attribute: boundary
154
- hazardous_name: hazardous
156
+ nogo_name: nogo
155
157
  containment_name: containment
156
158
  ```
157
159
  All four settings are optional, and if not specified, the default values are used.
@@ -182,6 +184,8 @@ class CO2Migration(WebvizPluginABC):
182
184
  super().__init__()
183
185
  self._error_message = ""
184
186
  try:
187
+ deactivate_polygon_warnings()
188
+ check_hazardous_polygon(boundary_settings)
185
189
  ensemble_paths = {
186
190
  ensemble_name: webviz_settings.shared_settings["scratch_ensembles"][
187
191
  ensemble_name
@@ -435,6 +439,13 @@ class CO2Migration(WebvizPluginABC):
435
439
  "cm_max_val": Input(
436
440
  self._settings_component(ViewSettings.Ids.CM_MAX), "value"
437
441
  ),
442
+ "contour_switch": Input(
443
+ self._settings_component(ViewSettings.Ids.CONTOURS_SWITCH), "value"
444
+ ),
445
+ "contour_quantity": Input(
446
+ self._settings_component(ViewSettings.Ids.CONTOURS_QUANTITY),
447
+ "value",
448
+ ),
438
449
  "plume_threshold": Input(
439
450
  self._settings_component(ViewSettings.Ids.PLUME_THRESHOLD),
440
451
  "value",
@@ -480,12 +491,14 @@ class CO2Migration(WebvizPluginABC):
480
491
  cm_min_val: Optional[float],
481
492
  cm_max_auto: List[str],
482
493
  cm_max_val: Optional[float],
494
+ contour_switch: List[str],
495
+ contour_quantity: Optional[float],
483
496
  plume_threshold: Optional[float],
484
497
  plume_smoothing: Optional[float],
485
498
  visualization_update: int,
486
499
  mass_unit: str,
487
500
  mass_unit_update: int,
488
- options_dialog_options: List[int],
501
+ options_dialog_options: List[str],
489
502
  selected_wells: List[str],
490
503
  ensemble: str,
491
504
  current_views: List[Any],
@@ -545,13 +558,12 @@ class CO2Migration(WebvizPluginABC):
545
558
  map_attribute_names=self._map_attribute_names,
546
559
  )
547
560
  assert isinstance(self._visualization_info["unit"], str)
548
- surf_data, self._summed_co2 = process_summed_mass(
561
+ current_summed_mass, self._summed_co2 = process_summed_mass(
549
562
  formation,
550
563
  realization,
551
564
  datestr,
552
565
  attribute,
553
566
  summed_mass,
554
- surf_data,
555
567
  self._summed_co2,
556
568
  self._visualization_info["unit"],
557
569
  )
@@ -568,6 +580,9 @@ class CO2Migration(WebvizPluginABC):
568
580
  fault_polygon_url = self._fault_polygon_handlers[
569
581
  ensemble
570
582
  ].extract_fault_polygon_url(formation, realization)
583
+ nogo_polygon_url = self._polygon_handlers[ensemble].extract_nogo_poly_url(
584
+ realization
585
+ )
571
586
  hazardous_polygon_url = self._polygon_handlers[
572
587
  ensemble
573
588
  ].extract_hazardous_poly_url(realization)
@@ -580,11 +595,14 @@ class CO2Migration(WebvizPluginABC):
580
595
  surface_data=surf_data,
581
596
  fault_polygon_url=fault_polygon_url,
582
597
  containment_bounds_url=containment_polygon_url,
583
- haz_bounds_url=hazardous_polygon_url,
598
+ nogo_bounds_url=nogo_polygon_url,
599
+ hazardous_bounds_url=hazardous_polygon_url,
584
600
  well_pick_provider=self._well_pick_provider.get(ensemble, None),
585
601
  plume_extent_data=plume_polygon,
586
602
  options_dialog_options=options_dialog_options,
587
603
  selected_wells=selected_wells,
604
+ show_contours=len(contour_switch) > 0,
605
+ num_contours=contour_quantity,
588
606
  )
589
607
  annotations = create_map_annotations(
590
608
  formation=formation,
@@ -592,6 +610,11 @@ class CO2Migration(WebvizPluginABC):
592
610
  colortables=self._color_tables,
593
611
  attribute=attribute,
594
612
  unit=self._visualization_info["unit"],
613
+ current_total=current_summed_mass,
614
+ options=options_dialog_options,
615
+ con_url=containment_polygon_url,
616
+ haz_url=hazardous_polygon_url,
617
+ nogo_url=nogo_polygon_url,
595
618
  )
596
619
  viewports = no_update if current_views else create_map_viewports()
597
620
  return layers, annotations, viewports
@@ -7,7 +7,7 @@ import geojson
7
7
  import numpy as np
8
8
  import plotly.graph_objects as go
9
9
  import webviz_subsurface_components as wsc
10
- from dash import dcc, no_update
10
+ from dash import dcc, html, no_update
11
11
  from flask_caching import Cache
12
12
 
13
13
  from webviz_subsurface._providers import (
@@ -234,12 +234,127 @@ def _find_legend_title(attribute: MapAttribute, unit: str) -> str:
234
234
  return ""
235
235
 
236
236
 
237
+ def _create_summed_mass_annotation(
238
+ attribute: MapAttribute,
239
+ summed_mass: Optional[float],
240
+ unit: str,
241
+ ) -> Union[str, tuple]:
242
+ annotation = (
243
+ html.P(
244
+ [
245
+ f"Total {MapAttribute[attribute.name].value.lower()}:",
246
+ html.Br(),
247
+ f"{summed_mass:.2f} {unit}",
248
+ ]
249
+ )
250
+ if MapType[attribute.name].value == "MASS" and summed_mass is not None
251
+ else ""
252
+ )
253
+ return html.Div(
254
+ annotation,
255
+ style={
256
+ "position": "absolute",
257
+ "top": "210px",
258
+ "right": "4px",
259
+ "backgroundColor": "rgba(255,255,255,0.8)",
260
+ "padding": "1px 1px",
261
+ "fontWeight": "bold",
262
+ "fontSize": "15px",
263
+ "display": "block",
264
+ },
265
+ )
266
+
267
+
268
+ def _create_polygon_legend(
269
+ options: List[str],
270
+ con_url: Optional[str],
271
+ haz_url: Optional[str], # Keep for backward compatibility
272
+ nogo_url: Optional[str],
273
+ ) -> List:
274
+ legend: List = []
275
+ hide_con = con_url is None or LayoutLabels.SHOW_CONTAINMENT_POLYGON not in options
276
+ hide_nogo = (
277
+ nogo_url is None and haz_url is None
278
+ ) or LayoutLabels.SHOW_NOGO_POLYGON not in options
279
+ outline = LayoutLabels.SHOW_POLYGONS_AS_OUTLINES in options
280
+ if hide_con and hide_nogo:
281
+ return legend
282
+ legend_items = []
283
+ square = {"width": "12px", "height": "12px", "marginRight": "6px"}
284
+ text = {"color": "black", "fontSize": "14px"}
285
+ if not hide_con:
286
+ legend_items.append(
287
+ html.Div(
288
+ style={"display": "flex", "alignItems": "center"},
289
+ children=[
290
+ html.Div(
291
+ style={
292
+ **square,
293
+ "backgroundColor": "transparent"
294
+ if outline
295
+ else "rgba(0, 172, 0, 0.47)",
296
+ "border": "3px solid rgba(0, 172, 0, 0.70)"
297
+ if outline
298
+ else "transparent",
299
+ }
300
+ ),
301
+ html.Div("Containment Polygon", style=text),
302
+ ],
303
+ )
304
+ )
305
+ if not hide_nogo:
306
+ legend_items.append(
307
+ html.Div(
308
+ style={"display": "flex", "alignItems": "center"},
309
+ children=[
310
+ html.Div(
311
+ style={
312
+ **square,
313
+ "backgroundColor": "transparent"
314
+ if outline
315
+ else "rgba(200, 0, 0, 0.47)",
316
+ "border": "3px solid rgba(200, 0, 0, 0.70)"
317
+ if outline
318
+ else "transparent",
319
+ }
320
+ ),
321
+ html.Div("No-go Polygon", style=text),
322
+ ],
323
+ )
324
+ )
325
+ legend.append(
326
+ wsc.ViewAnnotation(
327
+ id="polygon_legends",
328
+ children=html.Div(
329
+ children=legend_items,
330
+ style={
331
+ "position": "absolute",
332
+ "top": "50px",
333
+ "left": "4px",
334
+ "backgroundColor": "rgba(255,255,255,0.9)",
335
+ "padding": "6px 8px",
336
+ "borderRadius": "4px",
337
+ "boxShadow": "0 0 4px rgba(0,0,0,0.2)",
338
+ "zIndex": 10,
339
+ },
340
+ ),
341
+ )
342
+ )
343
+ return legend
344
+
345
+
346
+ # pylint: disable=too-many-arguments, too-many-locals
237
347
  def create_map_annotations(
238
348
  formation: str,
239
349
  surface_data: Optional[SurfaceData],
240
350
  colortables: List[Dict[str, Any]],
241
351
  attribute: MapAttribute,
242
352
  unit: str,
353
+ current_total: Optional[float],
354
+ options: List[str],
355
+ con_url: Optional[str],
356
+ haz_url: Optional[str],
357
+ nogo_url: Optional[str],
243
358
  ) -> List[wsc.ViewAnnotation]:
244
359
  annotations = []
245
360
  if (
@@ -268,7 +383,9 @@ def create_map_annotations(
268
383
  colorTables=colortables,
269
384
  ),
270
385
  wsc.ViewFooter(children=formation),
271
- ],
386
+ _create_summed_mass_annotation(attribute, current_total, unit),
387
+ ]
388
+ + _create_polygon_legend(options, con_url, haz_url, nogo_url),
272
389
  )
273
390
  )
274
391
  return annotations
@@ -286,7 +403,8 @@ def create_map_viewports() -> Dict:
286
403
  "colormap-layer",
287
404
  "fault-polygons-layer",
288
405
  "license-boundary-layer",
289
- "hazardous-boundary-layer",
406
+ "nogo-boundary-layer",
407
+ "hazardous-boundary-layer", # Keep for backward compatibility
290
408
  "well-picks-layer",
291
409
  "plume-polygon-layer",
292
410
  ],
@@ -302,16 +420,35 @@ def create_map_layers(
302
420
  surface_data: Optional[SurfaceData],
303
421
  fault_polygon_url: Optional[str],
304
422
  containment_bounds_url: Optional[str],
305
- haz_bounds_url: Optional[str],
423
+ nogo_bounds_url: Optional[str],
424
+ hazardous_bounds_url: Optional[str], # Keep for backward compatibility
306
425
  well_pick_provider: Optional[EnsembleWellPicks],
307
426
  plume_extent_data: Optional[geojson.FeatureCollection],
308
- options_dialog_options: List[int],
427
+ options_dialog_options: List[str],
309
428
  selected_wells: List[str],
429
+ show_contours: bool,
430
+ num_contours: Optional[float],
310
431
  ) -> List[Dict]:
311
432
  layers = []
433
+ outline = LayoutLabels.SHOW_POLYGONS_AS_OUTLINES in options_dialog_options
312
434
  if surface_data is not None:
313
435
  # Update ColormapLayer
314
436
  meta = surface_data.meta_data
437
+
438
+ # Generate contour lines
439
+ contours = []
440
+ if (
441
+ show_contours
442
+ and surface_data.color_map_range[0] is not None
443
+ and surface_data.color_map_range[1] is not None
444
+ and num_contours is not None
445
+ ):
446
+ min_val, max_val = surface_data.color_map_range
447
+ assert min_val is not None and max_val is not None
448
+ buffer = 0.01 * (max_val - min_val) # Strange effects at min_val/max_val
449
+ step = (max_val - min_val + 2 * buffer) / (np.round(num_contours) + 1)
450
+ contours = [min_val + step - buffer, step]
451
+
315
452
  layers.append(
316
453
  {
317
454
  "@@type": "MapLayer",
@@ -327,6 +464,7 @@ def create_map_layers(
327
464
  "colorMapName": surface_data.color_map_name,
328
465
  "colorMapRange": surface_data.color_map_range,
329
466
  "material": False,
467
+ "contours": contours,
330
468
  }
331
469
  )
332
470
 
@@ -353,24 +491,52 @@ def create_map_layers(
353
491
  "name": "Containment Polygon",
354
492
  "id": "license-boundary-layer",
355
493
  "data": containment_bounds_url,
356
- "stroked": False,
494
+ "stroked": outline,
495
+ "filled": not outline,
357
496
  "getFillColor": [0, 172, 0, 120],
497
+ "getLineColor": [0, 172, 0, 120],
498
+ "getLineWidth": 3,
499
+ "lineWidthUnits": "pixels",
500
+ "visible": True,
501
+ }
502
+ )
503
+
504
+ if (
505
+ nogo_bounds_url is not None
506
+ and LayoutLabels.SHOW_NOGO_POLYGON in options_dialog_options
507
+ ):
508
+ layers.append(
509
+ {
510
+ "@@type": "GeoJsonLayer",
511
+ "name": "No-go Polygon",
512
+ "id": "nogo-boundary-layer",
513
+ "data": nogo_bounds_url,
514
+ "stroked": outline,
515
+ "filled": not outline,
516
+ "getFillColor": [200, 0, 0, 120],
517
+ "getLineColor": [200, 0, 0, 180],
518
+ "getLineWidth": 3,
519
+ "lineWidthUnits": "pixels",
358
520
  "visible": True,
359
521
  }
360
522
  )
361
523
 
362
524
  if (
363
- haz_bounds_url is not None
364
- and LayoutLabels.SHOW_HAZARDOUS_POLYGON in options_dialog_options
525
+ hazardous_bounds_url is not None
526
+ and LayoutLabels.SHOW_NOGO_POLYGON in options_dialog_options
365
527
  ):
366
528
  layers.append(
367
529
  {
368
530
  "@@type": "GeoJsonLayer",
369
- "name": "Hazardous Polygon",
531
+ "name": "No-go Polygon",
370
532
  "id": "hazardous-boundary-layer",
371
- "data": haz_bounds_url,
372
- "stroked": False,
533
+ "data": hazardous_bounds_url,
534
+ "stroked": outline,
535
+ "filled": not outline,
373
536
  "getFillColor": [200, 0, 0, 120],
537
+ "getLineColor": [200, 0, 0, 180],
538
+ "getLineWidth": 3,
539
+ "lineWidthUnits": "pixels",
374
540
  "visible": True,
375
541
  }
376
542
  )
@@ -551,7 +717,7 @@ def process_containment_info(
551
717
  mark_choice=mark_choice,
552
718
  sorting=sorting,
553
719
  phases=[phase for phase in menu_options["phases"] if phase != "total"],
554
- containments=["hazardous", "outside", "contained"],
720
+ containments=["nogo", "outside", "contained"],
555
721
  plume_groups=plume_groups,
556
722
  use_stats=lines_to_show == "stat",
557
723
  date_option=date_option,
@@ -631,20 +797,18 @@ def process_summed_mass(
631
797
  datestr: Optional[str],
632
798
  attribute: MapAttribute,
633
799
  summed_mass: Optional[float],
634
- surf_data: Optional[SurfaceData],
635
800
  summed_co2: Dict[str, float],
636
801
  unit: str,
637
- ) -> Tuple[Optional[SurfaceData], Dict[str, float]]:
802
+ ) -> Tuple[Optional[float], Dict[str, float]]:
638
803
  summed_co2_key = f"{formation}-{realization[0]}-{datestr}-{attribute}-{unit}"
804
+ current_total = None
639
805
  if len(realization) == 1:
640
806
  if MapType[MapAttribute(attribute).name].value == "MASS":
641
807
  if summed_mass is not None and summed_co2_key not in summed_co2:
642
808
  summed_co2[summed_co2_key] = summed_mass
643
- if summed_co2_key in summed_co2 and surf_data is not None:
644
- surf_data.readable_name += (
645
- f" ({unit}) (Total: {summed_co2[summed_co2_key]:.2E}): "
646
- )
647
- return surf_data, summed_co2
809
+ if summed_co2_key in summed_co2:
810
+ current_total = summed_co2[summed_co2_key]
811
+ return current_total, summed_co2
648
812
 
649
813
 
650
814
  def export_figure_data_to_csv(
@@ -11,7 +11,6 @@ import pandas as pd
11
11
  import plotly.express as px
12
12
  import plotly.graph_objects as go
13
13
 
14
- from webviz_subsurface._providers import EnsembleTableProvider
15
14
  from webviz_subsurface._utils.enum_shim import StrEnum
16
15
  from webviz_subsurface.plugins._co2_migration._utilities.containment_data_provider import (
17
16
  ContainmentDataProvider,
@@ -32,19 +31,6 @@ class _Columns(StrEnum):
32
31
  VOLUME_OUTSIDE = "volume_outside"
33
32
 
34
33
 
35
- class Colors(StrEnum):
36
- # pylint: disable=invalid-name
37
- total = "#222222"
38
- contained = "#00aa00"
39
- outside = "#006ddd"
40
- hazardous = "#dd4300"
41
- dissolved_water = "#208eb7"
42
- dissolved_oil = "#A0522D"
43
- gas = "#C41E3A"
44
- free_gas = "#FF2400"
45
- trapped_gas = "#880808"
46
-
47
-
48
34
  class Marks(StrEnum):
49
35
  dissolved_water = "/"
50
36
  dissolved_oil = "x"
@@ -61,61 +47,76 @@ class Lines(StrEnum):
61
47
  trapped_gas = "dashdot"
62
48
 
63
49
 
64
- _COLOR_ZONES = [
65
- "#e91451",
66
- "#daa218",
67
- "#208eb7",
68
- "#84bc04",
69
- "#b74532",
70
- "#9a89b4",
71
- "#8d30ba",
72
- "#256b33",
73
- "#95704d",
74
- "#1357ca",
75
- "#f75ef0",
76
- "#34b36f",
50
+ _CONTAINMENT_COLORS = {
51
+ "total": ("#222222", "#909090"),
52
+ "contained": ("#00aa00", "#55ff55"),
53
+ "outside": ("#006ddd", "#6eb6ff"),
54
+ "nogo": ("#dd4300", "#ff9a6e"),
55
+ }
56
+
57
+
58
+ _PHASE_COLORS = {
59
+ "total": ("#222222", "#909090"),
60
+ "dissolved_water": ("#208eb7", "#81cde9"),
61
+ "dissolved_oil": ("#A0522D", "#C28163"),
62
+ "gas": ("#C41E3A", "#E42E5A"),
63
+ "free_gas": ("#FF2400", "#FF7430"),
64
+ "trapped_gas": ("#880808", "#C84848"),
65
+ }
66
+
67
+
68
+ _GENERAL_COLORS = [
69
+ ("#e91451", "#f589a8"),
70
+ ("#daa218", "#f2d386"),
71
+ ("#208eb7", "#81cde9"),
72
+ ("#84bc04", "#cdfc63"),
73
+ ("#b74532", "#e19e92"),
74
+ ("#9a89b4", "#ccc4d9"),
75
+ ("#8d30ba", "#c891e3"),
76
+ ("#256b33", "#77d089"),
77
+ ("#95704d", "#cfb7a1"),
78
+ ("#1357ca", "#7ba7f3"),
79
+ ("#f75ef0", "#fbaef7"),
80
+ ("#34b36f", "#93e0b7"),
77
81
  ]
78
82
 
83
+
79
84
  _LIGHTER_COLORS = {
80
85
  "black": "#909090",
81
- "#222222": "#909090",
82
- "#00aa00": "#55ff55",
83
- "#006ddd": "#6eb6ff",
84
- "#dd4300": "#ff9a6e",
85
- "#e91451": "#f589a8",
86
- "#daa218": "#f2d386",
87
- "#208eb7": "#81cde9",
88
- "#84bc04": "#cdfc63",
89
- "#b74532": "#e19e92",
90
- "#9a89b4": "#ccc4d9",
91
- "#8d30ba": "#c891e3",
92
- "#256b33": "#77d089",
93
- "#95704d": "#cfb7a1",
94
- "#1357ca": "#7ba7f3",
95
- "#f75ef0": "#fbaef7",
96
- "#34b36f": "#93e0b7",
97
- "#C41E3A": "#E42E5A",
98
- "#FF2400": "#FF7430",
99
- "#880808": "#C84848",
86
+ **dict(_CONTAINMENT_COLORS.values()),
87
+ **dict(_PHASE_COLORS.values()),
88
+ **dict(_GENERAL_COLORS),
100
89
  }
101
90
 
91
+ _LABEL_TRANSLATIONS = {
92
+ "nogo": "no-go",
93
+ "dissolved_water": "dissolved water",
94
+ "dissolved_oil": "dissolved oil",
95
+ "free_gas": "free gas",
96
+ "trapped_gas": "trapped gas",
97
+ }
102
98
 
103
- def _read_dataframe(
104
- table_provider: EnsembleTableProvider,
105
- realization: int,
106
- scale_factor: float,
107
- ) -> pd.DataFrame:
108
- df = table_provider.get_column_data(table_provider.column_names(), [realization])
109
- if scale_factor == 1.0:
110
- return df
111
- df["amount"] /= scale_factor
112
- return df
99
+
100
+ def _translate_labels(df: Union[pd.DataFrame, Dict], column: str = "type") -> None:
101
+ def translate_label(label: str) -> str:
102
+ if ", " in label:
103
+ parts = label.split(", ")
104
+ translated_parts = [_LABEL_TRANSLATIONS.get(part, part) for part in parts]
105
+ return ", ".join(translated_parts)
106
+ return _LABEL_TRANSLATIONS.get(label, label)
107
+
108
+ if isinstance(df, dict):
109
+ df[column] = [translate_label(label) for label in df[column]]
110
+ else:
111
+ df[column] = df[column].apply(translate_label)
113
112
 
114
113
 
115
114
  def _get_colors(color_options: List[str], split: str) -> List[str]:
116
- if split in {"containment", "phase"}:
117
- return [Colors[option] for option in color_options]
118
- options = list(_COLOR_ZONES)
115
+ if split == "containment":
116
+ return [_CONTAINMENT_COLORS[option][0] for option in color_options]
117
+ if split == "phase":
118
+ return [_PHASE_COLORS[option][0] for option in color_options]
119
+ options = [x[0] for x in _GENERAL_COLORS]
119
120
  if split == "region":
120
121
  options.reverse()
121
122
  num_cols = len(color_options)
@@ -268,8 +269,8 @@ def _prepare_pattern_and_color_options_statistics_plot(
268
269
 
269
270
 
270
271
  def _find_default_legendonly(df: pd.DataFrame, categories: List[str]) -> List[str]:
271
- if "hazardous" in categories:
272
- default_option = "hazardous"
272
+ if "no-go" in categories:
273
+ default_option = "no-go"
273
274
  else:
274
275
  max_value = -999.9
275
276
  default_option = categories[0]
@@ -416,7 +417,7 @@ def _add_sort_key_and_real(
416
417
  sort_value = np.sum(
417
418
  df[
418
419
  (df["phase"] == "total")
419
- & (df["containment"] == "hazardous")
420
+ & (df["containment"] == "nogo")
420
421
  & (df["zone"] == containment_info.zone)
421
422
  & (df["region"] == containment_info.region)
422
423
  & (df["plume_group"] == containment_info.plume_group)
@@ -530,6 +531,9 @@ def generate_co2_volume_figure(
530
531
  color_choice,
531
532
  mark_choice,
532
533
  )
534
+ _translate_labels(df, "type")
535
+ _translate_labels(cat_ord, "type")
536
+
533
537
  fig = px.bar(
534
538
  df,
535
539
  y="real",
@@ -590,6 +594,9 @@ def generate_co2_time_containment_one_realization_figure(
590
594
  color_choice,
591
595
  mark_choice,
592
596
  )
597
+ _translate_labels(df, "type")
598
+ _translate_labels(cat_ord, "type")
599
+
593
600
  fig = px.area(
594
601
  df,
595
602
  x="date",
@@ -776,6 +783,8 @@ def generate_co2_time_containment_figure(
776
783
  options = _prepare_line_type_and_color_options(
777
784
  df, containment_info, color_choice, mark_choice
778
785
  )
786
+ _translate_labels(df, "name")
787
+ _translate_labels(options, "name")
779
788
  if legendonly_traces is None:
780
789
  inactive_cols_at_startup = list(
781
790
  options[~(options["line_type"].isin(["solid", "0px"]))]["name"]
@@ -788,6 +797,14 @@ def generate_co2_time_containment_figure(
788
797
  except ValueError:
789
798
  pass
790
799
 
800
+ options["name"] = options["name"].apply(
801
+ lambda label: ", ".join(
802
+ [_LABEL_TRANSLATIONS.get(part, part) for part in label.split(", ")]
803
+ )
804
+ if ", " in label
805
+ else _LABEL_TRANSLATIONS.get(label, label)
806
+ )
807
+
791
808
  fig = go.Figure()
792
809
  # Generate dummy scatters for legend entries
793
810
  dummy_args = {"x": df["date"], "mode": "lines", "hoverinfo": "none"}
@@ -907,6 +924,8 @@ def generate_co2_statistics_figure(
907
924
  color_choice,
908
925
  mark_choice,
909
926
  )
927
+ _translate_labels(df, "type")
928
+ _translate_labels(cat_ord, "type")
910
929
 
911
930
  df = df.drop(columns=["REAL"]).reset_index(drop=True)
912
931
  fig = px.ecdf(
@@ -973,6 +992,8 @@ def generate_co2_box_plot_figure(
973
992
  color_choice,
974
993
  mark_choice,
975
994
  )
995
+ _translate_labels(df, "type")
996
+ _translate_labels(cat_ord, "type")
976
997
 
977
998
  fig = go.Figure()
978
999
  for count, type_val in enumerate(cat_ord["type"], 0):