Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
HansKallekleiv committed Nov 15, 2024
1 parent bc3f403 commit b46fd0d
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ def get_geojson(
properties = {
"name": row[WellPickTableColumns.WELL],
"attribute": str(row[attribute]),
"line_color": row.get("line_color", [0, 0, 0]),
"text_color": row.get("text_color", [0, 0, 0]),
}

feature = geojson.Feature(
Expand Down
1 change: 1 addition & 0 deletions webviz_subsurface/plugins/_map_viewer_fmu/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class LayerTypes(StrEnum):
WELLTOPSLAYER = "GeoJsonLayer"
DRAWING = "DrawingLayer"
FAULTPOLYGONS = "FaultPolygonsLayer"
FIELD_OUTLINE = "GeoJsonLayer"
GEOJSON = "GeoJsonLayer"


Expand Down
19 changes: 18 additions & 1 deletion webviz_subsurface/plugins/_map_viewer_fmu/_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import base64
import io
import math
from typing import List
from typing import List, Dict

from PIL import Image, ImageDraw
import geojson
import xtgeo


def round_to_significant(val: float, sig: int = 4) -> float:
Expand Down Expand Up @@ -39,3 +41,18 @@ def create_colormap_image_string(
draw.rectangle([(x_0, 0), (x_1, height)], fill=rgb_to_hex(color))

return f"data:image/png;base64,{image_to_base64(img)}"


def xtgeo_polygons_to_geojson(polygons: xtgeo.Polygons) -> Dict:
feature_arr = []
for name, polygon in polygons.dataframe.groupby("POLY_ID"):
coords = [list(zip(polygon.X_UTME, polygon.Y_UTMN))]
feature = geojson.Feature(
geometry=geojson.Polygon(coords),
properties={
"name": f"id:{name}",
"color": [200, 200, 200],
},
)
feature_arr.append(feature)
return geojson.FeatureCollection(features=feature_arr)
49 changes: 37 additions & 12 deletions webviz_subsurface/plugins/_map_viewer_fmu/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

import numpy as np
import xtgeo
import webviz_subsurface_components as wsc
from dash import ALL, MATCH, Input, Output, State, callback, callback_context, no_update
from dash.exceptions import PreventUpdate
Expand All @@ -32,7 +33,7 @@
from ._layer_model import DeckGLMapLayersModel
from ._tmp_well_pick_provider import WellPickProvider
from ._types import LayerTypes, SurfaceMode
from ._utils import round_to_significant
from ._utils import round_to_significant, xtgeo_polygons_to_geojson
from .layout import (
DefaultSettings,
LayoutElements,
Expand All @@ -51,6 +52,8 @@ def plugin_callbacks(
surface_server: Union[SurfaceArrayServer, SurfaceImageServer],
ensemble_fault_polygons_providers: Dict[str, EnsembleFaultPolygonsProvider],
fault_polygons_server: FaultPolygonsServer,
field_outline_polygons: xtgeo.Polygons,
field_outline_color: List[int],
map_surface_names_to_fault_polygons: Dict[str, str],
well_picks_provider: Optional[WellPickProvider],
fault_polygon_attribute: Optional[str],
Expand Down Expand Up @@ -518,9 +521,26 @@ def _update_map(
layer_data={
"data": well_picks_provider.get_geojson(
selected_wells, horizon_name
)
),
"getLineColor": "@@=properties.color",
"getTextColor": "@@=properties.color",
},
)
if (
LayoutLabels.SHOW_FIELD_OUTLINE in options
and field_outline_polygons is not None
):
layer_model.update_layer_by_id(
layer_id=f"{LayoutElements.FIELD_OUTLINE_LAYER}-{idx}",
layer_data={
"data": xtgeo_polygons_to_geojson(field_outline_polygons),
"filled": False,
"depthTest": False,
"lineWidthMinPixels": 2,
"getLineColor": field_outline_color,
},
)

viewports = []
view_annotations = []
for idx, data in enumerate(surface_elements):
Expand Down Expand Up @@ -550,10 +570,13 @@ def _update_map(
"show3D": False,
"isSync": True,
"layerIds": [
f"{LayoutElements.MAP3D_LAYER}-{idx}"
if isinstance(surface_server, SurfaceArrayServer)
else f"{LayoutElements.COLORMAP_LAYER}-{idx}",
(
f"{LayoutElements.MAP3D_LAYER}-{idx}"
if isinstance(surface_server, SurfaceArrayServer)
else f"{LayoutElements.COLORMAP_LAYER}-{idx}"
),
f"{LayoutElements.FAULTPOLYGONS_LAYER}-{idx}",
f"{LayoutElements.FIELD_OUTLINE_LAYER}-{idx}",
f"{LayoutElements.WELLS_LAYER}-{idx}",
],
"name": make_viewport_label(data, tab_name, multi),
Expand Down Expand Up @@ -851,13 +874,15 @@ def _update_color_component_properties(
"colormap": {"value": colormap, "options": colormaps},
"color_range": {
"value": color_range,
"step": calculate_slider_step(
min_value=value_range[0],
max_value=value_range[1],
steps=100,
)
if value_range[0] != value_range[1]
else 0,
"step": (
calculate_slider_step(
min_value=value_range[0],
max_value=value_range[1],
steps=100,
)
if value_range[0] != value_range[1]
else 0
),
"range": value_range,
},
}
Expand Down
46 changes: 30 additions & 16 deletions webviz_subsurface/plugins/_map_viewer_fmu/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,17 @@ class LayoutElements(StrEnum):
RANGE_RESET = "color-range-reset-button"
RESET_BUTTOM_CLICK = "color-range-reset-stored-state"
FAULTPOLYGONS = "fault-polygon-toggle"
FIELD_OUTLINE_TOGGLE = "field-outline-toggle"
WRAPPER = "wrapper-for-selector-component"
COLORWRAPPER = "wrapper-for-color-selector-component"
OPTIONS = "options"

COLORMAP_LAYER = "deckglcolormaplayer"
HILLSHADING_LAYER = "deckglhillshadinglayer"

WELLS_LAYER = "deckglwelllayer"
MAP3D_LAYER = "deckglmap3dlayer"
FAULTPOLYGONS_LAYER = "deckglfaultpolygonslayer"
FIELD_OUTLINE_LAYER = "deckglfieldoutlinelayer"
REALIZATIONS_FILTER = "realization-filter-selector"
OPTIONS_DIALOG = "options-dialog"

Expand All @@ -69,8 +71,8 @@ class LayoutLabels(StrEnum):
LINK = "🔗 Link"
FAULTPOLYGONS = "Fault polygons"
SHOW_FAULTPOLYGONS = "Show fault polygons"
SHOW_FIELD_OUTLINE = "Show field outline"
SHOW_WELLS = "Show wells"
SHOW_HILLSHADING = "Hillshading"
COMMON_SELECTIONS = "Options and global filters"
REAL_FILTER = "Realization filter"
WELL_FILTER = "Well filter"
Expand Down Expand Up @@ -183,7 +185,7 @@ def main_layout(
realizations: List[int],
color_tables: List[Dict],
show_fault_polygons: bool = True,
hillshading_enabled: bool = True,
show_field_outline: bool = False,
render_surfaces_as_images: bool = True,
) -> html.Div:
return html.Div(
Expand Down Expand Up @@ -240,9 +242,9 @@ def main_layout(
DialogLayout(
get_uuid,
show_fault_polygons,
show_field_outline,
well_names,
realizations,
hillshading_enabled,
),
]
)
Expand Down Expand Up @@ -304,18 +306,20 @@ def __init__(
self,
get_uuid: Callable,
show_fault_polygons: bool,
show_field_outline: bool,
well_names: List[str],
realizations: List[int],
hillshading_enabled: bool = True,
) -> None:
checklist_options = [LayoutLabels.SHOW_HILLSHADING]
checklist_values = (
[LayoutLabels.SHOW_HILLSHADING] if hillshading_enabled else []
)
checklist_options = []
checklist_values = []
if show_fault_polygons:
checklist_options.append(LayoutLabels.SHOW_FAULTPOLYGONS)
checklist_values.append(LayoutLabels.SHOW_FAULTPOLYGONS)

if show_field_outline:
checklist_options.append(LayoutLabels.SHOW_FIELD_OUTLINE)
checklist_values.append(LayoutLabels.SHOW_FIELD_OUTLINE)

if well_names:
checklist_options.append(LayoutLabels.SHOW_WELLS)
checklist_values.append(LayoutLabels.SHOW_FAULTPOLYGONS)
Expand Down Expand Up @@ -358,9 +362,11 @@ def __init__(self, tab: Tabs, get_uuid: Callable, selector: str) -> None:
clicked = selector in DefaultSettings.LINKED_SELECTORS.get(tab, [])
super().__init__(
id={
"id": get_uuid(LayoutElements.LINK)
if selector not in ["color_range", "colormap"]
else get_uuid(LayoutElements.COLORLINK),
"id": (
get_uuid(LayoutElements.LINK)
if selector not in ["color_range", "colormap"]
else get_uuid(LayoutElements.COLORLINK)
),
"tab": tab,
"selector": selector,
},
Expand Down Expand Up @@ -570,9 +576,11 @@ def __init__(
) -> None:
super().__init__(
style={
"display": "none"
if tab == Tabs.STATS and selector == MapSelector.MODE
else "block"
"display": (
"none"
if tab == Tabs.STATS and selector == MapSelector.MODE
else "block"
)
},
children=wcc.Selectors(
label=label,
Expand Down Expand Up @@ -805,7 +813,13 @@ def update_map_layers(
"parameters": {"depthTest": False},
}
)

layers.append(
{
"@@type": LayerTypes.FIELD_OUTLINE,
"id": f"{LayoutElements.FIELD_OUTLINE_LAYER}-{idx}",
"data": {"type": "FeatureCollection", "features": []},
}
)
if include_well_layer:
layers.append(
{
Expand Down
32 changes: 28 additions & 4 deletions webviz_subsurface/plugins/_map_viewer_fmu/map_viewer_fmu.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Callable, Dict, List, Optional, Tuple, Union

from dash import Dash, html
import xtgeo
from webviz_config import WebvizPluginABC, WebvizSettings

from webviz_subsurface._providers import (
Expand Down Expand Up @@ -39,6 +40,8 @@ class MapViewerFMU(WebvizPluginABC):
Default value is 'share/results/maps'.
* **`well_pick_file`:** A csv file with well picks. See data input.
* **`fault_polygon_attribute`:** Which set of fault polygons to use.
* **`field_outline_polygons_file_path`:** Full filepath to a field outline polygons file.
* **`field_outline_color:** Color of the field outline polygons (rgb).
* **`map_surface_names_to_well_pick_names`:** Allows mapping of file surface names
to the relevant well pick name
* **`map_surface_names_to_fault_polygons`:** Allows mapping of file surface names
Expand Down Expand Up @@ -69,6 +72,8 @@ class MapViewerFMU(WebvizPluginABC):
01_drogon_ahm/realization-0/iter-0/share/results/polygons/\
toptherys--gl_faultlines_extract_postprocess.pol) for an example.
Field outline polygons have the same format as fault polygons.
Well picks are provided as a csv file with columns `X_UTME,Y_UTMN,Z_TVDSS,MD,WELL,HORIZON`.
See [wellpicks.csv](https://github.com/equinor/webviz-subsurface-testdata/tree/master/\
observed_data/drogon_well_picks/wellpicks.csv) for an example.<br>
Expand All @@ -91,6 +96,8 @@ def __init__(
attributes: list = None,
well_pick_file: Path = None,
fault_polygon_attribute: Optional[str] = None,
field_outline_polygons_file_path: Path = None,
field_outline_color: List[int] = [200, 200, 200],
map_surface_names_to_fault_polygons: Dict[str, str] = None,
map_surface_names_to_well_pick_names: Dict[str, str] = None,
rel_surface_folder: str = "share/results/maps",
Expand Down Expand Up @@ -155,7 +162,15 @@ def __init__(
self._fault_polygons_server = FaultPolygonsServer.instance(app)
for fault_polygons_provider in self._ensemble_fault_polygons_providers.values():
self._fault_polygons_server.add_provider(fault_polygons_provider)

self.field_outline_polygons = None
if field_outline_polygons_file_path is not None:
try:
self.field_outline_polygons = xtgeo.Polygons(
read_csv(field_outline_polygons_file_path)
)
except:
print("Error reading field outline polygons file")
self.field_outline_color = field_outline_color
self.map_surface_names_to_fault_polygons = (
map_surface_names_to_fault_polygons
if map_surface_names_to_fault_polygons is not None
Expand All @@ -175,10 +190,13 @@ def layout(self) -> html.Div:
reals.extend([x for x in provider.realizations() if x not in reals])
return main_layout(
get_uuid=self.uuid,
well_names=self.well_pick_provider.well_names()
if self.well_pick_provider is not None
else [],
well_names=(
self.well_pick_provider.well_names()
if self.well_pick_provider is not None
else []
),
realizations=reals,
show_field_outline=self.field_outline_polygons is not None,
color_tables=self.color_tables,
render_surfaces_as_images=self.render_surfaces_as_images,
)
Expand All @@ -191,6 +209,8 @@ def set_callbacks(self) -> None:
ensemble_fault_polygons_providers=self._ensemble_fault_polygons_providers,
fault_polygon_attribute=self.fault_polygon_attribute,
fault_polygons_server=self._fault_polygons_server,
field_outline_polygons=self.field_outline_polygons,
field_outline_color=self.field_outline_color,
map_surface_names_to_fault_polygons=self.map_surface_names_to_fault_polygons,
well_picks_provider=self.well_pick_provider,
color_tables=self.color_tables,
Expand All @@ -202,4 +222,8 @@ def add_webvizstore(self) -> List[Tuple[Callable, list]]:
store_functions = []
if self.well_pick_file is not None:
store_functions.append((read_csv, [{"csv_file": self.well_pick_file}]))
if self.field_outline_polygons_file_path is not None:
store_functions.append(
(read_csv, [{"csv_file": self.field_outline_polygons_file_path}])
)
return store_functions

0 comments on commit b46fd0d

Please sign in to comment.