Skip to content

mibitrans.visualize API reference

animation

animate_1d(x_axis_parameter, y_axis_parameter, time_parameter, y_names=None, y_colors=None, linestyle=None)

Animate any type and number of input 1D plottables.

Source code in mibitrans/visualize/animation.py
def animate_1d(
    x_axis_parameter: np.ndarray, y_axis_parameter, time_parameter, y_names=None, y_colors=None, linestyle=None
):
    """Animate any type and number of input 1D plottables."""
    if not isinstance(y_axis_parameter, list):
        y_axis_parameter = [y_axis_parameter]
    fig, ax = plt.subplots()
    plot_bin = []
    max_conc = 0
    for i, y in enumerate(y_axis_parameter):
        line = ax.plot(x_axis_parameter, y[0, :], color=y_colors[i], label=y_names[i], linestyle=linestyle[i])[0]
        if np.max(y) > max_conc:
            max_conc = np.max(y)
        plot_bin.append(line)
    ax.set_ylim(bottom=0, top=max_conc + max_conc / 10)
    ax.set_xlabel("Distance from source [m]")
    ax.set_ylabel("Concentration [g/m3]")
    ax.legend()
    n_frames = len(time_parameter)

    def update(frame):
        """Update plot with values for the next time step in the animation."""
        for i, y in enumerate(y_axis_parameter):
            plot_bin[i].set_xdata(x_axis_parameter)
            plot_bin[i].set_ydata(y[frame, :])
        ax.set_title(f"Concentration distribution at t={time_parameter[frame]} days")
        return plot_bin

    ani = animation.FuncAnimation(fig=fig, func=update, frames=n_frames)
    return ani

plot_line

Author: Jorrit Bakker.

Module plotting a 3D matrix of contaminant plume concentrations as a line.

allowed_model_types()

Return object of parent class that is allowed for input/output.

Source code in mibitrans/visualize/plot_line.py
def allowed_model_types():
    """Return object of parent class that is allowed for input/output."""
    return mibitrans.transport.model_parent.Results

breakthrough(model, x_position, y_position=0, relative_concentration=False, legend_names=None, animate=False, **kwargs)

Plot contaminant breakthrough curve at given x and y position in model domain.

Parameters:

Name Type Description Default
model

Model object from mibitrans.transport, or list of model objects.

required
x_position

x-position along the plume (longitudinal direction).

required
y_position

y-position across the plume (transverse horizontal direction). By default, at the center of the plume (at y=0).

required
relative_concentration (bool, optional)

If set to True, will plot concentrations relative to maximum source zone concentrations at t=0. By default, absolute concentrations are shown.

required
legend_names str | list

List of legend names as strings, in the same order as given models. By default, no legend is shown.

None
animate bool

If True, animation of contaminant plume until given time is shown. If multiple models are given as input, dt should be the same for each one to ensure accurate animation. Default is False.

False
**kwargs

Arguments to be passed to plt.plot().

required
Source code in mibitrans/visualize/plot_line.py
def breakthrough(
    model, x_position, y_position=0, relative_concentration=False, legend_names=None, animate=False, **kwargs
):
    """Plot contaminant breakthrough curve at given x and y position in model domain.

    Args:
        model : Model object from mibitrans.transport, or list of model objects.
        x_position : x-position along the plume (longitudinal direction).
        y_position : y-position across the plume (transverse horizontal direction).
            By default, at the center of the plume (at y=0).
        relative_concentration (bool, optional) : If set to True, will plot concentrations relative to maximum source
            zone concentrations at t=0. By default, absolute concentrations are shown.
        legend_names (str | list, optional): List of legend names as strings, in the same order as given models.
            By default, no legend is shown.
        animate (bool, optional): If True, animation of contaminant plume until given time is shown. If multiple models
            are given as input, dt should be the same for each one to ensure accurate animation. Default is False.
        **kwargs : Arguments to be passed to plt.plot().
    """
    if not isinstance(model, list):
        model = [model]
    if not isinstance(legend_names, list) and legend_names is not None:
        legend_names = [legend_names]

    plot_array_list = []
    # Checks for list model input: dt should be equal, time should be smaller than the smallest end time, y_position
    # should be inside narrowest domain boundaries
    for mod in model:
        check_model_type(mod, allowed_model_types())
        x_pos = check_x_in_domain(mod, x_position)
        y_pos = check_y_in_domain(mod, y_position)
        if relative_concentration:
            plot_array_list.append(mod.relative_cxyt[:, y_pos, x_pos])
            y_label = relative_conc_ylabel
        else:
            plot_array_list.append(mod.cxyt[:, y_pos, x_pos])
            y_label = absolute_conc_ylabel

    # Non animated plot
    if not animate:
        for i, mod in enumerate(model):
            if legend_names is not None:
                plt.plot(mod.t, plot_array_list[i], label=legend_names[i], **kwargs)
            else:
                plt.plot(mod.t, plot_array_list[i], **kwargs)

        plt.ylim(bottom=0)
        plt.xlabel("Time [days]")
        plt.ylabel(y_label)
        plot_title = _plot_title_generator(
            "Breakthrough", model[0], x_position=x_position, y_position=y_position, multiple=len(model) > 1
        )
        plt.title(plot_title)
        if legend_names is not None:
            plt.legend()

    # Animated plot
    else:
        fig, ax = plt.subplots()
        plot_bin = []
        max_conc = 0
        max_time = 0
        for i, mod in enumerate(model):
            if legend_names is not None:
                line = ax.plot(mod.t[0], plot_array_list[i][0], label=legend_names[i])[0]
            else:
                line = ax.plot(mod.t[0], plot_array_list[i][0], **kwargs)[0]

            # As plot extent is decided by first initiation of plot, ensure that axis concentration and time limits
            # are corresponding with their maximum values
            if mod.t[-1] > max_time:
                max_time = mod.t[-1]
            if np.max(plot_array_list[i]) > max_conc:
                max_conc = np.max(plot_array_list[i])
            plot_bin.append(line)
        ax.set_xlim(right=max_time)
        ax.set_ylim(bottom=0, top=max_conc + max_conc / 10)
        ax.set_xlabel("Time [days]")
        ax.set_ylabel(y_label)
        if legend_names is not None:
            ax.legend()

        def update(frame):
            for i, mod in enumerate(model):
                plot_bin[i].set_xdata(mod.t[:frame])
                plot_bin[i].set_ydata(plot_array_list[i][:frame])
                ax.set_title(f"Breakthrough curve at t={mod.t[frame]} days")
            return plot_bin

        ani = animation.FuncAnimation(fig=fig, func=update, frames=len(model[0].t))
        return ani

centerline(model, y_position=0, time=None, relative_concentration=False, legend_names=None, animate=False, **kwargs)

Plot center of contaminant plume of one or multiple models as a line, at a specified time and y position.

Parameters:

Name Type Description Default
model

Model object from mibitrans.transport, or list of model objects.

required
y_position float

y-position across the plume (transverse horizontal direction) for the plot. By default, the center of the plume at y=0 is plotted.

0
time float

Point of time for the plot. Will show the closest time step to given value. By default, last point in time is plotted.

None
relative_concentration (bool, optional)

If set to True, will plot concentrations relative to maximum source zone concentrations at t=0. By default, absolute concentrations are shown.

required
legend_names str | list

List of legend names as strings, in the same order as given models. By default, no legend is shown.

None
animate bool

If True, animation of contaminant plume until given time is shown. If multiple models are given as input, dt should be the same for each one to ensure accurate animation. Default is False.

False
**kwargs

Arguments to be passed to plt.plot().

required
Source code in mibitrans/visualize/plot_line.py
def centerline(
    model, y_position=0, time=None, relative_concentration=False, legend_names=None, animate=False, **kwargs
):
    """Plot center of contaminant plume of one or multiple models as a line, at a specified time and y position.

    Args:
        model : Model object from mibitrans.transport, or list of model objects.
        y_position (float, optional): y-position across the plume (transverse horizontal direction) for the plot.
            By default, the center of the plume at y=0 is plotted.
        time (float, optional): Point of time for the plot. Will show the closest time step to given value.
            By default, last point in time is plotted.
        relative_concentration (bool, optional) : If set to True, will plot concentrations relative to maximum source
            zone concentrations at t=0. By default, absolute concentrations are shown.
        legend_names (str | list, optional): List of legend names as strings, in the same order as given models.
            By default, no legend is shown.
        animate (bool, optional): If True, animation of contaminant plume until given time is shown. If multiple models
            are given as input, dt should be the same for each one to ensure accurate animation. Default is False.
        **kwargs : Arguments to be passed to plt.plot().

    """
    if not isinstance(model, list):
        model = [model]
    if not isinstance(legend_names, list) and legend_names is not None:
        legend_names = [legend_names]

    plot_array_list = []
    # Checks for list model input: dt should be equal, time should be smaller than the smallest end time, y_position
    # should be inside narrowest domain boundaries
    for mod in model:
        check_model_type(mod, allowed_model_types())
        y_pos = check_y_in_domain(mod, y_position)
        t_pos = check_time_in_domain(mod, time)

        if relative_concentration:
            if animate:
                plot_array_list.append(mod.relative_cxyt[:, y_pos, :])
            else:
                plot_array_list.append(mod.relative_cxyt[t_pos, y_pos, :])
            y_label = relative_conc_ylabel
        else:
            if animate:
                plot_array_list.append(mod.cxyt[:, y_pos, :])
            else:
                plot_array_list.append(mod.cxyt[t_pos, y_pos, :])
            y_label = absolute_conc_ylabel

    # Non-animated plot
    if not animate:
        for i, mod in enumerate(model):
            if legend_names is not None:
                plt.plot(mod.x, plot_array_list[i], label=legend_names[i], **kwargs)
            else:
                plt.plot(mod.x, plot_array_list[i], **kwargs)

        plt.ylim(bottom=0)
        plt.xlabel("Distance from source [m]")
        plt.ylabel(y_label)

        plot_title = _plot_title_generator(
            "Centerline", model[0], time=model[0].t[t_pos], y_position=y_position, multiple=len(model) > 1
        )
        plt.title(plot_title)
        if legend_names is not None:
            plt.legend()

    # Animated plot
    else:
        fig, ax = plt.subplots()
        plot_bin = []
        for i, mod in enumerate(model):
            if legend_names is not None:
                line = ax.plot(mod.x, plot_array_list[i][0, :], label=legend_names[i], **kwargs)[0]
            else:
                line = ax.plot(mod.x, plot_array_list[i][0, :], **kwargs)[0]
            plot_bin.append(line)
        ax.set_ylim(bottom=0)
        ax.set_xlabel("Distance from source [m]")
        ax.set_ylabel(y_label)

        if legend_names is not None:
            ax.legend()

        def update(frame):
            for i, mod in enumerate(model):
                plot_bin[i].set_xdata(mod.x)
                plot_bin[i].set_ydata(plot_array_list[i][frame, :])
                ax.set_title(f"Concentration distribution at t={mod.t[frame]} days")
            return plot_bin

        ani = animation.FuncAnimation(fig=fig, func=update, frames=t_pos + 1)
        return ani

transverse(model, x_position, time=None, relative_concentration=False, legend_names=None, animate=False, **kwargs)

Plot concentration distribution as a line horizontal transverse to the plume extent.

Parameters:

Name Type Description Default
model

Model object from mibitrans.transport, or list of model objects.

required
x_position

x-position along the plume (longitudinal direction) for the plot.

required
time float

Point of time for the plot. Will show the closest time step to given value. By default, last point in time is plotted.

None
relative_concentration (bool, optional)

If set to True, will plot concentrations relative to maximum source zone concentrations at t=0. By default, absolute concentrations are shown.

required
legend_names str | list

List of legend names as strings, in the same order as given models. By default, no legend is shown.

None
animate bool

If True, animation of contaminant plume until given time is shown. If multiple models are given as input, dt should be the same for each one to ensure accurate animation. Default is False.

False
**kwargs

Arguments to be passed to plt.plot().

required
Source code in mibitrans/visualize/plot_line.py
def transverse(model, x_position, time=None, relative_concentration=False, legend_names=None, animate=False, **kwargs):
    """Plot concentration distribution as a line horizontal transverse to the plume extent.

    Args:
        model : Model object from mibitrans.transport, or list of model objects.
        x_position : x-position along the plume (longitudinal direction) for the plot.
        time (float): Point of time for the plot. Will show the closest time step to given value.
            By default, last point in time is plotted.
        relative_concentration (bool, optional) : If set to True, will plot concentrations relative to maximum source
            zone concentrations at t=0. By default, absolute concentrations are shown.
        legend_names (str | list, optional): List of legend names as strings, in the same order as given models.
            By default, no legend is shown.
        animate (bool, optional): If True, animation of contaminant plume until given time is shown. If multiple models
            are given as input, dt should be the same for each one to ensure accurate animation. Default is False.
        **kwargs : Arguments to be passed to plt.plot().
    """
    if not isinstance(model, list):
        model = [model]
    if not isinstance(legend_names, list) and legend_names is not None:
        legend_names = [legend_names]

    plot_array_list = []
    # Checks for list model input: dt should be equal, time should be smaller than the smallest end time, y_position
    # should be inside narrowest domain boundaries
    for mod in model:
        check_model_type(mod, allowed_model_types())
        x_pos = check_x_in_domain(mod, x_position)
        t_pos = check_time_in_domain(mod, time)

        if relative_concentration:
            if animate:
                plot_array_list.append(mod.relative_cxyt[:, :, x_pos])
            else:
                plot_array_list.append(mod.relative_cxyt[t_pos, :, x_pos])
            y_label = relative_conc_ylabel
        else:
            if animate:
                plot_array_list.append(mod.cxyt[:, :, x_pos])
            else:
                plot_array_list.append(mod.cxyt[t_pos, :, x_pos])
            y_label = absolute_conc_ylabel

    if not animate:
        for i, mod in enumerate(model):
            if legend_names is not None:
                plt.plot(mod.y, plot_array_list[i], label=legend_names[i], **kwargs)
            else:
                plt.plot(mod.y, plot_array_list[i], **kwargs)

        plt.ylim(bottom=0)
        plt.xlabel("y-position [m]")
        plt.ylabel(y_label)
        plot_title = _plot_title_generator(
            "Transverse", model[0], time=model[0].t[t_pos], x_position=x_position, multiple=len(model) > 1
        )
        plt.title(plot_title)
        if legend_names is not None:
            plt.legend()
    else:
        fig, ax = plt.subplots()
        plot_bin = []
        max_conc = 0
        for i, mod in enumerate(model):
            if legend_names is not None:
                line = ax.plot(mod.y, plot_array_list[i][0, :], label=legend_names[i])[0]
            else:
                line = ax.plot(mod.y, plot_array_list[i][0, :], **kwargs)[0]
            if np.max(plot_array_list[i]) > max_conc:
                max_conc = np.max(plot_array_list[i])
            plot_bin.append(line)
        ax.set_ylim(bottom=0, top=max_conc + max_conc / 10)

        ax.set_xlabel("y-position [m]")
        ax.set_ylabel(y_label)

        if legend_names is not None:
            ax.legend()

        def update(frame):
            for i, mod in enumerate(model):
                plot_bin[i].set_xdata(mod.y)
                plot_bin[i].set_ydata(plot_array_list[i][frame, :])
                ax.set_title(f"Concentration distribution at t={mod.t[frame]} days")
            return plot_bin

        ani = animation.FuncAnimation(fig=fig, func=update, frames=t_pos + 1)
        return ani

plot_surface

plume_2d(model, time=None, relative_concentration=False, animate=False, **kwargs)

Plot contaminant plume as a 2D colormesh, at a specified time.

Parameters:

Name Type Description Default
model

Model object from mibitrans.transport.

required
time float

Point of time for the plot. Will show the closest time step to given value. By default, last point in time is plotted.

None
relative_concentration (bool, optional)

If set to True, will plot concentrations relative to maximum source zone concentrations at t=0. By default, absolute concentrations are shown.

required
animate bool

If True, animation of contaminant plume until given time is shown. Default is False.

False
**kwargs

Arguments to be passed to plt.pcolormesh().

required

Returns a matrix plot of the input plume as object.

Source code in mibitrans/visualize/plot_surface.py
def plume_2d(model, time=None, relative_concentration=False, animate=False, **kwargs):
    """Plot contaminant plume as a 2D colormesh, at a specified time.

    Args:
        model : Model object from mibitrans.transport.
        time (float): Point of time for the plot. Will show the closest time step to given value.
            By default, last point in time is plotted.
        relative_concentration (bool, optional) : If set to True, will plot concentrations relative to maximum source
            zone concentrations at t=0. By default, absolute concentrations are shown.
        animate (bool, optional): If True, animation of contaminant plume until given time is shown. Default is
            False.
        **kwargs : Arguments to be passed to plt.pcolormesh().

    Returns a matrix plot of the input plume as object.
    """
    check_model_type(model, allowed_model_types())
    t_pos = check_time_in_domain(model, time)
    if relative_concentration:
        model_concentration = model.relative_cxyt
        z_label = relative_conc_zlabel
    else:
        model_concentration = model.cxyt
        z_label = absolute_conc_zlabel
    # Non animated plot
    if not animate:
        plt.pcolormesh(model.x, model.y, model_concentration[t_pos, :, :], **kwargs)
        plt.xlabel("Distance from source (m)")
        plt.ylabel("Distance from plume center (m)")
        plt.colorbar(label=z_label)
        plot_title = _plot_title_generator("Plume", model, time=model.t[t_pos])
        plt.title(plot_title)

    # Animated plot
    else:
        fig, ax = plt.subplots()
        mesh = ax.pcolormesh(
            model.x, model.y, model_concentration[0, :, :], vmin=0, vmax=np.max(model_concentration), **kwargs
        )
        cbar = fig.colorbar(mesh, ax=ax)
        cbar.set_label(z_label)
        ax.set_xlabel("Distance from source (m)")
        ax.set_ylabel("Distance from plume center (m)")

        def update(frame):
            mesh.set_array(model_concentration[frame, :, :])
            ax.set_title(f"Concentration distribution at t={model.t[frame]} days")
            return mesh

        ani = animation.FuncAnimation(fig=fig, func=update, frames=t_pos + 1)
        return ani

plume_3d(model, time=None, relative_concentration=False, animate=False, **kwargs)

Plot contaminant plume as a 3D surface, at a specified time.

Parameters:

Name Type Description Default
model

Model object from mibitrans.transport.

required
time float

Point of time for the plot. Will show the closest time step to given value. By default, last point in time is plotted.

None
relative_concentration (bool, optional)

If set to True, will plot concentrations relative to maximum source zone concentrations at t=0. By default, absolute concentrations are shown.

required
animate bool

If True, animation of contaminant plume until given time is shown. Default is False.

False
**kwargs

Arguments to be passed to plt.plot_surface().

required

Returns:

Type Description

ax (matplotlib.axes._axes.Axes) : Returns matplotlib axes object of plume plot.

Source code in mibitrans/visualize/plot_surface.py
def plume_3d(model, time=None, relative_concentration=False, animate=False, **kwargs):
    """Plot contaminant plume as a 3D surface, at a specified time.

    Args:
        model : Model object from mibitrans.transport.
        time (float): Point of time for the plot. Will show the closest time step to given value.
            By default, last point in time is plotted.
        relative_concentration (bool, optional) : If set to True, will plot concentrations relative to maximum source
            zone concentrations at t=0. By default, absolute concentrations are shown.
        animate (bool, optional): If True, animation of contaminant plume until given time is shown. Default is
            False.
        **kwargs : Arguments to be passed to plt.plot_surface().

    Returns:
        ax (matplotlib.axes._axes.Axes) : Returns matplotlib axes object of plume plot.
    """
    check_model_type(model, allowed_model_types())
    t_pos = check_time_in_domain(model, time)
    if relative_concentration:
        model_concentration = model.relative_cxyt
        z_label = relative_conc_zlabel
    else:
        model_concentration = model.cxyt
        z_label = absolute_conc_zlabel

    # Non animated plot
    xxx = np.tile(model.x, (len(model.t), len(model.y), 1))
    yyy = np.tile(model.y[:, None], (len(model.t), 1, len(model.x)))
    if not animate:
        fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
        ax.plot_surface(xxx[t_pos, :, :], yyy[t_pos, :, :], model_concentration[t_pos, :, :], **kwargs)
        ax.view_init(elev=30, azim=310)
        ax.set_xlabel("Distance from source (m)")
        ax.set_ylabel("Distance from plume center (m)")
        ax.set_zlabel(z_label)
        plot_title = _plot_title_generator("Plume", model, time=model.t[t_pos])
        ax.set_title(plot_title)
        return ax

    # Animated plot
    else:
        if "cmap" not in kwargs and "color" not in kwargs:
            kwargs["color"] = "tab:blue"
        model_max = np.max(model_concentration)
        fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
        surface = ax.plot_surface(
            xxx[0, :, :],
            yyy[0, :, :],
            model_concentration[0, :, :],
            vmin=0,
            vmax=model_max,
            **kwargs,
        )
        ax.set_xlabel("Distance from source (m)")
        ax.set_ylabel("Distance from plume center (m)")
        ax.set_zlabel(z_label)
        ax.set_zlim(0, model_max)

        # plot_surface creates a static surface; need to create new plot every time step
        def update(frame):
            # nonlocal needed in order for the previous plot to be removed before new one is plotted
            nonlocal surface
            surface.remove()
            surface = ax.plot_surface(
                xxx[frame, :, :],
                yyy[frame, :, :],
                model_concentration[frame, :, :],
                vmin=0,
                vmax=model_max,
                **kwargs,
            )
            ax.set_title(f"Concentration distribution at t={model.t[frame]} days")
            return surface

        ani = animation.FuncAnimation(fig=fig, func=update, frames=t_pos + 1)
        return ani

show_conditions

Author: Jorrit Bakker.

Module including various methods to visualize (input) parameter conditions, intended to only be called internally.

model_grid(model_parameters)

Visualize the model grid.

Source code in mibitrans/visualize/show_conditions.py
def model_grid(model_parameters):
    """Visualize the model grid."""
    return None

source_zone(source_parameters)

Visualize source zone conditions.

Source code in mibitrans/visualize/show_conditions.py
def source_zone(source_parameters):
    """Visualize source zone conditions."""
    source_y = source_parameters.source_zone_boundary
    source_c = source_parameters.source_zone_concentration

    y_discretization = np.linspace(-source_y[-1] - source_y[-1] / 10, source_y[-1] + source_y[-1] / 10, 10000)
    c_values = np.zeros(len(y_discretization))
    for i, y in enumerate(source_y[::-1]):
        c_values = np.where((y_discretization <= y) & (y_discretization >= -y), source_c[-(i + 1)], c_values)

    indexer = np.linspace(1, 0.3, len(source_y))
    colormap = matplotlib.colormaps["YlGnBu"]

    plt.figure(dpi=300)

    for i, y in enumerate(source_y):
        if i == 0:
            plt.fill_betweenx(
                y=y_discretization,
                x1=c_values,
                where=(y_discretization <= y) & (y_discretization >= -y),
                color=colormap(indexer[i]),
                zorder=len(source_y) + 2,
            )
        else:
            plt.fill_betweenx(
                y=y_discretization,
                x1=c_values,
                # Boolean array for domain of source zone i
                where=((y_discretization <= y) & (y_discretization > source_y[i - 1]))
                | ((y_discretization >= -y) & (y_discretization < -source_y[i - 1])),
                color=colormap(indexer[i]),
                zorder=len(source_y) + 2 - i,
            )

    plt.xlabel(r"Source zone concentration $g/m^3$")
    plt.ylabel("Source zone y-coordinate")
    plt.title("Concentration distribution in the source zone")