Skip to content

TrackModelResult

modelskill.TrackModelResult

Bases: TimeSeries, Alignable

Construct a TrackModelResult from a dfs0 file, mikeio.Dataset, pandas.DataFrame or a xarray.Datasets

Parameters:

Name Type Description Default
data TrackType

The input data or file path

required
name Optional[str]

The name of the model result, by default None (will be set to file name or item name)

None
item str | int | None

If multiple items/arrays are present in the input an item must be given (as either an index or a string), by default None

None
x_item str | int | None

Item of the first coordinate of positions, by default None

0
y_item str | int | None

Item of the second coordinate of positions, by default None

1
quantity Quantity

Model quantity, for MIKE files this is inferred from the EUM information

None
keep_duplicates (str, bool)

Strategy for handling duplicate timestamps (wraps xarray.Dataset.drop_duplicates) "first" to keep first occurrence, "last" to keep last occurrence, False to drop all duplicates, "offset" to add milliseconds to consecutive duplicates, by default "first"

'first'
aux_items Optional[list[int | str]]

Auxiliary items, by default None

None
Source code in modelskill/model/track.py
class TrackModelResult(TimeSeries, Alignable):
    """Construct a TrackModelResult from a dfs0 file,
    mikeio.Dataset, pandas.DataFrame or a xarray.Datasets

    Parameters
    ----------
    data : types.TrackType
        The input data or file path
    name : Optional[str], optional
        The name of the model result,
        by default None (will be set to file name or item name)
    item : str | int | None, optional
        If multiple items/arrays are present in the input an item
        must be given (as either an index or a string), by default None
    x_item : str | int | None, optional
        Item of the first coordinate of positions, by default None
    y_item : str | int | None, optional
        Item of the second coordinate of positions, by default None
    quantity : Quantity, optional
        Model quantity, for MIKE files this is inferred from the EUM information
    keep_duplicates : (str, bool), optional
        Strategy for handling duplicate timestamps (wraps xarray.Dataset.drop_duplicates)
        "first" to keep first occurrence, "last" to keep last occurrence,
        False to drop all duplicates, "offset" to add milliseconds to
        consecutive duplicates, by default "first"
    aux_items : Optional[list[int | str]], optional
        Auxiliary items, by default None
    """

    def __init__(
        self,
        data: TrackType,
        *,
        name: Optional[str] = None,
        item: str | int | None = None,
        quantity: Optional[Quantity] = None,
        x_item: str | int = 0,
        y_item: str | int = 1,
        keep_duplicates: str | bool = "first",
        aux_items: Optional[Sequence[int | str]] = None,
    ) -> None:
        if not self._is_input_validated(data):
            data = _parse_track_input(
                data=data,
                name=name,
                item=item,
                quantity=quantity,
                x_item=x_item,
                y_item=y_item,
                keep_duplicates=keep_duplicates,
                aux_items=aux_items,
            )

        assert isinstance(data, xr.Dataset)
        data_var = str(list(data.data_vars)[0])
        data[data_var].attrs["kind"] = "model"
        super().__init__(data=data)

    def extract(
        self, obs: TrackObservation, spatial_method: Optional[str] = None
    ) -> TrackModelResult:
        if not isinstance(obs, TrackObservation):
            raise ValueError(f"obs must be a TrackObservation not {type(obs)}")
        if spatial_method is not None:
            raise NotImplementedError(
                "spatial interpolation not possible when matching track model results with track observations"
            )
        return self

    def align(self, observation: Observation, **kwargs: Any) -> xr.Dataset:
        spatial_tolerance = 1e-3

        mri = self
        mod_df = mri.data.to_dataframe()
        obs_df = observation.data.to_dataframe()

        # 1. inner join on time
        df = mod_df.join(obs_df, how="inner", lsuffix="_mod", rsuffix="_obs")

        # 2. remove model points outside observation track
        n_points = len(df)
        keep_x = np.abs((df.x_mod - df.x_obs)) < spatial_tolerance
        keep_y = np.abs((df.y_mod - df.y_obs)) < spatial_tolerance
        df = df[keep_x & keep_y]
        if n_points_removed := n_points - len(df):
            warnings.warn(
                f"Removed {n_points_removed} model points outside observation track (spatial_tolerance={spatial_tolerance})"
            )
        return mri.data.sel(time=df.index)

gtype property

gtype

Geometry type

n_points property

n_points

Number of data points

name property writable

name

Name of time series (value item name)

plot instance-attribute

plot = plotter(self)

Plot using the ComparerPlotter

Examples:

>>> obj.plot.timeseries()
>>> obj.plot.hist()

quantity property writable

quantity

Quantity of time series

time property

time

Time index

values property

values

Values as numpy array

x property writable

x

x-coordinate

y property writable

y

y-coordinate

equals

equals(other)

Check if two TimeSeries are equal

Source code in modelskill/timeseries/_timeseries.py
def equals(self, other: TimeSeries) -> bool:
    """Check if two TimeSeries are equal"""
    return self.data.equals(other.data)

sel

sel(**kwargs)

Select data by label

Source code in modelskill/timeseries/_timeseries.py
def sel(self: T, **kwargs: Any) -> T:
    """Select data by label"""
    return self.__class__(self.data.sel(**kwargs))

to_dataframe

to_dataframe()

Convert matched data to pandas DataFrame

Include x, y coordinates only if gtype=track

Returns:

Type Description
DataFrame

data as a pandas DataFrame

Source code in modelskill/timeseries/_timeseries.py
def to_dataframe(self) -> pd.DataFrame:
    """Convert matched data to pandas DataFrame

    Include x, y coordinates only if gtype=track

    Returns
    -------
    pd.DataFrame
        data as a pandas DataFrame
    """
    if self.gtype == str(GeometryType.POINT):
        # we remove the scalar coordinate variables as they
        # will otherwise be columns in the dataframe
        return self.data.drop_vars(["x", "y", "z"]).to_dataframe()
    elif self.gtype == str(GeometryType.TRACK):
        df = self.data.drop_vars(["z"]).to_dataframe()
        # make sure that x, y cols are first
        cols = ["x", "y"] + [c for c in df.columns if c not in ["x", "y"]]
        return df[cols]
    else:
        raise NotImplementedError(f"Unknown gtype: {self.gtype}")

trim

trim(start_time=None, end_time=None, buffer='1s')

Trim observation data to a given time interval

Parameters:

Name Type Description Default
start_time Timestamp

start time

None
end_time Timestamp

end time

None
buffer str

buffer time around start and end time, by default "1s"

'1s'
Source code in modelskill/timeseries/_timeseries.py
def trim(
    self: T,
    start_time: Optional[pd.Timestamp] = None,
    end_time: Optional[pd.Timestamp] = None,
    buffer: str = "1s",
) -> T:
    """Trim observation data to a given time interval

    Parameters
    ----------
    start_time : pd.Timestamp
        start time
    end_time : pd.Timestamp
        end time
    buffer : str, optional
        buffer time around start and end time, by default "1s"
    """
    # Expand time interval with buffer
    start_time = pd.Timestamp(start_time) - pd.Timedelta(buffer)
    end_time = pd.Timestamp(end_time) + pd.Timedelta(buffer)

    data = self.data.sel(time=slice(start_time, end_time))
    if len(data.time) == 0:
        raise ValueError(
            f"No data left after trimming to {start_time} - {end_time}"
        )
    return self.__class__(data)

modelskill.timeseries._plotter.MatplotlibTimeSeriesPlotter

Bases: TimeSeriesPlotter

Source code in modelskill/timeseries/_plotter.py
class MatplotlibTimeSeriesPlotter(TimeSeriesPlotter):
    def __init__(self, ts) -> None:
        self._ts = ts

    def __call__(self, **kwargs):
        # default to timeseries plot
        self.timeseries(**kwargs)

    def timeseries(
        self, title=None, color=None, marker=".", linestyle="None", **kwargs
    ):
        """Plot timeseries

        Wraps pandas.DataFrame plot() method.

        Parameters
        ----------
        title : str, optional
            plot title, default: [name]
        color : str, optional
            plot color, by default '#d62728'
        marker : str, optional
            plot marker, by default '.'
        linestyle : str, optional
            line style, by default None
        **kwargs
            other keyword arguments to df.plot()
        """
        kwargs["color"] = self._ts._color if color is None else color
        ax = self._ts._values_as_series.plot(
            marker=marker, linestyle=linestyle, **kwargs
        )

        title = self._ts.name if title is None else title
        ax.set_title(title)

        ax.set_ylabel(str(self._ts.quantity))
        return ax

    def hist(self, bins=100, title=None, color=None, **kwargs):
        """Plot histogram of timeseries values

        Wraps pandas.DataFrame hist() method.

        Parameters
        ----------
        bins : int, optional
            specification of bins, by default 100
        title : str, optional
            plot title, default: observation name
        color : str, optional
            plot color, by default "#d62728"
        **kwargs
            other keyword arguments to df.hist()

        Returns
        -------
        matplotlib axes
        """
        title = self._ts.name if title is None else title

        kwargs["color"] = self._ts._color if color is None else color

        ax = self._ts._values_as_series.hist(bins=bins, **kwargs)
        ax.set_title(title)
        ax.set_xlabel(str(self._ts.quantity))
        return ax

hist

hist(bins=100, title=None, color=None, **kwargs)

Plot histogram of timeseries values

Wraps pandas.DataFrame hist() method.

Parameters:

Name Type Description Default
bins int

specification of bins, by default 100

100
title str

plot title, default: observation name

None
color str

plot color, by default "#d62728"

None
**kwargs

other keyword arguments to df.hist()

{}

Returns:

Type Description
matplotlib axes
Source code in modelskill/timeseries/_plotter.py
def hist(self, bins=100, title=None, color=None, **kwargs):
    """Plot histogram of timeseries values

    Wraps pandas.DataFrame hist() method.

    Parameters
    ----------
    bins : int, optional
        specification of bins, by default 100
    title : str, optional
        plot title, default: observation name
    color : str, optional
        plot color, by default "#d62728"
    **kwargs
        other keyword arguments to df.hist()

    Returns
    -------
    matplotlib axes
    """
    title = self._ts.name if title is None else title

    kwargs["color"] = self._ts._color if color is None else color

    ax = self._ts._values_as_series.hist(bins=bins, **kwargs)
    ax.set_title(title)
    ax.set_xlabel(str(self._ts.quantity))
    return ax

timeseries

timeseries(title=None, color=None, marker='.', linestyle='None', **kwargs)

Plot timeseries

Wraps pandas.DataFrame plot() method.

Parameters:

Name Type Description Default
title str

plot title, default: [name]

None
color str

plot color, by default '#d62728'

None
marker str

plot marker, by default '.'

'.'
linestyle str

line style, by default None

'None'
**kwargs

other keyword arguments to df.plot()

{}
Source code in modelskill/timeseries/_plotter.py
def timeseries(
    self, title=None, color=None, marker=".", linestyle="None", **kwargs
):
    """Plot timeseries

    Wraps pandas.DataFrame plot() method.

    Parameters
    ----------
    title : str, optional
        plot title, default: [name]
    color : str, optional
        plot color, by default '#d62728'
    marker : str, optional
        plot marker, by default '.'
    linestyle : str, optional
        line style, by default None
    **kwargs
        other keyword arguments to df.plot()
    """
    kwargs["color"] = self._ts._color if color is None else color
    ax = self._ts._values_as_series.plot(
        marker=marker, linestyle=linestyle, **kwargs
    )

    title = self._ts.name if title is None else title
    ax.set_title(title)

    ax.set_ylabel(str(self._ts.quantity))
    return ax