Example #1
0
 def __init__(self):
     super().__init__()
     self._screenshot_filename = f"{self.plugin_name()}.png"
     ASSETS_DIR = Path(pkg_resources.resource_filename("everviz", "assets"))
     WEBVIZ_ASSETS.add(ASSETS_DIR / "axis_customization.css")
Example #2
0
import pkg_resources
import json
from pathlib import Path
from webviz_config.webviz_assets import WEBVIZ_ASSETS

ASSETS_DIR = Path(pkg_resources.resource_filename("ertviz", "assets"))
WEBVIZ_ASSETS.add(ASSETS_DIR / "ert-style.css")
with open(ASSETS_DIR / "ert-style.json") as f:
    ERTSTYLE = json.load(f)

WEBVIZ_CONFIG = (Path(pkg_resources.resource_filename("ertviz", "assets")) /
                 "webviz-config.yml")
Example #3
0
    def __init__(
        self,
        app: Dash,
        webviz_settings: WebvizSettings,
        basedir: Path,
        planned_wells_dir: Path = None,
    ):

        super().__init__()
        self.plotly_theme = webviz_settings.theme.plotly_theme
        self.uid = uuid4()
        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "modal.css")
        self.set_callbacks(app)

        self.basedir = basedir
        self.planned_wells_dir = planned_wells_dir
        self.modelfile_path = basedir / "model_file.xml"
        self.modelfile = get_path(self.modelfile_path)
        self.surfaces = load_surfaces(basedir, self.modelfile_path)
        self.planned_wellfiles = (json.load(
            find_files(planned_wells_dir, "*.txt"))
                                  if planned_wells_dir else None)
        self.wellfiles = json.load(
            find_files(basedir / "input" / "welldata", "*.txt"))
        self.wellfiles = [str(get_path(Path(w))) for w in self.wellfiles]
        self.allfiles = json.load(find_files(basedir))
        self.allfiles.append(self.modelfile_path)
        self.allfiles += self.planned_wellfiles
        self.planned_wellfiles = [
            str(get_path(Path(w))) for w in self.planned_wellfiles
        ]
        self.surface_attributes = {}
        for i, surface in enumerate(self.surfaces):
            self.surface_attributes[surface["name"]] = {
                "color": get_color(i),
                "order": i,
                "name": surface["name"],
                "topofzone": surface["topofzone"],
                "surface": surface["d_"],
                "surface_de": surface["de_"],
                "surface_dt": surface["dt_"],
                "surface_dr": surface["dr_"],
                "surface_dte": surface["dte_"],
            }

        self.surfacenames = [surface["name"] for surface in self.surfaces]
        # Log files
        zonation_status_file = get_zonation_status(basedir)
        well_points_file = get_well_points(basedir)
        zonelog_name = get_zonelog_name(self.modelfile)
        self.xsec = HuvXsection(
            self.surface_attributes,
            zonation_status_file,
            well_points_file,
            zonelog_name,
        )
        target_points_file = get_target_points(basedir)
        self.df_well_target_points = FilterTable(target_points_file,
                                                 well_points_file)

        # Wellfiles and planned wells
        self.planned_wells = {}
        if planned_wells_dir is not None:
            self.planned_wells = {
                wf: xtgeo.well_from_file(wfile=wf)
                for wf in self.planned_wellfiles
            }

        self.wells = {
            wf: xtgeo.well_from_file(wfile=wf)
            for wf in self.wellfiles
        }

        # Store current layers
        self.state = {"switch": False}
        self.layers_state = []
Example #4
0
    def __init__(
        self,
        app: dash.Dash,
        webviz_settings: WebvizSettings,
        ensembles: Optional[list] = None,
        rel_file_pattern: str = "share/results/unsmry/*.arrow",
        perform_presampling: bool = False,
        obsfile: Path = None,
        options: dict = None,
        sampling: str = Frequency.MONTHLY.value,
        predefined_expressions: str = None,
        user_defined_vector_definitions: str = None,
        line_shape_fallback: str = "linear",
    ) -> None:
        super().__init__()

        # NOTE: Temporary css, pending on new wcc modal component.
        # See: https://github.com/equinor/webviz-core-components/issues/163
        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "modal.css")

        self._webviz_settings = webviz_settings
        self._obsfile = obsfile

        # Retrieve user defined vector descriptions from configuration and validate
        self._user_defined_vector_descriptions_path = (
            None if user_defined_vector_definitions is None else
            webviz_settings.shared_settings["user_defined_vector_definitions"]
            [user_defined_vector_definitions])
        self._user_defined_vector_definitions: Dict[
            str, wsc.
            VectorDefinition] = create_user_defined_vector_descriptions_from_config(
                get_path(self._user_defined_vector_descriptions_path) if self.
                _user_defined_vector_descriptions_path else None)
        self._custom_vector_definitions = copy.deepcopy(
            self._user_defined_vector_definitions)

        self._line_shape_fallback = set_simulation_line_shape_fallback(
            line_shape_fallback)

        # Must define valid freqency!
        if Frequency.from_string_value(sampling) is None:
            raise ValueError(
                'Sampling frequency conversion is "None", i.e. Raw sampling, and '
                "is not supported by plugin yet!")
        self._sampling = Frequency(sampling)
        self._presampled_frequency = None

        # TODO: Update functionality when allowing raw data and csv file input
        # NOTE: If csv is implemented-> handle/disable statistics, PER_INTVL_, PER_DAY_, delta
        # ensemble, etc.
        if ensembles is not None:
            ensemble_paths: Dict[str, Path] = {
                ensemble_name:
                webviz_settings.shared_settings["scratch_ensembles"]
                [ensemble_name]
                for ensemble_name in ensembles
            }
            if perform_presampling:
                self._presampled_frequency = self._sampling
                self._input_provider_set = create_presampled_provider_set_from_paths(
                    ensemble_paths, rel_file_pattern,
                    self._presampled_frequency)
            else:
                self._input_provider_set = create_lazy_provider_set_from_paths(
                    ensemble_paths, rel_file_pattern)
        else:
            raise ValueError('Incorrect argument, must provide "ensembles"')

        if not self._input_provider_set:
            raise ValueError(
                "Initial provider set is undefined, and ensemble summary providers"
                " are not instanciated for plugin")

        self._theme = webviz_settings.theme

        self._observations = {}
        if self._obsfile:
            self._observations = check_and_format_observations(
                get_path(self._obsfile))

        # NOTE: Initially keep set of all vector names - can make dynamic if wanted?
        vector_names = self._input_provider_set.all_vector_names()
        non_historical_vector_names = [
            vector for vector in vector_names
            if historical_vector(vector, None, False) not in vector_names
        ]

        # NOTE: Initially: With set of vector names, the vector selector data is static
        # Can be made dynamic based on selected ensembles - i.e. vectors present among
        # selected providers?
        self._vector_selector_base_data: list = []
        self._vector_calculator_data: list = []
        for vector in non_historical_vector_names:
            add_vector_to_vector_selector_data(
                self._vector_selector_base_data,
                vector,
            )

            # Only vectors from providers are provided to vector calculator
            add_vector_to_vector_selector_data(
                self._vector_calculator_data,
                vector,
            )

            metadata = (self._input_provider_set.vector_metadata(vector)
                        if self._input_provider_set else None)
            if metadata and metadata.is_total:
                # Get the likely name for equivalent rate vector and make dropdown options.
                # Requires that the time_index was either defined or possible to infer.
                per_day_vec = create_per_day_vector_name(vector)
                per_intvl_vec = create_per_interval_vector_name(vector)

                add_vector_to_vector_selector_data(
                    self._vector_selector_base_data,
                    per_day_vec,
                )
                add_vector_to_vector_selector_data(
                    self._vector_selector_base_data,
                    per_intvl_vec,
                )

                # Add vector base to custom vector definition if not existing
                vector_base = vector.split(":")[0]
                _definition = wsc.VectorDefinitions.get(vector_base, None)
                _type = _definition["type"] if _definition else "others"

                per_day_vec_base = per_day_vec.split(":")[0]
                per_intvl_vec_base = per_intvl_vec.split(":")[0]
                if per_day_vec_base not in self._custom_vector_definitions:
                    self._custom_vector_definitions[
                        per_day_vec_base] = wsc.VectorDefinition(
                            type=_type,
                            description=simulation_vector_description(
                                per_day_vec_base,
                                self._user_defined_vector_definitions),
                        )
                if per_intvl_vec_base not in self._custom_vector_definitions:
                    self._custom_vector_definitions[
                        per_intvl_vec_base] = wsc.VectorDefinition(
                            type=_type,
                            description=simulation_vector_description(
                                per_intvl_vec_base,
                                self._user_defined_vector_definitions),
                        )

        # Retreive predefined expressions from configuration and validate
        self._predefined_expressions_path = (
            None if predefined_expressions is None else webviz_settings.
            shared_settings["predefined_expressions"][predefined_expressions])
        self._predefined_expressions = expressions_from_config(
            get_path(self._predefined_expressions_path) if self.
            _predefined_expressions_path else None)
        for expression in self._predefined_expressions:
            valid, message = validate_predefined_expression(
                expression, self._vector_selector_base_data)
            if not valid:
                warnings.warn(message)
            expression["isValid"] = valid

        # Add expressions to custom vector definitions
        self._custom_vector_definitions_base = copy.deepcopy(
            self._custom_vector_definitions)
        _custom_vector_definitions_from_expressions = (
            get_vector_definitions_from_expressions(
                self._predefined_expressions))
        for key, value in _custom_vector_definitions_from_expressions.items():
            if key not in self._custom_vector_definitions:
                self._custom_vector_definitions[key] = value

        # Create initial vector selector data with predefined expressions
        self._initial_vector_selector_data = copy.deepcopy(
            self._vector_selector_base_data)
        add_expressions_to_vector_selector_data(
            self._initial_vector_selector_data, self._predefined_expressions)

        plot_options = options if options else {}
        self._initial_visualization_selection = VisualizationOptions(
            plot_options.get("visualization", "statistics"))

        # Initial selected vectors - NB: {vector1, vector2, vector3} is deprecated!
        initial_vectors: List[str] = plot_options.get("vectors", [])

        # TODO: Remove when depretaced code is not utilized anymore
        if "vectors" in plot_options and any(
                elm in plot_options
                for elm in ["vector1", "vector2", "vector3"]):
            warnings.warn(
                'Providing new user input option "vectors" and deprecated user input options '
                '"vector1", "vector2" and "vector3" simultaneously. Initially selected vectors '
                'for plugin are set equal to new user input option "vectors".')
        if not initial_vectors:
            initial_vectors = [
                plot_options[elm] for elm in ["vector1", "vector2", "vector3"]
                if elm in plot_options
            ][:3]

        # Check if initially selected vectors exist in data, raise ValueError if not
        missing_vectors = [
            elm for elm in initial_vectors
            if not is_vector_name_in_vector_selector_data(
                elm, self._initial_vector_selector_data)
        ]
        if missing_vectors:
            raise ValueError(
                f"Cannot find: {', '.join(missing_vectors)} to plot initially in "
                "SimulationTimeSeries. Check that the vector(s) exist in your data."
            )

        if len(initial_vectors) > 3:
            warnings.warn(
                'User input option "vectors" contains more than 3 vectors. Only the first 3 listed '
                "vectors are kept for initially selected vectors - the remaining are neglected."
            )
        self._initial_vectors = initial_vectors[:3]

        # Set callbacks
        self.set_callbacks(app)
Example #5
0
    def __init__(
        self,
        app,
        webviz_settings: WebvizSettings,
        ensembles: list,
        relpermfile: str = None,
        scalfile: Path = None,
        sheet_name: Optional[Union[str, int, list]] = None,
    ):

        super().__init__()

        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "block_options.css")

        self.ens_paths = {
            ens: webviz_settings.shared_settings["scratch_ensembles"][ens]
            for ens in ensembles
        }
        self.plotly_theme = webviz_settings.theme.plotly_theme
        self.relpermfile = relpermfile
        if self.relpermfile is not None:
            self.satfunc = load_csv(ensemble_paths=self.ens_paths,
                                    csv_file=relpermfile)
            self.satfunc = self.satfunc.rename(
                str.upper, axis="columns").rename(columns={"TYPE": "KEYWORD"})
            if "KEYWORD" not in self.satfunc.columns:
                raise ValueError(
                    "There has to be a KEYWORD or TYPE column with corresponding Eclipse keyword: "
                    "e.g SWOF, SGOF and etc.")
            # pylint: disable=literal-comparison
            valid_columns = (["ENSEMBLE", "REAL", "KEYWORD", "SATNUM"] +
                             RelativePermeability.SATURATIONS + [
                                 key
                                 for key in RelativePermeability.SCAL_COLORMAP
                                 if key != "Missing"
                             ])
            self.satfunc = self.satfunc[[
                col for col in self.satfunc.columns if col in valid_columns
            ]]
        else:
            self.satfunc = load_satfunc(self.ens_paths)
        if any(keyword in RelativePermeability.RELPERM_FAMILIES[1]
               for keyword in self.satfunc["KEYWORD"].unique()):
            self.family = 1
            if any(keyword in RelativePermeability.RELPERM_FAMILIES[2]
                   for keyword in self.satfunc["KEYWORD"].unique()):
                warnings.warn((
                    "Mix of keyword family 1 and 2, currently only support one family at the "
                    "time. Dropping all data of family 2 ('SWFN', 'SGFN', 'SGWFN', 'SOF2', "
                    "'SOF3', 'SOF32D') and continues with family 1 ('SWOF', 'SGOF', 'SLGOF')."
                ), )
                self.satfunc = self.satfunc[self.satfunc["KEYWORD"].isin(
                    RelativePermeability.RELPERM_FAMILIES["fam1"])]
            if "SGOF" in self.satfunc["KEYWORD"].unique():
                if "SLGOF" in self.satfunc["KEYWORD"].unique():
                    warnings.warn((
                        "Mix of 'SGOF' and 'SLGOF' in ensembles, resulting in non-unique "
                        "horizontal axis ('SG' and 'SL') for 'KRG', 'KROG' and 'PCOG'. "
                        "Dropping all data with 'SLGOF'."), )
                    self.satfunc = self.satfunc[
                        self.satfunc["KEYWORD"] != "SLGOF"]
                self.sat_axes_maps = {
                    "SW": ["KRW", "KROW", "PCOW"],
                    "SG": ["KRG", "KROG", "PCOG"],
                }
            else:
                self.sat_axes_maps = {
                    "SW": ["KRW", "KROW", "PCOW"],
                    "SL": ["KRG", "KROG", "PCOG"],
                }
        elif not all(keyword in RelativePermeability.RELPERM_FAMILIES[2]
                     for keyword in self.satfunc["KEYWORD"].unique()):
            raise ValueError(
                "Unrecognized saturation table keyword in data. This should not occur unless "
                "there has been changes to ecl2df. Update of this plugin might be required."
            )
        else:
            self.family = 2
            self.sat_axes_maps = {
                "SW": ["KRW", "PCOW"],
                "SG": ["KRG", "PCOG"],
                "SO": ["KROW", "KROG"],
            }
        self.scalfile = scalfile
        self.sheet_name = sheet_name
        self.scal = (load_scal_recommendation(self.scalfile, self.sheet_name)
                     if self.scalfile is not None else None)
        self.set_callbacks(app)
    def __init__(
        self,
        app: Dash,
        webviz_settings: WebvizSettings,
        csvfile: str = None,
        ensembles: list = None,
        aggregated_csvfile: Path = None,
        aggregated_parameterfile: Path = None,
        observation_file: Path = None,
        observation_group: str = "general",
        remap_observation_keys: Dict[str, str] = None,
        remap_observation_values: Dict[str, str] = None,
        colors: Dict = None,
        initial_data: Dict = None,
        initial_layout: Dict = None,
    ):
        super().__init__()

        provider = EnsembleTableProviderFactory.instance()
        self._initial_data = initial_data if initial_data else {}
        self._initial_layout = initial_layout if initial_layout else {}
        if ensembles is not None and csvfile is not None:
            ensembles_dict: Dict[str, str] = {
                ens_name:
                webviz_settings.shared_settings["scratch_ensembles"][ens_name]
                for ens_name in ensembles
            }
            self._parameterproviderset = (
                provider.
                create_provider_set_from_per_realization_parameter_file(
                    ensembles_dict))
            self._tableproviderset = (
                provider.create_provider_set_from_per_realization_csv_file(
                    ensembles_dict, csvfile))
            self._ensemble_names = ensembles
        elif aggregated_csvfile and aggregated_parameterfile is not None:
            self._tableproviderset = (
                provider.create_provider_set_from_aggregated_csv_file(
                    aggregated_csvfile))
            self._parameterproviderset = (
                provider.create_provider_set_from_aggregated_csv_file(
                    aggregated_parameterfile))
            self._ensemble_names = self._tableproviderset.ensemble_names()
        else:
            raise ValueError(
                "Specify either ensembles and csvfile or aggregated_csvfile "
                "and aggregated_parameterfile")
        all_parameters: list = [
            self._parameterproviderset.ensemble_provider(ens).column_names()
            for ens in self._ensemble_names
        ]
        self._parameter_names: list = list(set().union(*all_parameters))
        all_data_columns: list = [
            self._tableproviderset.ensemble_provider(ens).column_names()
            for ens in self._ensemble_names
        ]
        self._data_column_names: list = list(set().union(*all_data_columns))
        dfs = []
        for ens in self._ensemble_names:
            df = self._parameterproviderset.ensemble_provider(
                ens).get_column_data(column_names=self._parameterproviderset.
                                     ensemble_provider(ens).column_names())
            df["ENSEMBLE"] = ens
            dfs.append(df)
        parameterdf = pd.concat(dfs)
        self._realizations = sorted(list(parameterdf["REAL"].unique()))
        self._parameter_filter = ParameterFilter(self.uuid("parameter-filter"),
                                                 parameterdf)
        self._observationfile = observation_file
        self._observationmodel = (ObservationModel(
            get_path(self._observationfile),
            observation_group,
            remap_observation_keys,
            remap_observation_values,
        ) if self._observationfile else None)
        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "js" /
            "clientside_functions.js")

        self._colors: Dict = unique_colors(self._ensemble_names,
                                           webviz_settings.theme)
        if colors is not None:
            self._colors.update(colors)

        self.set_callbacks(app)
    def __init__(
        self,
        app: Dash,
        webviz_settings: WebvizSettings,
        ensembles: list,
        surface_attributes: list,
        surface_name_filter: List[str] = None,
        wellfolder: Path = None,
        wellsuffix: str = ".w",
        zonelog: str = None,
        mdlog: str = None,
        well_tvdmin: Union[int, float] = None,
        well_tvdmax: Union[int, float] = None,
        well_downsample_interval: int = None,
        calculate_percentiles: bool = False,
        initial_settings: Dict = None,
    ):

        super().__init__()
        self._initial_settings = initial_settings if initial_settings else {}

        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "structural_uncertainty.css")
        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "js" /
            "clientside_functions.js")
        self._calculate_percentiles = calculate_percentiles
        self._wellfolder = wellfolder
        self._wellsuffix = wellsuffix
        self._wellfiles: List = []
        if wellfolder is not None:
            self._wellfiles = json.load(find_files(wellfolder, wellsuffix))

        self._well_set_model = WellSetModel(
            self._wellfiles,
            zonelog=zonelog,
            mdlog=mdlog,
            tvdmin=well_tvdmin,
            tvdmax=well_tvdmax,
            downsample_interval=well_downsample_interval,
        )
        self._use_wells = bool(self._wellfiles)
        if (self._initial_settings.get("intersection_data", {}).get("well")
                and not self._use_wells):
            raise KeyError(
                "Well is specified in initial settings but no well data is found!"
            )
        self._surf_attrs = surface_attributes
        self._ensemble_paths = {
            ens: webviz_settings.shared_settings["scratch_ensembles"][ens]
            for ens in ensembles
        }

        # Create a table of surface files
        surface_table = find_surfaces(self._ensemble_paths)
        # Filter on provided surface attributes
        surface_table = surface_table[surface_table["attribute"].isin(
            self._surf_attrs)]
        # Filter on provided surface names
        self._surfacenames = (list(surface_table["name"].unique())
                              if surface_name_filter is None else
                              surface_name_filter)
        surface_table = surface_table[surface_table["name"].isin(
            surface_name_filter)]

        if surface_table.empty:
            raise ValueError("No surfaces found with the given attributes")

        self.ensembles = list(surface_table["ENSEMBLE"].unique())
        for _, attr_df in surface_table.groupby("attribute"):

            if set(attr_df["name"].unique()) != set(self._surfacenames):
                raise ValueError(
                    "Surface attributes has different surfaces. This is not supported!"
                )

        self._surface_ensemble_set_model = {
            ens: SurfaceSetModel(surf_ens_df)
            for ens, surf_ens_df in surface_table.groupby("ENSEMBLE")
        }
        self._realizations = sorted(list(surface_table["REAL"].unique()))

        self._zonelog = zonelog
        colors = [
            "#1f77b4",  # muted blue
            "#ff7f0e",  # safety orange
            "#2ca02c",  # cooked asparagus green
            "#d62728",  # brick red
            "#9467bd",  # muted purple
            "#8c564b",  # chestnut brown
            "#e377c2",  # raspberry yogurt pink
            "#7f7f7f",  # middle gray
            "#bcbd22",  # curry yellow-green
            "#17becf",  # blue-teal
        ]
        self._surfacecolors = [{
            "surfacename":
            surfacename,
            "ensemble":
            ens,
            "COLOR":
            self._initial_settings.get("colors", {}).get(surfacename, {}).get(
                ens, colors[idx % len(colors)]),
        } for idx, surfacename in enumerate(self._surfacenames)
                               for ens in self.ensembles]
        self._color_picker = ColorPicker(
            app=app,
            uuid=self.uuid("colorpicker"),
            dframe=pd.DataFrame(self._surfacecolors),
        )
        self.first_surface_geometry = self._surface_ensemble_set_model[
            self.ensembles[0]].first_surface_geometry
        self.set_callbacks(app)
Example #8
0
import pkg_resources
import json
from pathlib import Path
from webviz_config.webviz_assets import WEBVIZ_ASSETS

ASSETS_DIR = Path(pkg_resources.resource_filename("webviz_ert", "assets"))
WEBVIZ_ASSETS.add(ASSETS_DIR / "bootstrap-grid.css")
WEBVIZ_ASSETS.add(ASSETS_DIR / "ert-style.css")
with open(ASSETS_DIR / "ert-style.json") as f:
    ERTSTYLE = json.load(f)

WEBVIZ_CONFIG = (
    Path(pkg_resources.resource_filename("webviz_ert", "assets")) /
    "webviz-config.yml")
Example #9
0
    def __init__(
        self,
        app: dash.Dash,
        webviz_settings: WebvizSettings,
        ensembles: Optional[list] = None,
        rel_file_pattern: str = "share/results/unsmry/*.arrow",
        perform_presampling: bool = False,
        obsfile: Path = None,
        options: dict = None,
        sampling: str = Frequency.MONTHLY.value,
        predefined_expressions: str = None,
        line_shape_fallback: str = "linear",
    ) -> None:
        super().__init__()

        # NOTE: Temporary css, pending on new wcc modal component.
        # See: https://github.com/equinor/webviz-core-components/issues/163
        WEBVIZ_ASSETS.add(
            Path(webviz_subsurface.__file__).parent / "_assets" / "css" /
            "modal.css")

        self._webviz_settings = webviz_settings
        self._obsfile = obsfile

        self._line_shape_fallback = set_simulation_line_shape_fallback(
            line_shape_fallback)

        # Must define valid freqency!
        if Frequency.from_string_value(sampling) is None:
            raise ValueError(
                'Sampling frequency conversion is "None", i.e. Raw sampling, and '
                "is not supported by plugin yet!")
        self._sampling = Frequency(sampling)
        self._presampled_frequency = None

        # TODO: Update functionality when allowing raw data and csv file input
        # NOTE: If csv is implemented-> handle/disable statistics, INTVL_, AVG_, delta
        # ensemble, etc.
        if ensembles is not None:
            ensemble_paths: Dict[str, Path] = {
                ensemble_name:
                webviz_settings.shared_settings["scratch_ensembles"]
                [ensemble_name]
                for ensemble_name in ensembles
            }
            if perform_presampling:
                self._presampled_frequency = self._sampling
                self._input_provider_set = create_presampled_provider_set_from_paths(
                    ensemble_paths, rel_file_pattern,
                    self._presampled_frequency)
            else:
                self._input_provider_set = create_lazy_provider_set_from_paths(
                    ensemble_paths, rel_file_pattern)
        else:
            raise ValueError('Incorrect argument, must provide "ensembles"')

        if not self._input_provider_set:
            raise ValueError(
                "Initial provider set is undefined, and ensemble summary providers"
                " are not instanciated for plugin")

        self._theme = webviz_settings.theme

        self._observations = {}
        if self._obsfile:
            self._observations = check_and_format_observations(
                get_path(self._obsfile))

        # NOTE: Initially keep set of all vector names - can make dynamic if wanted?
        vector_names = self._input_provider_set.all_vector_names()
        non_historical_vector_names = [
            vector for vector in vector_names
            if historical_vector(vector, None, False) not in vector_names
        ]

        # NOTE: Initially: With set of vector names, the vector selector data is static
        # Can be made dynamic based on selected ensembles - i.e. vectors present among
        # selected providers?
        self._vector_selector_base_data: list = []
        self._vector_calculator_data: list = []
        for vector in non_historical_vector_names:
            split = vector.split(":")
            add_vector_to_vector_selector_data(
                self._vector_selector_base_data,
                vector,
                simulation_vector_description(split[0]),
            )
            add_vector_to_vector_selector_data(
                self._vector_calculator_data,
                vector,
                simulation_vector_description(split[0]),
            )

            metadata = (self._input_provider_set.vector_metadata(vector)
                        if self._input_provider_set else None)
            if metadata and metadata.is_total:
                # Get the likely name for equivalent rate vector and make dropdown options.
                # Requires that the time_index was either defined or possible to infer.
                avgrate_vec = rename_vector_from_cumulative(vector=vector,
                                                            as_rate=True)
                interval_vec = rename_vector_from_cumulative(vector=vector,
                                                             as_rate=False)

                avgrate_split = avgrate_vec.split(":")
                interval_split = interval_vec.split(":")

                add_vector_to_vector_selector_data(
                    self._vector_selector_base_data,
                    avgrate_vec,
                    f"{simulation_vector_description(avgrate_split[0])} ({avgrate_vec})",
                )
                add_vector_to_vector_selector_data(
                    self._vector_selector_base_data,
                    interval_vec,
                    f"{simulation_vector_description(interval_split[0])} ({interval_vec})",
                )

        # Retreive predefined expressions from configuration and validate
        self._predefined_expressions_path = (
            None if predefined_expressions is None else webviz_settings.
            shared_settings["predefined_expressions"][predefined_expressions])
        self._predefined_expressions = expressions_from_config(
            get_path(self._predefined_expressions_path) if self.
            _predefined_expressions_path else None)
        for expression in self._predefined_expressions:
            valid, message = validate_predefined_expression(
                expression, self._vector_selector_base_data)
            if not valid:
                warnings.warn(message)
            expression["isValid"] = valid

        # Create initial vector selector data with predefined expressions
        self._initial_vector_selector_data = copy.deepcopy(
            self._vector_selector_base_data)
        add_expressions_to_vector_selector_data(
            self._initial_vector_selector_data, self._predefined_expressions)

        plot_options = options if options else {}
        self._initial_visualization_selection = VisualizationOptions(
            plot_options.get("visualization", "statistics"))
        self._initial_vectors: List[str] = []
        if "vectors" not in plot_options:
            self._initial_vectors = []
        for vector in [
                vector for vector in ["vector1", "vector2", "vector3"]
                if vector in plot_options
        ]:
            self._initial_vectors.append(plot_options[vector])
        self._initial_vectors = self._initial_vectors[:3]

        # Set callbacks
        self.set_callbacks(app)