def make_surfaces( surface_table: pd.DataFrame, prop: str, zone: str, ensemble: str, delta_ensemble: str, get_uuid: Callable, statistic: str = "mean", ) -> html.Div: try: ens_surface = surface_from_zone_prop( surface_table, zone=zone, prop=prop, ensemble=ensemble, stype=statistic, ) delta_ens_surface = surface_from_zone_prop( surface_table, zone=zone, prop=prop, ensemble=delta_ensemble, stype=statistic, ) except ValueError: return html.Div("No surfaces found") # Truncating surface values to highest low and lowest high for each map min_val = max([ens_surface.values.min(), delta_ens_surface.values.min()]) max_val = min([ens_surface.values.max(), delta_ens_surface.values.max()]) ens_surface.values[ens_surface.values < min_val] = min_val ens_surface.values[ens_surface.values > max_val] = max_val delta_ens_surface.values[delta_ens_surface.values < min_val] = min_val delta_ens_surface.values[delta_ens_surface.values > max_val] = max_val diff_surface = ens_surface.copy() diff_surface.values = ens_surface.values - delta_ens_surface.values return surface_views( ens_layer=SurfaceLeafletModel(ens_surface, name="ens_surface").layer, delta_ens_layer=SurfaceLeafletModel( delta_ens_surface, name="delta_ens_surface" ).layer, diff_layer=SurfaceLeafletModel(diff_surface, name="diff_surface").layer, ensemble=ensemble, delta_ensemble=delta_ensemble, get_uuid=get_uuid, prop=prop, zone=zone, )
def _render_surface( fencespec: List[List[float]], surfacename: str, surfacetype: str, ensemble: str, ) -> List[dict]: """Update map""" intersect_layer = { "name": "Well", "id": "Well", "action": "replace", "checked": True, "base_layer": False, "data": [{ "type": "polyline", "color": "red", "positions": fencespec, }], } surface = get_surface_statistics( self.realizations.to_dict(orient="records"), ensemble, self.surfacefiles[self.surfacenames.index(surfacename)], self.surfacefolder, )[surfacetype] surface_layer = SurfaceLeafletModel(surface, name=surfacename).layer return [surface_layer, intersect_layer]
def _render_surface( surfacepath, surface_type, gridparameter, color_values, colorscale, hillshade, ): surface = xtgeo.RegularSurface(get_path(surfacepath)) min_val = None max_val = None color = None if surface_type == "attribute": min_val = color_values[0] if color_values else None max_val = color_values[1] if color_values else None color = colorscale if colorscale else color grid = load_grid(get_path(self.gridfile)) gridparameter = load_grid_parameter(grid, get_path(gridparameter)) surface.slice_grid3d(grid, gridparameter) return [ SurfaceLeafletModel( surface, name="surface", clip_min=min_val, clip_max=max_val, apply_shading=hillshade.get("value", False), ).layer ]
def create_or_return_base_layer( update_controls: Dict, surface: xtgeo.RegularSurface, current_map: List[Dict], shade_map: Dict[str, bool], color_range_settings: Dict, map_id: str, ) -> List[Dict]: surface_layers = [] if update_controls[map_id]["use_base_layer"]: for layer in current_map: if layer["baseLayer"]: layer["data"][0]["shader"]["applyHillshading"] = shade_map.get( "value") surface_layers = [layer] else: surface_layers = [ SurfaceLeafletModel( surface, clip_min=color_range_settings[map_id]["color_range"][0], clip_max=color_range_settings[map_id]["color_range"][1], name=map_id, apply_shading=shade_map.get("value", False), ).layer ] return surface_layers
def _render_surface(wellfile: str) -> List[Dict[str, Any]]: """Update map""" wellname = Path(wellfile).stem wellfile = get_path(wellfile) surface = load_surface(get_path(self.surfacefiles[0])) well = load_well(wellfile) s_layer = SurfaceLeafletModel(surface, name=self.surfacenames[0]).layer well_layer = make_well_layer(well, wellname) return [s_layer, well_layer]
def make_surfaces( parent: "PropertyStatistics", prop: str, zone: str, ensemble: str, delta_ensemble: str, statistic: str = "mean", ) -> html.Div: sprop = parent.surface_renaming.get(prop, prop) szone = parent.surface_renaming.get(zone, zone) ens_surface = surface_from_zone_prop(parent, zone=szone, prop=sprop, ensemble=ensemble, stype=statistic) delta_ens_surface = surface_from_zone_prop(parent, zone=szone, prop=sprop, ensemble=delta_ensemble, stype=statistic) # Truncating surface values to highest low and lowest high for each map min_val = max([ens_surface.values.min(), delta_ens_surface.values.min()]) max_val = min([ens_surface.values.max(), delta_ens_surface.values.max()]) ens_surface.values[ens_surface.values < min_val] = min_val ens_surface.values[ens_surface.values > max_val] = max_val delta_ens_surface.values[delta_ens_surface.values < min_val] = min_val delta_ens_surface.values[delta_ens_surface.values > max_val] = max_val diff_surface = ens_surface.copy() diff_surface.values = ens_surface.values - delta_ens_surface.values return surface_views( ens_layer=SurfaceLeafletModel(ens_surface, name="ens_surface").layer, delta_ens_layer=SurfaceLeafletModel(delta_ens_surface, name="delta_ens_surface").layer, diff_layer=SurfaceLeafletModel(diff_surface, name="diff_surface").layer, ensemble=ensemble, delta_ensemble=delta_ensemble, parent=parent, prop=prop, zone=zone, )
def _update_surface(clickdata: Union[None, dict], ensemble: str, stype: str) -> Tuple[list, str]: if clickdata is not None: label = clickdata["points"][0]["y"] prop = label.split(" | ")[0] zone = label.split(" | ")[1] sprop = parent.surface_renaming.get(prop, prop) szone = parent.surface_renaming.get(zone, zone) surface = surface_from_zone_prop(parent, zone=szone, prop=sprop, ensemble=ensemble, stype=stype) surface_layer = SurfaceLeafletModel(surface, name="surface").layer return [surface_layer], f"{stype.capitalize()} for {prop}, {zone}" raise PreventUpdate
def _render_surface(surfacepath, surface_type, cubepath, color_values, hillshade): surface = xtgeo.surface_from_file(get_path(surfacepath)) min_val = None max_val = None if surface_type == "attribute": min_val = color_values[0] if color_values else None max_val = color_values[1] if color_values else None cube = load_cube_data(get_path(cubepath)) surface.slice_cube(cube) return [ SurfaceLeafletModel( surface, name="surface", clip_min=min_val, clip_max=max_val, apply_shading=hillshade.get("value", False), ).layer ]
def _render_map(surface_name, switch, wellfile): """Renders map view for one surface with de, dt, dte, dr, dre and depth Wells marked with circles, trajectory and hillshading toggle """ surfaces = [ self.surface_attributes[surface_name]["surface"], self.surface_attributes[surface_name]["surface_de"], self.surface_attributes[surface_name]["surface_dr"], self.surface_attributes[surface_name]["surface_dt"], self.surface_attributes[surface_name]["surface_dte"], ] well_layers = get_well_layers( self.wells, self.planned_wells, surface_name, surfaces[0], wellfile, ) layers = [] for i, surface in enumerate(surfaces): layers.append( SurfaceLeafletModel( surface, name=self.surface_types[i], apply_shading=switch["value"], updatemode="add", ).layer ) layers.extend(well_layers) # Deletes old layers when switching surface in dropdown old_layers = self.layers_state self.layers_state = layers.copy() if old_layers is not None and len(old_layers) > 0: for layer in old_layers: layer["action"] = "delete" old_layers.extend(layers) layers = old_layers return layers
def _update_surface(clickdata: Union[None, dict], ensemble: str, stype: str) -> Tuple[list, str]: if clickdata is not None: label = clickdata["points"][0]["y"] prop = label.split(" | ")[0] zone = label.split(" | ")[1] try: surface = surface_from_zone_prop( surface_table, zone=zone, prop=prop, ensemble=ensemble, stype=stype, ) except ValueError: # Surface does not exist return ( no_update, f"No surface found for {stype.capitalize()} for {prop}, {zone}", ) surface_layer = SurfaceLeafletModel(surface, name="surface").layer return [surface_layer], f"{stype.capitalize()} for {prop}, {zone}" raise PreventUpdate
def _set_base_layer( stored_selector_data: str, ensemble: str, real: str, stored_selector2_data: str, ensemble2: str, real2: str, calculation: str, stored_attribute_settings: str, diff_min: Union[int, float, None], diff_max: Union[int, float, None], hillshade: dict, hillshade2: dict, hillshade3: dict, ) -> Tuple[List[dict], List[dict], List[dict], str]: ctx = callback_context.triggered if not ctx or not stored_selector_data or not stored_selector2_data: raise PreventUpdate # TODO(Sigurd) # These two are presumably of type dict, but the type depends on the actual python # objects that get serialized inside SurfaceSelector. # Should deserialization and validation be delegated to SurfaceSelector? # Note that according to the doc, it seems that dcc.Store actualy does the # serialization/deserialization for us! # Should be refactored data: dict = json.loads(stored_selector_data) data2: dict = json.loads(stored_selector2_data) if not isinstance(data, dict) or not isinstance(data2, dict): raise TypeError("Selector data payload must be of type dict") attribute_settings: dict = json.loads(stored_attribute_settings) if not isinstance(attribute_settings, dict): raise TypeError("Expected stored attribute_settings to be of type dict") if real in ["Mean", "StdDev", "Min", "Max"]: surface = self._surface_ensemble_set_model[ ensemble ].calculate_statistical_surface(**data, calculation=real) else: surface = self._surface_ensemble_set_model[ ensemble ].get_realization_surface(**data, realization=int(real)) if real2 in ["Mean", "StdDev", "Min", "Max"]: surface2 = self._surface_ensemble_set_model[ ensemble2 ].calculate_statistical_surface(**data2, calculation=real2) else: surface2 = self._surface_ensemble_set_model[ ensemble2 ].get_realization_surface(**data2, realization=int(real2)) surface_layers: List[dict] = [ SurfaceLeafletModel( surface, name="surface", colors=attribute_settings.get(data["attribute"], {}).get("color"), apply_shading=hillshade.get("value", False), clip_min=attribute_settings.get(data["attribute"], {}).get( "min", None ), clip_max=attribute_settings.get(data["attribute"], {}).get( "max", None ), unit=attribute_settings.get(data["attribute"], {}).get("unit", " "), ).layer ] surface_layers2: List[dict] = [ SurfaceLeafletModel( surface2, name="surface2", colors=attribute_settings.get(data2["attribute"], {}).get("color"), apply_shading=hillshade2.get("value", False), clip_min=attribute_settings.get(data2["attribute"], {}).get( "min", None ), clip_max=attribute_settings.get(data2["attribute"], {}).get( "max", None ), unit=attribute_settings.get(data2["attribute"], {}).get( "unit", " " ), ).layer ] try: surface3 = calculate_surface_difference(surface, surface2, calculation) if diff_min is not None: surface3.values[surface3.values <= diff_min] = diff_min if diff_max is not None: surface3.values[surface3.values >= diff_max] = diff_max diff_layers: List[dict] = [] diff_layers.append( SurfaceLeafletModel( surface3, name="surface3", colors=attribute_settings.get(data["attribute"], {}).get( "color" ), apply_shading=hillshade3.get("value", False), ).layer ) error_label = "" except ValueError: diff_layers = [] error_label = ( "Cannot calculate because the surfaces have different geometries" ) if self.well_layer: surface_layers.append(self.well_layer) surface_layers2.append(self.well_layer) diff_layers.append(self.well_layer) return (surface_layers, surface_layers2, diff_layers, error_label)
def _update_maps( surfattr_map: str, surfattr_map2: str, surfname_map: str, surfname_map2: str, ensemble_map: str, ensemble_map2: str, calc_map: str, calc_map2: str, shade_map: Dict[str, bool], shade_map2: Dict[str, bool], shade_map3: Dict[str, bool], options: List[str], options2: List[str], color_range_settings: Dict, compute_diff: List[str], real_list: List[str], wellname: Optional[str], polyline: Optional[List], xline: Optional[List], yline: Optional[List], source: str, current_map: List, current_map2: List, current_map3: List, ) -> Tuple[str, List, str, List, str, List]: """Generate Leaflet layers for the three map views""" realizations = [int(real) for real in real_list] ctx = dash.callback_context.triggered[0] if "compute_diff" in ctx["prop_id"]: if not compute_diff: return ( dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, [], ) # Check if map is already generated and should just be updated with polylines update_poly_only = bool(current_map and ("stored_polyline" in ctx["prop_id"] or "stored_yline" in ctx["prop_id"] or "stored_xline" in ctx["prop_id"])) if polyline is not None: poly_layer = create_leaflet_polyline_layer(polyline, name="Polyline", poly_id="random_line") for map_layers in [current_map, current_map2, current_map3]: map_layers = replace_or_add_map_layer(map_layers, "Polyline", poly_layer) if xline is not None and source == "xline": xline_layer = create_leaflet_polyline_layer(xline, name="Xline", poly_id="x_line") for map_layers in [current_map, current_map2, current_map3]: map_layers = replace_or_add_map_layer(map_layers, "Xline", xline_layer) if yline is not None and source == "yline": yline_layer = create_leaflet_polyline_layer(yline, name="Yline", poly_id="y_line") for map_layers in [current_map, current_map2, current_map3]: map_layers = replace_or_add_map_layer(map_layers, "Yline", yline_layer) # If callback is triggered by polyline drawing, only update polyline if update_poly_only: return ( f"Surface A: {surfattr_map} - {surfname_map} - {ensemble_map} - {calc_map}", current_map, f"Surface B: {surfattr_map2} - {surfname_map2} - {ensemble_map2} - {calc_map2}", dash.no_update, "Surface A-B", dash.no_update, ) if wellname is not None: well = well_set_model.get_well(wellname) well_layer = make_well_layer(well, name=well.name) # If callback is triggered by well change, only update well layer if "well" in ctx["prop_id"] or ("source" in ctx["prop_id"] and source == "well"): for map_layers in [current_map, current_map2, current_map3]: map_layers = replace_or_add_map_layer( map_layers, "Well", well_layer) return ( f"Surface A: {surfattr_map} - {surfname_map} - " f"{ensemble_map} - {calc_map}", current_map, f"Surface B: {surfattr_map2} - {surfname_map2} - " f"{ensemble_map2} - {calc_map2}", current_map2, "Surface A-B", dash.no_update, ) # Calculate maps if calc_map in ["Mean", "StdDev", "Max", "Min", "P90", "P10"]: surface = surface_set_models[ ensemble_map].calculate_statistical_surface( name=surfname_map, attribute=surfattr_map, calculation=calc_map, realizations=realizations, ) else: surface = surface_set_models[ensemble_map].get_realization_surface( name=surfname_map, attribute=surfattr_map, realization=int(calc_map)) if calc_map2 in ["Mean", "StdDev", "Max", "Min", "P90", "P10"]: surface2 = surface_set_models[ ensemble_map2].calculate_statistical_surface( name=surfname_map2, attribute=surfattr_map2, calculation=calc_map2, realizations=realizations, ) else: surface2 = surface_set_models[ ensemble_map2].get_realization_surface( name=surfname_map2, attribute=surfattr_map2, realization=int(calc_map2)) # Generate Leaflet layers update_controls = check_if_update_needed( ctx=ctx, current_maps=[current_map, current_map2], compute_diff=compute_diff, color_range_settings=color_range_settings, ) surface_layers = create_or_return_base_layer( update_controls, surface, current_map, shade_map, color_range_settings, map_id="map1", ) surface_layers2 = create_or_return_base_layer( update_controls, surface2, current_map2, shade_map2, color_range_settings, map_id="map2", ) try: surface3 = surface.copy() surface3.values = surface3.values - surface2.values diff_layers = ([ SurfaceLeafletModel( surface3, name="surface3", apply_shading=shade_map3.get("value", False), ).layer ] if update_controls["diff_map"]["update"] else []) except ValueError: diff_layers = [] if wellname is not None: surface_layers.append(well_layer) surface_layers2.append(well_layer) if polyline is not None: surface_layers.append(poly_layer) if xline is not None and source == "xline": surface_layers.append(xline_layer) if yline is not None and source == "yline": surface_layers.append(yline_layer) if well_set_model is not None: if options is not None or options2 is not None: if "intersect_well" in options or "intersect_well" in options2: ### This is potentially a heavy task as it loads all wells into memory wells: List[xtgeo.Well] = list( well_set_model.wells.values()) if "intersect_well" in options and update_controls["map1"][ "update"]: surface_layers.append( create_leaflet_well_marker_layer(wells, surface)) if "intersect_well" in options2 and update_controls["map2"][ "update"]: surface_layers2.append( create_leaflet_well_marker_layer(wells, surface2)) return ( f"Surface A: {surfattr_map} - {surfname_map} - {ensemble_map} - {calc_map}", surface_layers if update_controls["map1"]["update"] else dash.no_update, f"Surface B: {surfattr_map2} - {surfname_map2} - {ensemble_map2} - {calc_map2}", surface_layers2 if update_controls["map2"]["update"] else dash.no_update, "Surface A-B", diff_layers if update_controls["diff_map"]["update"] else dash.no_update, )