Skip to content

viz2d.py

Viz2D

Viz2D(*args, **kwargs)

              flowchart TD
              erosionfront.visualization.viz2d.Viz2D[Viz2D]
              erosionfront.visualization.speedviz.ErosionSpeedViz[ErosionSpeedViz]
              erosionfront.visualization.gmaviz.GeometricMechanicsViz[GeometricMechanicsViz]
              erosionfront.visualization.simviz.SimulationViz[SimulationViz]
              erosionfront.visualization.topoviz.TopoViz[TopoViz]
              erosionfront.visualization.base.GraphingBase[GraphingBase]

                              erosionfront.visualization.speedviz.ErosionSpeedViz --> erosionfront.visualization.viz2d.Viz2D
                                erosionfront.visualization.base.GraphingBase --> erosionfront.visualization.speedviz.ErosionSpeedViz
                

                erosionfront.visualization.gmaviz.GeometricMechanicsViz --> erosionfront.visualization.viz2d.Viz2D
                                erosionfront.visualization.base.GraphingBase --> erosionfront.visualization.gmaviz.GeometricMechanicsViz
                

                erosionfront.visualization.simviz.SimulationViz --> erosionfront.visualization.viz2d.Viz2D
                                erosionfront.visualization.base.GraphingBase --> erosionfront.visualization.simviz.SimulationViz
                

                erosionfront.visualization.topoviz.TopoViz --> erosionfront.visualization.viz2d.Viz2D
                                erosionfront.visualization.base.GraphingBase --> erosionfront.visualization.topoviz.TopoViz
                



              click erosionfront.visualization.viz2d.Viz2D href "" "erosionfront.visualization.viz2d.Viz2D"
              click erosionfront.visualization.speedviz.ErosionSpeedViz href "" "erosionfront.visualization.speedviz.ErosionSpeedViz"
              click erosionfront.visualization.gmaviz.GeometricMechanicsViz href "" "erosionfront.visualization.gmaviz.GeometricMechanicsViz"
              click erosionfront.visualization.simviz.SimulationViz href "" "erosionfront.visualization.simviz.SimulationViz"
              click erosionfront.visualization.topoviz.TopoViz href "" "erosionfront.visualization.topoviz.TopoViz"
              click erosionfront.visualization.base.GraphingBase href "" "erosionfront.visualization.base.GraphingBase"
            

XXXX

Parameters

XXX

Attributes

TBD

Returns

XXX

Subclasses GraphingBase.

Parameters:

  • kwargs

    arguments to pass to constructor

Methods:

Source code in erosionfront/visualization/gmaviz.py
def __init__(
        self, 
        *args, 
        **kwargs,
    ) -> None:
    """
    2D visualization class.

    Subclasses `GraphingBase`.

    Arguments:
        kwargs:
            arguments to pass to constructor
    """
    self.props = {
        "βt_color" : "orange", #"magenta","violet"
        "βt_marker" : "o",
        "βc0_color" : "magenta", #"magenta","violet"
        "βc0_marker" : "v",
        "βc1_color" : "darkorchid", #"darkorchid",
        "βc1_marker" : "^",
        "βrs0_color" : "magenta", #"magenta","violet"
        "βrs0_marker" : "h",
        "βrs1_color" : "darkorchid", #"darkorchid",
        "βrs1_marker" : "H",
        "βmpx_color" : "g",
        "βmpx_marker" : "*",
        "cvx0_color" : "black",  #"blue",
        "cvx1_color" : "0.4", #"midnightblue",
        "ccv_color" : "crimson",
    }
    super().__init__(*args, **kwargs)

create_figure

create_figure(
    fig_name: str, fig_size: tuple[float, float] | None = None, dpi: int | None = None
) -> Figure

Initialize a :mod:Pyplot <matplotlib.pyplot> figure.

Set its size and dpi, set the font size, choose the Arial font family if possible, and append it to the figures dictionary.

Parameters

fig_name: name of figure; used as key in figures dictionary fig_size: optional width and height of figure in inches dpi: rasterization resolution

Returns

:obj:Pyplot figure <matplotlib.figure.Figure>: reference to :mod:MatPlotLib/Pyplot <matplotlib.pyplot> figure

Source code in erosionfront/visualization/base.py
def create_figure(
    self,
    fig_name: str,
    fig_size: tuple[float, float] | None = None,
    dpi: int | None = None,
) -> Figure:
    """
    Initialize a :mod:`Pyplot <matplotlib.pyplot>` figure.

    Set its size and dpi, set the font size,
    choose the Arial font family if possible,
    and append it to the figures dictionary.

    Parameters
    ----------
    fig_name:
        name of figure; used as key in figures dictionary
    fig_size:
        optional width and height of figure in inches
    dpi:
        rasterization resolution

    Returns
    -------
    :obj:`Pyplot figure <matplotlib.figure.Figure>`:
        reference to :mod:`MatPlotLib/Pyplot <matplotlib.pyplot>`
        figure
    """
    fig_size_: tuple[float, float] = (
        (8, 8) if fig_size is None else fig_size
    )
    dpi_: float = self.dpi if dpi is None else dpi
    logging.info(
        "gmplib.plot.GraphingBase:\n   "
        + f"Creating plot: {fig_name} size={fig_size_} @ {dpi_} dpi"
    )
    fig = plt.figure()
    self.fdict.update({fig_name: fig})
    fig.set_size_inches(fig_size_)
    fig.set_dpi(dpi_)
    return fig

get_aspect

get_aspect(axes: Axes) -> float

Get aspect ratio of graph.

Parameters

axes: the axes object of the figure

Returns

float: aspect ratio

Source code in erosionfront/visualization/base.py
def get_aspect(self, axes: plt.Axes) -> float:
    """
    Get aspect ratio of graph.

    Parameters
    ----------
    axes:
        the `axes` object of the figure

    Returns
    -------
    float:
        aspect ratio
    """
    # Total figure size
    figWH: tuple[float, float] \
        = axes.get_figure().get_size_inches() #type: ignore
    figW, figH = figWH
    # Axis size on figure
    bounds: tuple[float, float, float, float] = axes.get_position().bounds
    _, _, w, h = bounds
    # Ratio of display units
    disp_ratio: float = (figH * h) / (figW * w)
    # Ratio of data units
    # Negative over negative because of the order of subtraction
    # logging.info(axes.get_ylim(),axes.get_xlim())
    data_ratio: float = op.sub(*axes.get_ylim()) / op.sub(*axes.get_xlim())
    aspect_ratio: float = disp_ratio / data_ratio
    return aspect_ratio

get_fonts

get_fonts() -> list[str]

Fetch the names of all the font families available on the system.

Source code in erosionfront/visualization/base.py
def get_fonts(self) -> list[str]:
    """Fetch the names of all the font families available on the system."""
    fpaths = matplotlib.font_manager.findSystemFonts()
    fonts: list[str] = []
    for fpath in fpaths:
        try:
            font = matplotlib.font_manager.get_font(fpath).family_name
            fonts.append(font)
        except RuntimeError as re:
            logging.debug(f"{re}: failed to get font name for {fpath}")
            pass
    return fonts

naturalize

naturalize(fig: Figure) -> None

Adjust graph aspect ratio into 'natural' ratio.

Source code in erosionfront/visualization/base.py
def naturalize(self, fig: Figure) -> None:
    """Adjust graph aspect ratio into 'natural' ratio."""
    axes: plt.Axes = fig.gca()
    # x_lim, y_lim = axes.get_xlim(), axes.get_ylim()
    # axes.set_aspect((y_lim[1]-y_lim[0])/(x_lim[1]-x_lim[0]))
    axes.set_aspect(1 / self.get_aspect(axes))

plot_3d

plot_3d(mesh: MultiBlock, geometry: Geometry, profiles: Profiles) -> Plotter

Display (possibly) interactive 3D view using PyVista

Parameters

mesh: MultiBlock X geometry: Geometry X profiles: Profiles X

Returns

Plotter: An instance of a PyVista 3D viewer.

Source code in erosionfront/visualization/topoviz.py
def plot_3d(
    self,
    mesh: MultiBlock, 
    geometry: Geometry,
    profiles: Profiles,
) -> Plotter:
    """
    Display (possibly) interactive 3D view using PyVista

    Parameters
    ----------
    mesh: MultiBlock
        X
    geometry: Geometry
        X
    profiles: Profiles
        X

    Returns
    -------
    Plotter:
        An instance of a PyVista 3D viewer.
    """
    pl = Plotter(window_size=(1024, 768,),) #, notebook=True
    grid: tuple[dict[float, MultiBlock]] = geometry.grid
    grid_colors: tuple[str,str] = ("k","k",) # ("coral","limegreen",)
    for lines_, color_ in zip(grid, grid_colors,):
        for step_, line_ in lines_.items():
            pl.add_mesh(
                line_, 
                show_edges=False, 
                color=color_, 
                line_width=2 if step_==0 else 1, 
                render_lines_as_tubes=False,
            )
    # Profile slices
    profiles: dict[Any: ProfileData] = profiles.data
    colors = list(mcolors.TABLEAU_COLORS.values())
    for color_, profile_ in zip(colors,profiles.values()):
        slice_ = profile_.slice
        pl.add_mesh(
            slice_, show_edges=False, color=color_, 
            line_width=5, render_lines_as_tubes=True,
        )
    # 3D DEM
    pl.add_mesh(mesh, show_edges=False, color="lightgray",)
    pl.show_axes()
    return pl

plot_front_segment

plot_front_segment(
    fig_name: str,
    sim: LevelSetSolver,
    z_range: tuple[float, float] = (0.1, 0.4),
    title_font_size: int = 11,
    fig_size: tuple[float, float] = (5, 5),
) -> None

Plot near-base cut of final time slice surface & regression fit.

Parameters

fig_name: str sim: LevelSetSolver z_range: tuple[float, float]=(0.1, 0.4,) title_font_size: int=12 fig_size: tuple[float, float]=(5, 5,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/simviz.py
def plot_front_segment(
        self,
        fig_name: str,
        sim: LevelSetSolver,
        z_range: tuple[float, float]=(0.1, 0.4,),
        title_font_size: int=11,
        fig_size: tuple[float, float]=(5, 5,),
    ) -> None:
    """
    Plot near-base cut of final time slice surface & regression fit.

    Parameters
    ----------
    fig_name: str
    sim: LevelSetSolver
    z_range: tuple[float, float]=(0.1, 0.4,)
    title_font_size: int=12
    fig_size: tuple[float, float]=(5, 5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(sim, "Front segment tilt", sim.gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel("x  [-]")
    plt.ylabel("z  [-]")
    xz_: NDArray  = sim.get_front_points(sim.φ)
    x_: NDArray = xz_[0]
    z_: NDArray  = xz_[1]
    z_min_: float = z_range[0]
    z_max_: float = z_range[1]
    z_ = xz_[1][(xz_[1]>=z_min_) & (xz_[1]<z_max_)]
    x_ = xz_[0][(xz_[1]>=z_min_) & (xz_[1]<z_max_)]
    if x_.shape[0]>0:
        plt.plot(x_,z_, )
        plt.grid(ls=":")
        axes = plt.gca()
        axes.set_aspect(1)
        fit = linregress(x_,z_)
        plt.plot(x_, fit.slope*x_ + fit.intercept, "r:",);
        label: str = (
            r"$\widehat{\beta}_{\mathrm{ramp}} = $"
            + f"{float(np.round(np.rad2deg(np.arctan(fit.slope)),1))}"
            + r"$\degree$"
        )
        plt.text(0.1, 0.9, label, transform=axes.transAxes,)

plot_initial_surface

plot_initial_surface(
    fig_name: str,
    initial_surface: (
        StraightLineSurface
        | ErrorFunctionSurface
        | SemiCircularArcSurface
        | QuarterCircularArcSurface
    ),
    gma: GeometricMechanicsAnalysis | None = None,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (7, 5),
) -> None

Plot initial surface x-z curve.

Parameters

fig_name: str initial_surface: ErrorFunctionSurface | StraightLineSurface title_font_size: int=12 fig_size: tuple[float, float]=(7, 5,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/simviz.py
def plot_initial_surface(
        self,
        fig_name: str,
        initial_surface: (
            StraightLineSurface 
            | ErrorFunctionSurface
            | SemiCircularArcSurface 
            | QuarterCircularArcSurface
        ),
        gma: GeometricMechanicsAnalysis | None=None,
        # model: Any | None,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(7, 5,),
    ) -> None:
    """
    Plot initial surface x-z curve.

    Parameters
    ----------
    fig_name: str
    initial_surface: ErrorFunctionSurface | StraightLineSurface
    title_font_size: int=12
    fig_size: tuple[float, float]=(7, 5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    title: str = "Initial surface"
    plt.title(
        title,
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$x$  [-]")
    plt.ylabel(r"$z$  [-]")
    if initial_surface.x is None or initial_surface.z is None:
        raise ValueError("Surface points not given")
    plt.plot(
        initial_surface.x, 
        initial_surface.z, 
        ".-", 
        ms=1, 
        lw=1.5, 
        alpha=1,
    )
    plt.xlim(initial_surface.x[0],initial_surface.x[-1])
    plt.grid(ls=":")
    axes = plt.gca()
    axes.set_aspect(1)

plot_model_Hamiltonian_grid

plot_model_Hamiltonian_grid(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (5, 6),
) -> None

Image Hamiltonian H and plot H=½ figuratrix on p_x, p_z grid.

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(5, 6,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_model_Hamiltonian_grid(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(5, 6,),
    ) -> None:
    """
    Image Hamiltonian H and plot H=1/2 figuratrix on p_x, p_z grid.

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(5, 6,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(
            model, 
            r"Hamiltonian  \mathcal{H}(p_x,p_z)",
            gma,
        ),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$p_x$")
    plt.ylabel(r"$p_z$")
    H_interp_grid_clipped: NDArray = np.clip(gma.H_interp_grid, 0, 1,)
    H_interp_grid_clipped[0,0] = 0  # force cbar range to include zero
    H_interp_grid_clipped[-1,-1] = 1  # force cbar range to include one
    extent_: tuple[float,float,float,float] = (*gma.px_span, *gma.pz_span)
    plt.imshow(
        (np.flipud(H_interp_grid_clipped.T)), 
        extent=extent_, 
        alpha=0.5,
        cmap="bwr_r",
    )
    ticks: tuple = (0, 0.5, 1,)
    grid_aspect_ratio: float = (
        H_interp_grid_clipped.T.shape[0]/H_interp_grid_clipped.T.shape[1]
    )
    shrink: float = (
        0.4 if grid_aspect_ratio>0.4
        else grid_aspect_ratio
    )        
    cbar: Colorbar = plt.colorbar(
        shrink=shrink, 
        pad=0.05, 
        aspect=10,
        ticks=ticks,
    )
    cbar.set_label(r"$\mathcal{H}$  [-]", size=12,)
    # cbar.ax.tick_params(labelsize=9)
    # plt.contour(
    #     model.H_interp_grid.T, 
    #     extent=extent_, 
    #     levels=[0.5],
    #     linewidths=[2],
    #     colors=["k"],
    #     linestyles=[":"],
    # )
    plt.plot(
        gma.px,
        gma.pz, 
        color="k", 
        lw=1,
        label=r"on-shell $\mathcal{H}=\frac{1}{2}$",
    )
    plt.legend(loc=(1.08, 0.8,))
    axes = plt.gca()
    axes.set_aspect(1)
    plt.grid(ls=":")

plot_model_Hamiltonian_onshell

plot_model_Hamiltonian_onshell(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (6, 2),
) -> None

Plot on-shell Hamiltonian H(β), which should be H=½ everywhere.

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float,float]=(6, 2,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/gmaviz.py
def plot_model_Hamiltonian_onshell(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float,float]=(6, 2,),
    ) -> None:
    """
    Plot on-shell Hamiltonian H(β), which should be H=1/2 everywhere.

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float,float]=(6, 2,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(
            model,
            r"Hamiltonian at erosion surface  \mathcal{H}(\beta)",
            gma,
        ),
        fontdict={"fontsize": title_font_size,},
    )
    plt.ylabel(r"$\mathcal{H}$  [-]")
    plt.xlabel(r"$\beta$  [$\degree$]")
    β: NDArray = np.linspace(-0.,np.pi/1,101)
    px: NDArray = np.array(gma.px_onshell(β))
    pz: NDArray = np.array(gma.pz_onshell(β))
    plt.plot(np.rad2deg(β), gma.Hamiltonian(px, pz))
    plt.ylim(0,1)
    plt.xlim(0,180)
    plt.grid(ls=":")

plot_model_detgstar_grid

plot_model_detgstar_grid(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (5, 6),
) -> None

Image |g_*| on p_x, p_z grid plus H=½ contour, critical β angles.

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(5, 6,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_model_detgstar_grid(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(5, 6,),
    ) -> None:
    """
    Image |g_*| on p_x, p_z grid plus H=1/2 contour, critical β angles.

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(5, 6,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    fig = self.create_figure(fig_name, fig_size=fig_size,)
    # plt.title(r"Determinant of dual metric tensor  $\det{g_*}$",
    plt.title(
        self.make_title(
            model, 
            r"Convexity \det{g_*} & figuratrix ||\mathbf{p}||_{g*}=1",
            gma,
        ), 
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$p_x$")
    plt.ylabel(r"$p_z$")
    extent_: tuple[float,float,float,float] = (*gma.px_span, *gma.pz_span)
    sf: float = 1/np.max(gma.det_gstar_grid)
    grid: NDArray = np.clip(gma.det_gstar_interp_grid*sf, -1,1)
    image = plt.imshow(
        (np.flipud(grid.T)), 
        extent=extent_, 
        alpha=0.5,
        cmap="bwr_r",
        norm=CenteredNorm(),
    )

    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
    β_mpx: float = 0 if gma.β_mpx is None else gma.β_mpx
    β_rs0: float = 0 if gma.β_rs0 is None else gma.β_rs0
    β_rs1: float = 0 if gma.β_rs1 is None else gma.β_rs1

    # plt.contour(det_gstar, extent=extent_, levels=[0])
    # plt.contour(H_interp_grid.T, extent=extent_, levels=[0.5])
    β: NDArray = gma.β
    plt.plot(
        gma.px[β<=β_c0],
        gma.pz[β<=β_c0], 
        color=self.props["cvx0_color"], 
        lw=1.5,
        label=r"$\mathcal{H}=\frac{1}{2}$  (convex)",
    )
    plt.plot(
        gma.px[(β>=β_c0) & (β<=β_c1)],
        gma.pz[(β>=β_c0) & (β<=β_c1)], 
        color=self.props["ccv_color"], 
        lw=1,
        label=r"$\mathcal{H}=\frac{1}{2}$  (concave)",
    )
    plt.plot(
        gma.px[β>=β_c1],
        gma.pz[β>=β_c1], 
        color=self.props["cvx1_color"], 
        lw=1,
        # label=r"$\mathcal{H}=\frac{1}{2}$",
    )

    x_: float
    y_: float
    color_: str
    marker_: str
    x_fn: Callable = gma.px_onshell
    y_fn: Callable = gma.pz_onshell
    for (x_, y_, color_, marker_, label_,)  in list(zip(
            (
                x_fn(β_rs1), 
                x_fn(β_mpx), 
                x_fn(β_c0), 
                x_fn(β_c1),
                x_fn(β_rs0), 
             ),
            (
                y_fn(β_rs1),
                y_fn(β_mpx),
                y_fn(β_c0),
                y_fn(β_c1),
                y_fn(β_rs0),
             ),
            (
                self.props["βrs1_color"], 
                self.props["βmpx_color"], 
                self.props["βc0_color"], 
                self.props["βc1_color"],
                self.props["βrs0_color"],
             ),
            (
                self.props["βrs1_marker"], 
                self.props["βmpx_marker"], 
                self.props["βc0_marker"], 
                self.props["βc1_marker"],
                self.props["βrs0_marker"],
             ),
            (
                r"transition $\beta_\mathrm{rs1} = $"
                    +rf"{np.rad2deg(β_rs1):3.1f}$\degree$",
                r"max $p_x$ @ $\beta_\mathrm{mpx} = $"
                    +rf"{np.rad2deg(β_mpx):3.1f}$\degree$",
                r"$\det{g_*}=0$  @  $\beta_{\mathrm{c0}} = $" 
                    + rf"{np.rad2deg(β_c0):3.1f}$\degree$",
                r"$\det{g_*}=0$  @  $\beta_{\mathrm{c1}} = $"
                    + rf"{np.rad2deg(β_c1):3.1f}$\degree$",
                r"transition $\beta_\mathrm{rs0} = $"
                    +rf"{np.rad2deg(β_rs0):3.1f}$\degree$",
             ),
        ))[::-1]:
        plt.scatter(
            x_, 
            y_,
            marker=marker_,
            color=color_,
            s=50 if marker_=="*" else 25,
            alpha=0.75 if marker_=="*" else 1,
            label=label_,
            zorder=10,
        )

    plt.legend(loc=(1.07,0.67), fontsize=9, borderpad=0.3,)

    axes = plt.gca()
    # axins = inset_axes(
    #     axes,
    #     width="7%",  # width: 5% of parent_bbox width
    #     height="40%",  # height: 50%
    #     loc="lower left",
    #     bbox_to_anchor=(550,-50,350,800),
    #     # bbox_to_anchor=(1,-0.2,1.5,1),
    #     # bbox_transform=axes.transAxes,
    #     borderpad=10,
    # )
    # fig.colorbar(image, cax=axins)
    grid_aspect_ratio: float = (
        grid.T.shape[0]/grid.T.shape[1]
    )
    shrink: float = (
        0.3 if grid_aspect_ratio>0.3
        else grid_aspect_ratio
    )     
    cbar: Colorbar = plt.colorbar(
        image,
        # cax=axins,
        shrink=shrink, 
        pad=0.05, 
        aspect=10,
        location="right",
    )
    cbar.set_label(
        r"modified $\det{g_*}$", 
        size=10,
    )
    cbar.ax.tick_params(labelsize=9)

    axes.set_aspect(1)
    plt.grid(ls=":")

plot_model_detgstar_onshell

plot_model_detgstar_onshell(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (6, 3),
) -> None

Plot |g_*| vs β colorized by convex or concave; also critical β values.

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(6, 3,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_model_detgstar_onshell(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(6, 3,),
    ) -> None:
    """
    Plot |g_*| vs β colorized by convex or concave; also critical β values.

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(6, 3,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(
            model, 
            r"Dual metric tensor determinant  "
        +r"\det{g_{*}(\beta)} \,\,|\,\, \mathcal{H}(\beta)=\frac{1}{2}",
            gma,
        ),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$\beta$  [$\degree$]")
    plt.ylabel(r"normalized  $\det{g_*}$")

    β: NDArray = gma.β
    pos_l: NDArray = np.s_[(β<gma.β_c0)]
    pos_r: NDArray = np.s_[(β>gma.β_c1)]
    # zero = np.s_[np.abs(det_gstar_onshell)<approx_zero]
    neg : NDArray= np.s_[(β>gma.β_c0) & (β<gma.β_c1)]
    sf: float = 1/np.max(gma.det_gstar_onshell)
    plt.plot(
        np.rad2deg(β[pos_l][3:]), 
        gma.det_gstar_onshell_interpfn(β[pos_l][3:])*sf,
        color=self.props["cvx0_color"],
        label=r"convex $\mathcal{H}$"
    )
    plt.plot(
        np.rad2deg(β[neg]), 
        gma.det_gstar_onshell_interpfn(β[neg])*sf,
        color=self.props["ccv_color"],
        label=r"concave $\mathcal{H}$"
    )
    plt.plot(
        np.rad2deg(β[pos_r][:-10]), 
        gma.det_gstar_onshell_interpfn(β[pos_r][:-10])*sf,
        color=self.props["cvx1_color"],
    )

    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
    β_mpx: float = 0 if gma.β_mpx is None else gma.β_mpx

    x_: float
    y_: float
    color_: str
    marker_: str
    label_: str
    x_fn: Callable = np.rad2deg
    y_fn: Callable = lambda y: gma.det_gstar_onshell_interpfn(y)*sf
    for (x_, y_, color_, marker_, label_,)  in zip(
            (x_fn(β_mpx), 
             x_fn(β_c0), 
             x_fn(β_c1),),
            (y_fn(β_mpx),
             y_fn(β_c0),
             y_fn(β_c1),),
            (self.props["βmpx_color"], 
             self.props["βc0_color"], 
             self.props["βc1_color"],),
            (self.props["βmpx_marker"], 
             self.props["βc0_marker"], 
             self.props["βc1_marker"],),
            (r"max $p_x$ @ $\beta_\mathrm{mpx}=$"
                +rf"{np.rad2deg(β_mpx):3.1f}$\degree$",
             r"$\det{g_*}=0$  @  $\beta_{\mathrm{c0}} = $" 
             + rf"{np.rad2deg(β_c0):3.1f}$\degree$",
             r"$\det{g_*}=0$  @  $\beta_{\mathrm{c1}} = $"
              + rf"{np.rad2deg(β_c1):3.1f}$\degree$",),
        ):
        plt.scatter(
            x_, 
            y_,
            marker=marker_,
            color=color_,
            s=50 if marker_=="*" else 25,
            alpha=0.75 if marker_=="*" else 1,
            label=label_,
            zorder=10,
        )

    plt.legend(fontsize=9)
    plt.grid(ls=":")

plot_model_erosion_speed

plot_model_erosion_speed(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis | None = None,
    do_polar: bool = False,
    title_font_size: int = 12,
    fig_size: tuple[float, float] | None = None,
) -> None

Plot surface-normal erosion speed model ξ(β).

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(6, 2.5,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/speedviz.py
def plot_model_erosion_speed(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis | None = None,
        do_polar: bool=False,
        title_font_size: int=12,
        fig_size: tuple[float, float] | None=None,
    ) -> None:
    """
    Plot surface-normal erosion speed model ξ(β).

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(6, 2.5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    def plot_markers(
            gma: GeometricMechanicsAnalysis,
            x_fn: Callable, 
            y_fn: Callable,
            do_reverse: bool=False,
        ) -> None:
        β_t: float = model.β_t
        β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
        β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
        β_mpx: float = 0 if gma.β_mpx is None else gma.β_mpx
        β_rs0: float = 0 if gma.β_rs0 is None else gma.β_rs0
        β_rs1: float = 0 if gma.β_rs1 is None else gma.β_rs1
        x_: float
        y_: float
        color_: str
        marker_: str
        label_: str
        nrv: bool = do_reverse
        label_βrs1: str = (
            r"$\beta_\mathrm{rs1} = $"
            + rf"{np.rad2deg(β_rs1):3.1f}$\degree$"
        )
        label_mpx: str = (
            r"$\beta_\mathrm{mpx} = $"
            + rf"{np.rad2deg(β_mpx):3.1f}$\degree$"

        )
        markers_: list = list(zip(
                (
                    x_fn(β_rs1 if nrv else β_mpx),
                    x_fn(β_mpx if nrv else β_rs1), 
                    x_fn(β_t), 
                    x_fn(β_c0), 
                    x_fn(β_c1),
                    x_fn(β_rs0),
                ),
                (
                    y_fn(β_rs1 if nrv else β_mpx),
                    y_fn(β_mpx if nrv else β_rs1),
                    y_fn(β_t),
                    y_fn(β_c0),
                    y_fn(β_c1),
                    y_fn(β_rs0),
                ),
                (
                    self.props[("βrs1_color" if nrv else "βmpx_color")],
                    self.props[("βmpx_color" if nrv else "βrs1_color")],
                    self.props["βt_color"],
                    self.props["βc0_color"],
                    self.props["βc1_color"],
                    self.props["βrs0_color"],
                ),
                (
                    self.props[("βrs1_marker" if nrv else "βmpx_marker")],
                    self.props[("βmpx_marker" if nrv else "βrs1_marker")],
                    self.props["βt_marker"],
                    self.props["βc0_marker"],
                    self.props["βc1_marker"],
                    self.props["βrs0_marker"],
                ),
                (
                    (label_βrs1 if nrv else label_mpx),
                    (label_mpx if nrv else label_βrs1),
                    r"$\beta_\mathrm{t} = $"
                        +rf"{np.rad2deg(β_t):3.1f}$\degree$",
                    r"$\beta_\mathrm{c0} = $"
                        +rf"{np.rad2deg(β_c0):3.1f}$\degree$",
                    r"$\beta_\mathrm{c1} = $"
                        +rf"{np.rad2deg(β_c1):3.1f}$\degree$",
                    r"$\beta_\mathrm{rs0} = $"
                        +rf"{np.rad2deg(β_rs0):3.1f}$\degree$",
                ),
            ))
        markers_ = markers_[::-1] if do_reverse else markers_
        for (x_, y_, color_, marker_, label_,)  in markers_:
            plt.scatter(
                x_, 
                y_,
                marker=marker_,
                color=color_,
                s=60 if marker_=="*" else 30,
                alpha=0.75 if marker_=="*" else 1,
                label=label_,
                zorder=10,
            )

    title: str
    beta: NDArray
    speed: NDArray
    x_fn: Callable
    y_fn: Callable
    if not do_polar:
        fig_size_ = fig_size if fig_size is not None else (6, 2.5,)
        self.create_figure(fig_name, fig_size=fig_size_,)
        plt.xlabel(r"$\beta$  $[\degree]$")
        plt.ylabel(r"$\xi^{\!\perp}(\beta)$  [-]")
        beta = np.linspace(-10,180,191)
        speed = np.array(model.ξ_fn_β(np.deg2rad(beta)))
        # print(speed)
        plt.plot(beta, speed, "k", zorder=-1,)
        plt.ylim(-0.05, np.max(speed)*1.05)
        plt.xlim(beta[0],beta[-1])
        x_fn = np.rad2deg
        y_fn = model.ξ_fn_β
        if gma is not None:
            plot_markers(gma, x_fn, y_fn,)
        plt.legend(fontsize=9, loc="upper left",)
    else:
        fig_size_ = fig_size if fig_size is not None else (6, 6,)
        self.create_figure(fig_name, fig_size=fig_size_,)
        beta = np.linspace(0,180,131)
        speed = np.array(model.ξ_fn_β(np.deg2rad(beta)))
        # DO THIS FIRST because otherwise polar axes may not be created
        # axes = fig.add_subplot(projection="polar")
        plt.polar(np.deg2rad(beta), speed, "k", zorder=-1,)
        axes = plt.gca()
        axes.set_thetalim(0, np.deg2rad(130)) #type: ignore
        ξ_max: float = float(model.ξ_fn_β((np.pi/2))*1.05)
        axes.set_ylim(0, ξ_max,) #
        plt.text(
            np.deg2rad(116), ξ_max*1.15, 
            r"$\beta$  $[\degree]$"
        )
        plt.text(
            -0.4, 0.43,
            r"$\xi^{\!\perp}(\beta)$  [-]"
        )
        x_fn = lambda x: x
        y_fn = model.ξ_fn_β
        if gma is not None:
            plot_markers(gma, x_fn, y_fn, do_reverse=True,)
        plt.legend(fontsize=9, loc=(-0.05,0.1,))
    title = r"Model erosion speed  \it{\xi^{\perp}(\beta)}"
    plt.title(
        self.make_title(model, title, gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.grid(ls=":")

plot_model_pdotv

plot_model_pdotv(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (6, 2.5),
) -> None

Plot p(v) aka p dot v vs β, which for conjugacy should be =1.

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(6, 2.5,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_model_pdotv(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(6, 2.5,),
    ) -> None:
    """
    Plot p(v) aka p dot v vs β, which for conjugacy should be =1.

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(6, 2.5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(
            model, 
            r"Conjugacy of slowness covector {p} "
                        + r"and ray velocity {v}",
            gma,
        ),
        fontdict={"fontsize": title_font_size,},
    )
    plt.ylabel(r"$\mathbf{p}\mathbf{\cdot}\mathbf{v}$  [-]")
    plt.xlabel(r"$\beta$  [$\degree$]")
    plt.plot(np.rad2deg(gma.β), gma.p_dot_v())
    # plt.legend(fontsize=10)
    plt.ylim(0,2)
    plt.xlim(0,180)
    plt.grid(ls=":")

plot_model_pxpz

plot_model_pxpz(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    n_pts: int = 301,
    do_pz: bool = False,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (6, 2.5),
) -> None

Plot erosion model slowness components p_x, p_z vs β.

Parameters

fig_name: str model: Any n_pts: int=301 do_pz: bool=False title_font_size: int=12 fig_size: tuple[float, float]=(6, 2.5,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_model_pxpz(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        n_pts: int=301,
        do_pz: bool=False,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(6, 2.5,),
    ) -> None:
    """
    Plot erosion model slowness components p_x, p_z vs β.

    Parameters
    ----------
    fig_name: str
    model: Any
    n_pts: int=301
    do_pz: bool=False
    title_font_size: int=12
    fig_size: tuple[float, float]=(6, 2.5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    p_component: str = (
        r"p_z" if do_pz else r"p_x"
    )
    plt.title(
        self.make_title(
            model, f"Normal slowness component  {p_component}", gma,
        ),
        fontdict={"fontsize": title_font_size,},
    )
    y_label: str = (
        r"$p_z$  [-]" if do_pz else r"$p_x$  [-]"
    )
    plt.ylabel(y_label)
    plt.xlabel(r"$\beta$  [$\degree$]")
    x_fn: Callable = np.rad2deg
    y_fn: Callable[[float | NDArray], float | NDArray] = (
        gma.pz_onshell if do_pz
        else gma.px_onshell
    )

    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
    β_mpx: float = 0 if gma.β_mpx is None else gma.β_mpx
    β_rs0: float = 0 if gma.β_rs0 is None else gma.β_rs0
    β_rs1: float = 0 if gma.β_rs1 is None else gma.β_rs1

    # Plot main curve as three different-color segments
    β: NDArray = np.linspace(0, np.pi, n_pts, endpoint=True,)
    plt.plot(
        x_fn(β[β<=β_c0]), 
        y_fn(β[β<=β_c0]),
        self.props["cvx0_color"], 
        lw=1.5,
    )
    plt.plot(
        x_fn(β[(β>=β_c0) & (β<=β_c1)]), 
        y_fn(β[(β>=β_c0) & (β<=β_c1)]), 
        self.props["ccv_color"], 
        lw=1.5,
    )
    plt.plot(
        x_fn(β[β>β_c1]), 
        y_fn(β[β>β_c1]), 
        self.props["cvx1_color"], 
        lw=1.5,
    )

    x_: float | NDArray
    y_: float | NDArray
    color_: str
    marker_: str
    for (x_, y_, color_, marker_, label_,)  in list(zip(
            (
                x_fn(β_rs1), 
                x_fn(β_mpx), 
                x_fn(β_c0), 
                x_fn(β_c1), 
                x_fn(β_rs0),
             ),
            (
                y_fn(β_rs1),
                y_fn(β_mpx),
                y_fn(β_c0),
                y_fn(β_c1),
                y_fn(β_rs0),
             ),
            (
                self.props["βrs1_color"], 
                self.props["βmpx_color"], 
                self.props["βc0_color"], 
                self.props["βc1_color"], 
                self.props["βrs0_color"],
             ),
            (
                self.props["βrs1_marker"], 
                self.props["βmpx_marker"], 
                self.props["βc0_marker"], 
                self.props["βc1_marker"], 
                self.props["βrs0_marker"],
             ),
            (
                r"transition $\beta_\mathrm{rs1} = $"
                    +rf"{np.rad2deg(β_rs1):3.1f}$\degree$",
                r"max $p_x$ @ $\beta_\mathrm{mpx} = $"
                    +rf"{np.rad2deg(β_mpx):3.1f}$\degree$",
                r"$\det{g_*}=0$  @  $\beta_{\mathrm{c0}} = $" 
                    + rf"{np.rad2deg(β_c0):3.1f}$\degree$",
                r"$\det{g_*}=0$  @  $\beta_{\mathrm{c1}} = $"
                    + rf"{np.rad2deg(β_c1):3.1f}$\degree$",
                r"transition $\beta_\mathrm{rs0} = $"
                    +rf"{np.rad2deg(β_rs0):3.1f}$\degree$",
              ),
        ))[::-1]:
        plt.scatter(
            x_, 
            y_,
            marker=marker_,
            color=color_,
            s=50 if marker_=="*" else 25,
            alpha=0.75 if marker_=="*" else 1,
            label=label_,
            zorder=10,
        )

    plt.legend(fontsize=8,)
    plt.grid(ls=":")
    plt.xlim(0,180)

plot_model_α_β

plot_model_α_β(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (5, 5),
) -> None

Plot ray angle α(β) annotated by critical angles, concave/convex colors.

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(5, 5,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_model_α_β(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(5, 5,),
    ) -> None:
    """
    Plot ray angle α(β) annotated by critical angles, concave/convex colors.

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(5, 5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(
            model, 
            r"Ray angle \alpha versus slope angle \beta",
            gma,
        ),
        fontdict={"fontsize": title_font_size,},
    )
    plt.ylabel(r"$\alpha$  [$\degree$]")
    plt.xlabel(r"$\beta$  [$\degree$]")

    β: NDArray = gma.β
    α: NDArray = gma.α_onshell_interpfn(β)
    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
    beta: NDArray = np.rad2deg(β)
    alpha: NDArray = np.rad2deg(α)
    plt.plot(beta[β<β_c0], alpha[β<β_c0], self.props["cvx0_color"], lw=1.5,)
    plt.plot(
        beta[(β>=β_c0) & (β<=β_c1)], 
        α[(β>=β_c0) & (β<=β_c1)], 
        self.props["ccv_color"], lw=1.5,
    )
    plt.plot(beta[β>β_c1], α[β>β_c1], self.props["cvx1_color"], lw=1.5,)

    β_mpx: float = 0 if gma.β_mpx is None else gma.β_mpx
    x_: float
    y_: float
    color_: str
    marker_: str
    label_: str
    x_fn: Callable = np.rad2deg
    y_fn: Callable = lambda y: np.rad2deg(gma.α_onshell_interpfn(y))
    for (x_, y_, color_, marker_, label_,)  in zip(
            (x_fn(β_mpx), 
             x_fn(β_c0), 
             x_fn(β_c1),),
            (y_fn(β_mpx),
             y_fn(β_c0),
             y_fn(β_c1),),
            (self.props["βmpx_color"], 
             self.props["βc0_color"], 
             self.props["βc1_color"],),
            (self.props["βmpx_marker"], 
             self.props["βc0_marker"], 
             self.props["βc1_marker"],),
            (r"max $p_x$ @ $\beta_\mathrm{mpx} = $"
                +rf"{np.rad2deg(β_mpx):3.1f}$\degree$",
             r"$\det{g_*}=0$  @  $\beta_{\mathrm{c0}} = $" 
             + rf"{np.rad2deg(β_c0):3.1f}$\degree$",
             r"$\det{g_*}=0$  @  $\beta_{\mathrm{c1}} = $"
              + rf"{np.rad2deg(β_c1):3.1f}$\degree$",),
        ):
        plt.scatter(
            x_, 
            y_,
            marker=marker_,
            color=color_,
            s=50 if marker_=="*" else 25,
            alpha=0.75 if marker_=="*" else 1,
            label=label_,
            zorder=10,
        )

    axes = plt.gca()
    axes.set_aspect(1)
    plt.legend(loc="lower right", fontsize=9,)
    plt.grid(ls=":")

plot_profiles

plot_profiles(
    fig_name: str,
    profiles: Profiles,
    choices: tuple[str, ...] | None,
    marker_size: float | None,
    line_width: float | None,
    xlim: tuple[float, float] | None = None,
    ylim: tuple[float, float] | None = None,
    scale: float = 1,
    do_equal: bool = True,
    do_normals: bool = False,
    vector_sf: float = 1,
    θ_clip: tuple[float, float] = (0, 90),
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (7, 5),
) -> None

X

Parameters

fig_name: str Name used as key in figure dictionary. profiles: dict[Any: Profile] X choices: tuple[str,...] | None X marker_size: float | None X line_width: float | None X xlim: tuple[float,float] | None = None X ylim: tuple[float,float] | None = None X scale: float=1 X do_equal: bool=True X

use_normals: bool=False

X

do_normals: bool=False X vector_sf: float=1 X

do_flip_orientation: bool=False

X

θ_clip: tuple[float,float]=(0,90,) X title_font_size: int=12 Size of title text. fig_size: tuple[float, float]=(7, 5,) Figure size (in inches!).

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/topoviz.py
def plot_profiles(
    self,
    fig_name: str,
    profiles: Profiles,
    choices: tuple[str,...] | None,
    marker_size: float | None,
    line_width: float | None,
    xlim: tuple[float,float] | None = None,
    ylim: tuple[float,float] | None = None,
    scale: float=1,
    do_equal: bool=True,
    # use_normals: bool=False,
    do_normals: bool=False,
    vector_sf: float=1,
    # do_flip_orientation: bool=False,
    θ_clip: tuple[float,float]=(0,90,),
    title_font_size: int=12,
    fig_size: tuple[float, float]=(7, 5,),
) -> None:
    """
    X

    Parameters
    ----------
    fig_name: str
        Name used as key in figure dictionary.
    profiles: dict[Any: Profile]
        X
    choices: tuple[str,...] | None
        X
    marker_size: float | None
        X
    line_width: float | None
        X
    xlim: tuple[float,float] | None = None
        X
    ylim: tuple[float,float] | None = None
        X
    scale: float=1
        X
    do_equal: bool=True
        X
    # use_normals: bool=False
        X
    do_normals: bool=False
        X
    vector_sf: float=1
        X
    # do_flip_orientation: bool=False
        X
    θ_clip: tuple[float,float]=(0,90,)
        X
    title_font_size: int=12
        Size of title text.
    fig_size: tuple[float, float]=(7, 5,)
        Figure size (in inches!).

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=np.array(fig_size)*scale,)
    # title: str = ""
    # plt.title(
    #     title,
    #     fontdict={"fontsize": title_font_size,},
    # )
    profiles: dict[Any: ProfileData] = profiles.data
    colors = list(mcolors.TABLEAU_COLORS.values())
    for j_, profile_ in enumerate(profiles.values()):
        if choices is not None and profile_.name not in choices:
            continue
        chords_ = profile_.chords
        ψ_deg = profile_.orientation
        mid_points_ = profile_.mid_points
        parallels_ = profile_.parallels
        normals_ = profile_.normals
        tilts_ = profile_.tilts
        tilts_r_ = profile_.tilts_r
        for (i_, 
             (chord_, mid_point_, parallel_, normal_, tilt_, tilt_r_,),) \
            in enumerate(zip(
                chords_, mid_points_,parallels_,normals_,tilts_,tilts_r_
            ),):
            # Don't bother plotting chords whose endpts lie beyond the 
            # limits
            if xlim is not None:
                if chord_[0][0]<xlim[0] or chord_[0][1]>xlim[1]:
                    continue
            plt.plot(
                *chord_, 
                ("." if marker_size is not None else "") 
                    + ("-" if line_width is not None else ""),
                color=colors[j_] if not do_normals else "Gray",
                ms=marker_size,
                lw=line_width,
                label=rf"$\psi=${ψ_deg}$\degree$" if i_==0 else None,
            )
            if do_normals:
                normal_ #if use_normals else parallel_
                is_in_bounds = lambda tilt: \
                    ((tilt>=θ_clip[0] and tilt<=θ_clip[1]) 
                        or (-tilt>=θ_clip[0] and -tilt<=θ_clip[1])) 
                if tilt_ is not None and is_in_bounds(tilt_):
                    plt.plot(
                        (mid_point_[0], 
                         mid_point_[0]+normal_[0]*vector_sf,), 
                        (mid_point_[1], 
                         mid_point_[1]+normal_[1]*vector_sf,), 
                        "-",
                        color="k" if tilt_>0 else "b",
                        lw=0.5,
                    )
                elif tilt_r_ is not None and is_in_bounds(tilt_r_):
                    plt.plot(
                        (mid_point_[0], 
                         mid_point_[0]+normal_[0]*vector_sf,), 
                        (mid_point_[1], 
                         mid_point_[1]+normal_[1]*vector_sf,), 
                        "-",
                        color="g" if tilt_r_>0 else "r",
                        lw=0.5,
                    )
    plt.xlabel("Distance along profile  [m]")
    plt.ylabel(r"Elevation $z$  [m]")
    plt.grid(ls=":",)
    plt.legend()
    axes = plt.gca()
    if do_equal:
        axes.set_aspect("equal")
    if xlim is not None:
        plt.xlim(*xlim)
    if ylim is not None:
        plt.ylim(*ylim)

plot_ray_velocity

plot_ray_velocity(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (5, 5),
) -> None

Plot ray velocity indicatrix, plus convex/concave colors, critical βs.

Parameters

fig_name: str, model: Any, title_font_size: int=12, fig_size: tuple[float, float]=(5, 5,),

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_ray_velocity(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(5, 5,),
    ) -> None:
    """
    Plot ray velocity indicatrix, plus convex/concave colors, critical βs.

    Parameters
    ----------
    fig_name: str,
    model: Any,
    title_font_size: int=12,
    fig_size: tuple[float, float]=(5, 5,),

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(model, r"Ray velocity  v", gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$v^x$  [-]")
    plt.ylabel(r"$v^z$  [-]")

    β: NDArray = gma.β[gma.dHdpz_onshell<1.3]
    vx = gma.dHdpx_onshell[gma.dHdpz_onshell<1.3]
    vz = gma.dHdpz_onshell[gma.dHdpz_onshell<1.3]
    vx_max = np.max(vx)*1.1

    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
    β_mpx: float = 0 if gma.β_mpx is None else gma.β_mpx
    β_rs0: float = 0 if gma.β_rs0 is None else gma.β_rs0
    β_rs1: float = 0 if gma.β_rs1 is None else gma.β_rs1
    α_c0: float = 0 if gma.α_c0 is None else gma.α_c0
    α_c1: float = 0 if gma.α_c1 is None else gma.α_c1
    α_rs0: float = 0 if gma.α_rs0 is None else gma.α_rs0
    α_rs1: float = 0 if gma.α_rs1 is None else gma.α_rs1

    # plt.plot(
    #     vx, vz, self.props["cvx0_color"], lw=0.5,
    # )
    plt.plot(
        vx[β<=β_c0], vz[β<=β_c0], self.props["cvx0_color"], lw=2,
    )
    plt.plot(
        vx[(β>=β_c0) & (β<=β_c1)], vz[(β>=β_c0) & (β<=β_c1)], 
        self.props["ccv_color"], lw=1.5,
    )
    plt.plot(
        vx[β>=β_c1], vz[β>=β_c1], self.props["cvx1_color"], lw=1.5,
    )
    axes = plt.gca()
    axes.set_aspect(1)
    plt.grid(ls=":")

    if model.type=="ISO":
        return

    # plt.plot(
    #     (0,vx_max),
    #     (0,vx_max*np.tan(α_mpx)), 
    #     ":",
    #     lw=1,
    #     color=self.props["βmpx_color"],
    #     label=(
    #         r"$\beta_{\mathrm{mpx}}$" 
    #         + rf"$={np.rad2deg(β_mpx):3.1f}\degree$, "
    #         + r"$\alpha_{\mathrm{mpx}}$"
    #         + rf"$={np.rad2deg(α_mpx):3.1f}\degree$"
    #     ),
    # )
    plt.plot(
        (0,vx_max),
        (0,vx_max*np.tan(α_rs0)), 
        "-",
        lw=3,
        alpha=0.2,
        color=self.props["βrs0_color"],
        label=(
            r"$\beta_{\mathrm{rs0}}$" 
            + rf"$={np.rad2deg(β_rs0):3.1f}\degree$, "
            + r"$\alpha_{\mathrm{rs0}}$"
            + rf"$={np.rad2deg(α_rs0):3.1f}\degree$"
        ),
    )
    plt.plot(
        (0,vx_max),
        (0,vx_max*np.tan(α_c0)),
        "--",
        lw=1,
        color=self.props["βc0_color"],
        label=(
            r"$\beta_{\mathrm{c0}}$" 
            + rf"$={np.rad2deg(β_c0):3.1f}\degree$, "
            + r"$\alpha_{\mathrm{c0}}$"
            + rf"$={np.rad2deg(α_c0):3.1f}\degree$"
        ),
    )
    plt.plot(
        (0,vx_max),
        (0,vx_max*np.tan(α_c1)), 
        "--",
        lw=1,
        color=self.props["βc1_color"],
        label=(
            r"$\beta_{\mathrm{c1}}$" 
            + rf"$={np.rad2deg(β_c1):3.1f}\degree$, "
            + r"$\alpha_{\mathrm{c1}}$"
            + rf"$={np.rad2deg(α_c1):3.1f}\degree$"
            # + r",  $\beta_{\mathrm{rs}}$"
            # + rf"$= {np.rad2deg(model.β_rs1):3.1f}\degree$"
        ),
    )
    plt.plot(
        (0,vx_max),
        (0,vx_max*np.tan(α_rs1)), 
        "-",
        lw=3,
        alpha=0.4,
        color=self.props["βrs1_color"],
        label=(
            r"$\beta_{\mathrm{rs1}}$" 
            + rf"$={np.rad2deg(β_rs1):3.1f}\degree$, "
            + r"$\alpha_{\mathrm{rs1}}$"
            + rf"$={np.rad2deg(α_rs1):3.1f}\degree$"
        ),
    )

    x_: float
    y_: float
    color_: str
    marker_: str
    label_: str
    x_fn: Callable = gma.dHdpx_onshell_interpfn
    y_fn: Callable = gma.dHdpz_onshell_interpfn
    for (x_, y_, color_, marker_, label_,)  in zip(
            (
                x_fn(β_rs0),
                x_fn(β_c0), 
                x_fn(β_c1),
                x_fn(β_rs1),
                x_fn(β_mpx), 
             ),
            (
                y_fn(β_rs0),
                y_fn(β_c0),
                y_fn(β_c1),
                y_fn(β_rs1),
                y_fn(β_mpx),
             ),
            (
                self.props["βrs0_color"],
                self.props["βc0_color"],
                self.props["βc1_color"],
                self.props["βrs1_color"],
                self.props["βmpx_color"],
             ),
            (
                self.props["βrs0_marker"],
                self.props["βc0_marker"],
                self.props["βc1_marker"],
                self.props["βrs1_marker"],
                self.props["βmpx_marker"],
             ),
            (
                r"transition $\beta_\mathrm{rs0} = $"
                    +rf"{np.rad2deg(β_rs0):3.1f}$\degree$",
                r"$\det{g_*}=0$  @  $\beta_{\mathrm{c0}} = $" 
                    + rf"{np.rad2deg(β_c0):3.1f}$\degree$",
                r"$\det{g_*}=0$  @  $\beta_{\mathrm{c1}} = $"
                    + rf"{np.rad2deg(β_c1):3.1f}$\degree$",
                r"transition $\beta_\mathrm{rs1} = $"
                    +rf"{np.rad2deg(β_rs1):3.1f}$\degree$",
                r"max $p_x$ @ $\beta_\mathrm{mpx} = $"
                    +rf"{np.rad2deg(β_mpx):3.1f}$\degree$",
            ),
        ):
        # Switched to axes.plot from plt.scatter in hope we can overlay
        #   two plots and have separate legends for markers & lines
        plt.scatter(
            x_, 
            y_,
            marker=marker_,
            color=color_,
            s=50*2 if marker_=="*" else 25*2,
            alpha=0.75 if marker_=="*" else 1,
            label=label_,
            zorder=10,
        )

    plt.legend(loc=(1.03,0.3,), fontsize=9,)

plot_retreat_speed

plot_retreat_speed(
    fig_name: str,
    sim: LevelSetSolver,
    z_levels: tuple = (0.8, 0.4, 0.2),
    z_limits: tuple[float, float] = (0.8, 3),
    title_font_size: int = 11,
    fig_size: tuple[float, float] = (7, 3),
) -> Sequence

Plot estimated horizontal retreat speed vs time T.

Parameters

fig_name: str sim: LevelSetSolver z_levels: tuple=(0.8, 0.4, 0.2,) z_limits: tuple[float, float]=(0.8, 3,) title_font_size: int=12 fig_size: tuple[float, float]=(7, 3,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/simviz.py
def plot_retreat_speed(
        self,
        fig_name: str,
        sim: LevelSetSolver,
        z_levels: tuple=(0.8, 0.4, 0.2,),
        z_limits: tuple[float, float]=(0.8, 3,),
        title_font_size: int=11,
        fig_size: tuple[float, float]=(7, 3,),
    ) -> Sequence:
    """
    Plot estimated horizontal retreat speed vs time T.

    Parameters
    ----------
    fig_name: str
    sim: LevelSetSolver
    z_levels: tuple=(0.8, 0.4, 0.2,)
    z_limits: tuple[float, float]=(0.8, 3,)
    title_font_size: int=12
    fig_size: tuple[float, float]=(7, 3,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    title: str = (
        r"Horizontal retreat speed  \xi_{\mathrm{h}}" 
            # +r"  =(\partial{T}/\partial{x})^{-1}"
    )
    plt.title(
        self.make_title(sim, title, sim.gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.ylabel(r"Horizontal speed  $\xi_\mathrm{h}$")
    plt.xlabel(r"Arrival time  $T$")
    time_: NDArray
    speed_: NDArray
    for z_level_ in z_levels:
        t_  = np.array([
            ts_["T"]
            for ts_ in sim.T_slices.values() if np.any(ts_["z"]>z_level_)
        ])
        x_  = np.array([
            ts_["x"][ts_["z"]>=z_level_][0] 
            for ts_ in sim.T_slices.values() if np.any(ts_["z"]>z_level_)
        ])
        # z_  = np.array([
        #     ts_["x"][ts_["z"]>=z_level_][0] 
        #     for ts_ in sim.T_slices.values() if np.any(ts_["z"]>z_level_)
        # ])
        time_ = (t_[1:]+t_[:-1])/2
        speed_ = gaussian_filter((x_[1:]-x_[:-1])/(t_[1:]-t_[:-1]), 10,)
        plt.plot(time_, speed_, "-", label=rf"$z=${z_level_}",)
    plt.xlim(0, sim.t_total)
    plt.ylim(*z_limits)
    plt.grid(ls=":")
    plt.legend(fontsize=10, loc=(1.02, 0.3,),)
    return (z_level_, float(speed_[-1]),)

plot_semicircle_rays

plot_semicircle_rays(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    x_max: float = 2.5,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (7, 5),
) -> None

Plot ray velocity indicatrix, plus convex/concave colors, critical βs.

Parameters

fig_name: str, model: Any, title_font_size: int=12, fig_size: tuple[float, float]=(5, 5,),

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_semicircle_rays(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        x_max: float=2.5,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(7, 5,),
    ) -> None:
    """
    Plot ray velocity indicatrix, plus convex/concave colors, critical βs.

    Parameters
    ----------
    fig_name: str,
    model: Any,
    title_font_size: int=12,
    fig_size: tuple[float, float]=(5, 5,),

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(model, r"Semicircle propagation", gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$x$  [-]")
    plt.ylabel(r"$z$  [-]")

    β: NDArray = gma.β
    vx: NDArray = gma.dHdpx_onshell
    vz: NDArray = gma.dHdpz_onshell

    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_c1: float = 0 if gma.β_c1 is None else gma.β_c1
    β_rs1: float = 0 if gma.β_rs1 is None else gma.β_rs1
    α_c0: float = 0 if gma.α_c0 is None else gma.α_c0

    β_: NDArray
    for sf_ in np.linspace(0, 3, 31, endpoint=True,):
        β_ = β[β<β_c0]
        plt.plot(
            np.sin(β_) + vx[β<β_c0]*sf_, 
            1 -np.cos(β_) + vz[β<β_c0]*sf_, 
            # self.props["cvx0_color"], 
            color="k",
            lw=0.5,
        )
        β_ = β[(β>=β_c0) & (β<=β_c1)]
        plt.plot(
            np.sin(β_) + vx[(β>=β_c0) & (β<=β_c1)]*sf_, 
            1 -np.cos(β_) + vz[(β>=β_c0) & (β<=β_c1)]*sf_, 
            "-",
            color="r",
            # self.props["ccv_color"], 
            lw=1,
        )
        # β_ = β[β>β_c1]
        # plt.plot(
        #     np.sin(β_) + vx[β>β_c1]*sf_, 
        #     -np.cos(β_) + vz[β>β_c1]*sf_, 
        #     self.props["cvx1_color"], 
        #     lw=1,
        # )
    β_ = β[β<β_c0][-1]
    vx_ = vx[β<β_c0][-1]
    vz_ = vz[β<β_c0][-1]
    sf_ = np.linspace(0, 3, 101, endpoint=True,)
    plt.plot(
        np.sin(β_) + vx_*sf_, 
        1 -np.cos(β_) + vz_*sf_, 
        lw=3,
        alpha=0.2,
        color=self.props["βrs0_color"],
    )
    vx_fn: Callable = gma.dHdpx_onshell_interpfn
    vz_fn: Callable = gma.dHdpz_onshell_interpfn
    plt.plot(
        np.sin(β_c0) + vx_fn(β_c0)*sf_, 
        1 -np.cos(β_c0) + vz_fn(β_c0)*sf_, 
        "--",
        lw=1,
        color=self.props["βc0_color"],
        label=(
            r"$\beta_{\mathrm{c0}}$" 
            + rf"$={np.rad2deg(β_c0):3.1f}\degree$, "
            + r"$\alpha_{\mathrm{c0}}$"
            + rf"$={np.rad2deg(α_c0):3.1f}\degree$"
        ),
    )
    plt.plot(
        np.sin(β_rs1) + vx_fn(β_rs1)*sf_, 
        1 -np.cos(β_rs1) + vz_fn(β_rs1)*sf_, 
        lw=3,
        alpha=0.5,
        color=self.props["βrs1_color"],
        label=(
            r"$\beta_{\mathrm{rs1}}$" 
            + rf"$={np.rad2deg(β_rs1):3.1f}\degree$, "
            + r"$\alpha_{\mathrm{rs1}}$"
            + rf"$={np.rad2deg(β_rs1):3.1f}\degree$"
        ),
    )
    axes = plt.gca()
    axes.set_aspect(1)
    plt.grid(ls=":")
    plt.ylim(0, 1)
    plt.xlim(0, x_max,)
    plt.legend(fontsize=9, loc="upper left",)

plot_shocks

plot_shocks(
    fig_name: str,
    sim: LevelSetSolver,
    title_font_size: int = 11,
    fig_size: tuple[float, float] = (6, 6),
) -> None

Plot near-base cut of final time slice surface & regression fit.

Parameters

fig_name: str sim: LevelSetSolver z_range: tuple[float, float]=(0.1, 0.4,) title_font_size: int=12 fig_size: tuple[float, float]=(5, 5,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/simviz.py
def plot_shocks(
        self,
        fig_name: str,
        sim: LevelSetSolver,
        title_font_size: int=11,
        fig_size: tuple[float, float]=(6,6,),
    ) -> None:
    """
    Plot near-base cut of final time slice surface & regression fit.

    Parameters
    ----------
    fig_name: str
    sim: LevelSetSolver
    z_range: tuple[float, float]=(0.1, 0.4,)
    title_font_size: int=12
    fig_size: tuple[float, float]=(5, 5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(sim, "Shock progression", sim.gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.plot(
        *sim.shocks_xz, ".", 
        label="breaks in slope",
        zorder=10,
    )
    plt.xlabel("x  [-]")
    plt.ylabel("z  [-]")
    if (
        sim.gma is not None 
        and sim.gma.α_c0 is not None 
        and sim.gma.α_rs0 is not None
    ):
        angle: float = sim.gma.α_c0
        x = np.linspace(0, np.max(sim.shocks_xz[0]), 101,)
        y = x * np.tan((angle)) + 0.0
        alpha_rs0: float = np.rad2deg(sim.gma.α_rs0)
        plt.plot(
            x, y, 
            "-", 
            label=r"$\alpha_{rs0} =$"+rf"{alpha_rs0:0.2f}$\degree$",
        )
    axes = plt.gca()
    axes.set_aspect(1)
    plt.legend()
    plt.grid(ls=":",)

plot_slopes

plot_slopes(
    fig_name: str,
    profiles: Profiles,
    choices: tuple[str, ...] | None,
    w_filter: int = 15,
    scale: float = 1,
    line_width: float = 1,
    do_points: bool = False,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (6, 3.5),
) -> None

X

Parameters

fig_name: str Name used as key in figure dictionary. profiles: Profiles X choices: tuple[str,...] | None X w_filter: int=15 X scale: float=1 X line_width: float=1 X do_points: bool=False X title_font_size: int=12 Size of title text. fig_size: tuple[float, float]=(7, 5,) Figure size (in inches!).

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/topoviz.py
def plot_slopes(
    self,
    fig_name: str,
    profiles: Profiles,
    choices: tuple[str,...] | None,
    w_filter: int=15,
    scale: float=1,
    line_width: float=1,
    do_points: bool=False,
    title_font_size: int=12,
    fig_size: tuple[float,float]=(6,3.5,),
) -> None:
    """
    X

    Parameters
    ----------
    fig_name: str
        Name used as key in figure dictionary.
    profiles: Profiles
        X
    choices: tuple[str,...] | None
        X
    w_filter: int=15
        X
    scale: float=1
        X
    line_width: float=1
        X
    do_points: bool=False
        X
    title_font_size: int=12
        Size of title text.
    fig_size: tuple[float, float]=(7, 5,)
        Figure size (in inches!).

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=np.array(fig_size)*scale,)
    # title: str = ""
    # plt.title(
    #     title,
    #     fontdict={"fontsize": title_font_size,},
    # )
    profiles: dict[Any: ProfileData] = profiles.data
    colors = list(mcolors.TABLEAU_COLORS.values())
    for j_, profile_ in enumerate(profiles.values()):
        if choices is not None and profile_.name not in choices:
            continue
        xg_ = np.array([
            ( 
                (chord_[0][1]+chord_[0][0])/2, 
                np.rad2deg(np.atan2( 
                    (chord_[1][1]-chord_[1][0]), 
                    (chord_[0][1]-chord_[0][0]) 
                ))
            )
            for chord_ in profile_.chords   
        ])
        xgs_ = np.array(sorted(xg_, key=lambda x: x[0]))
        xgf_ = medfilt(xgs_[:,1], w_filter,)
        ψ_deg = profile_.orientation
        plt.plot(
            xgs_[:,0], xgf_, 
            "." if do_points else "-", 
            ms=3, 
            lw=line_width,
            color=colors[j_],
            label=rf"$\psi=${ψ_deg}$\degree$",
        )
    plt.xlabel("Distance along profile  [m]")
    plt.ylabel(r"Slope angle  [$\degree$]")
    axes = plt.gca()
    # axes.set_aspect("equal")
    plt.yticks(np.arange(-90,+90+15,15))
    plt.grid(ls=":",)
    plt.legend()

plot_threshold_ray_angle

plot_threshold_ray_angle(
    fig_name: str,
    model: Isotropic | Step | ExponentialActivation,
    gma: GeometricMechanicsAnalysis,
    title_font_size: int = 12,
    fig_size: tuple[float, float] = (4, 5),
) -> None

Plot β(α-α_c1) and the critical slope angle β_rs1(α_rs1).

Parameters

fig_name: str model: Any title_font_size: int=12 fig_size: tuple[float, float]=(4, 5,)

Attributes

Uses create_figure (adds to fig dict), props.

Source code in erosionfront/visualization/gmaviz.py
def plot_threshold_ray_angle(
        self,
        fig_name: str,
        model: Isotropic | Step | ExponentialActivation,
        gma: GeometricMechanicsAnalysis,
        title_font_size: int=12,
        fig_size: tuple[float, float]=(4, 5,),
    ) -> None:
    """
    Plot β(α-α_c1) and the critical slope angle β_rs1(α_rs1).

    Parameters
    ----------
    fig_name: str
    model: Any
    title_font_size: int=12
    fig_size: tuple[float, float]=(4, 5,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict), props.
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(model, "Threshold ray angle \\alpha", gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$\alpha - \alpha_{\mathrm{c1}}$  [$\degree$]")
    plt.ylabel(r"$\beta$  [$\degree$]")

    β_c0: float = 0 if gma.β_c0 is None else gma.β_c0
    β_rs1: float = 0 if gma.β_rs1 is None else gma.β_rs1
    α_rs1: float = 0 if gma.α_rs1 is None else gma.α_rs1
    α_c1: float = 0 if gma.α_c1 is None else gma.α_c1

    β = gma.β
    plt.scatter(
        np.rad2deg(α_rs1-α_c1), 
        np.rad2deg(β_rs1), 
        color = self.props["βrs1_color"], 
        marker = self.props["βrs1_marker"], 
        label = (
            r"$\beta_{\mathrm{rs1}}$"
            + rf"$= {np.rad2deg(β_rs1):3.1f}\degree$,  "
            + r"$\alpha_{\mathrm{rs1}} = \alpha_{\mathrm{c1}} $"
            + rf"$= {np.rad2deg(α_rs1):3.1f}\degree$"
        ),
        zorder=10,
    )
    plt.plot(
        np.rad2deg(gma.α_onshell_interpfn(β[β<β_c0])-α_c1),
        np.rad2deg(β[β<β_c0]), 
    )
    plt.legend()
    plt.grid(ls=":")

plot_time_slices

plot_time_slices(
    fig_name: str,
    sim: LevelSetSolver,
    x_limits: tuple[float | None, float | None] | None = None,
    z_min: float | None = -0.05,
    z_max: float | None = 1.05,
    pc_slicing: float = 10,
    pc_labeling: float = 20,
    title_font_size: int = 11,
    legend_font_size: int = 9,
    fig_size: tuple[float, float] = (7, 5),
) -> None

Plot selection of front-propagation time T(x,z) slices.

Parameters

fig_name: str Name used as key in figure dictionary. sim: LevelSetSolver Instance of level-set solver providing solution data. x_limits: tuple[float|None, float|None] | None = None Min/max x coordinates on graph. z_min: float | None=-0.05 Minimum z coordinate on graph. z_max: float | None=1.05 Maximum z coordinate on graph. pc_slicing: float = 10 Period of slice plotting as percentage of total number of steps. pc_labeling: float = 20 Period of slice labeling as percentage of total number of steps. title_font_size: int=11 Size of title text. legend_font_size: int=9 Size of legend text. fig_size: tuple[float, float]=(7, 5,) Figure size (in inches!).

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/simviz.py
def plot_time_slices(
        self,
        fig_name: str,
        sim: LevelSetSolver,
        x_limits: tuple[float|None,float|None] | None=None,
        z_min: float | None=-0.05,
        z_max: float | None=1.05,
        pc_slicing: float = 10,
        pc_labeling: float = 20,
        title_font_size: int=11,
        legend_font_size: int=9,
        fig_size: tuple[float, float]=(7, 5,),
    ) -> None:
    """
    Plot selection of front-propagation time T(x,z) slices.

    Parameters
    ----------
    fig_name: str
        Name used as key in figure dictionary.
    sim: LevelSetSolver
        Instance of level-set solver providing solution data.
    x_limits: tuple[float|None, float|None] | None = None
        Min/max x coordinates on graph.
    z_min: float | None=-0.05
        Minimum z coordinate on graph.
    z_max: float | None=1.05
        Maximum z coordinate on graph.
    pc_slicing: float = 10
        Period of slice plotting as percentage of total number of steps.
    pc_labeling: float = 20
        Period of slice labeling as percentage of total number of steps.
    title_font_size: int=11
        Size of title text.
    legend_font_size: int=9
        Size of legend text.
    fig_size: tuple[float, float]=(7, 5,)
        Figure size (in inches!).

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    plt.title(
        self.make_title(sim, "Surface T slices", sim.gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel("x  [-]")
    plt.ylabel("z  [-]")
    cmap = plt.colormaps["brg"] 
    t_: float
    t_max: float = sim.t_total 
    label_: str | None
    n_slices: int = len(sim.T_slices.keys())
    pc_label: float = n_slices if n_slices<50 else pc_labeling
    do_label: Callable \
        = lambda step: (
            False if int((n_slices)*pc_label/100)==0
            else (step)%int((n_slices)*pc_label/100)==0
        )
    pc_plot: float = pc_label/pc_slicing
    do_plot: Callable \
        = lambda step: (
            False if int((n_slices)*pc_plot/100)==0
            else (step)%int((n_slices)*pc_plot/100)==0
        )
    for i_, t_slice_ in enumerate(sim.T_slices.values()):
        if not do_plot(i_):
            continue
        t_ = t_slice_["T"]
        if np.min(t_slice_["φ"])>=-sim.Δx:
            continue
        color_ = cmap(t_/t_max*0.9)
        label_ = (
            rf"$T$ = {np.round(t_,2):g}" if do_label(i_) 
            else None
        )
        plt.plot(
            t_slice_["x"], t_slice_["z"], 
            lw=(1.5 if n_slices<5 or do_label(i_) else 0.25),
            color=color_, 
            label=label_,
        )
    plt.legend(fontsize=legend_font_size, loc=(1.02,0.1))
    plt.xlim(sim.get_x_limits() if x_limits is None else x_limits)
    plt.ylim(
        sim.get_z_limits()[0] if z_min is None else z_min,
        sim.get_z_limits()[1] if z_max is None else z_max
    )
    plt.grid(ls=":",)
    axes = plt.gca()
    axes.set_aspect(1)

plot_φ

plot_φ(
    fig_name: str,
    sim: LevelSetSolver,
    do_φ: bool = False,
    do_φ_everywhere: bool = False,
    do_φ_next: bool = False,
    do_dφdx: bool = False,
    do_dφdz: bool = False,
    do_dTdx: bool = False,
    do_dTdz: bool = False,
    do_beta: bool = False,
    do_speed: bool = False,
    do_aux: bool = False,
    do_ξ0: bool = False,
    do_arrival_time: bool = False,
    do_fix_ticks: bool = False,
    cbar_ticks: NDArray | None = None,
    clip: tuple[float, float] = (-0.2, 0.2),
    title_font_size: int = 11,
    fig_size: tuple[float, float] = (8, 6),
) -> None

Image grid of phi function (could be signed distance, β, ξ, etc).

Parameters

fig_name: str sim: LevelSetSolver title_font_size: int=12 do_φ: bool=False do_φ_everywhere: bool=False do_φ_next: bool=False do_dTdx: bool=False do_dTdz: bool=False do_beta: bool=False do_speed: bool=False do_travel_time: bool=False do_arrival_time: bool=False do_fix_ticks: bool=False cbar_ticks: NDArray | None=None clip: tuple[float, float]=(-0.2, 0.2,) fig_size: tuple[float, float]=(8, 6,)

Attributes

Uses create_figure (adds to fig dict).

Source code in erosionfront/visualization/simviz.py
def plot_φ(
        self,
        fig_name: str,
        sim: LevelSetSolver,
        do_φ: bool=False,
        do_φ_everywhere: bool=False,
        do_φ_next: bool=False,
        do_dφdx: bool=False,
        do_dφdz: bool=False,
        do_dTdx: bool=False,
        do_dTdz: bool=False,
        do_beta: bool=False,
        do_speed: bool=False,
        do_aux: bool=False,
        do_ξ0: bool=False,
        # do_travel_time: bool=False,
        do_arrival_time: bool=False,
        do_fix_ticks: bool=False,
        cbar_ticks: NDArray | None=None,
        clip: tuple[float,float]=(-0.2, 0.2,),
        title_font_size: int=11,
        fig_size: tuple[float,float]=(8, 6,),
    ) -> None:
    """
    Image grid of phi function (could be signed distance, β, ξ, etc).

    Parameters
    ----------

    fig_name: str
    sim: LevelSetSolver
    title_font_size: int=12
    do_φ: bool=False
    do_φ_everywhere: bool=False
    do_φ_next: bool=False
    do_dTdx: bool=False
    do_dTdz: bool=False
    do_beta: bool=False
    do_speed: bool=False
    do_travel_time: bool=False
    do_arrival_time: bool=False
    do_fix_ticks: bool=False
    cbar_ticks: NDArray | None=None
    clip: tuple[float, float]=(-0.2, 0.2,)
    fig_size: tuple[float, float]=(8, 6,)

    Attributes
    ----------
    Uses create_figure (adds to fig dict).
    """
    self.create_figure(fig_name, fig_size=fig_size,)
    f: NDArray | MaskedArray | None
    d: NDArray | MaskedArray | None
    dd: NDArray | MaskedArray | None
    title: str
    cbar_label: str
    cmap: str
    do_centered_norm: bool
    if do_φ:
        f = sim.φ
        d = f
        dd = None
        title = r"Signed distance  {\varphi}"
        cbar_label = "signed distance  [-]"
        cmap = "bwr"
        do_centered_norm = True
    elif do_φ_everywhere:
        f = sim.φ_everywhere
        d = f
        dd = None
        title = r"Signed distance everywhere  {\varphi}_{\infty}"
        cbar_label = "signed distance  [-]"
        cmap = "bwr"
        do_centered_norm = True
    elif do_φ_next:
        f = sim.φ_next
        d = f
        dd = None
        title = r"Signed distance (next)  {\varphi}_\mathrm{next}"
        cbar_label = "signed distance  [-]"
        cmap = "bwr"
        do_centered_norm = True
    elif do_dφdx:
        f = sim.Δφ_x
        d = sim.φ
        dd = None
        title = r"Gradient {\partial}\varphi/{\partial}x"
        cbar_label = r"${\partial}\varphi/{\partial}x$  [-]"
        cmap = "bwr"
        do_centered_norm = True
    elif do_dφdz:
        f = sim.Δφ_z
        d = sim.φ
        dd = None
        title = r"Gradient {\partial}\varphi/{\partial}z"
        cbar_label = r"${\partial}\varphi/{\partial}z$  [-]"
        cmap = "bwr"
        do_centered_norm = True
    # elif do_dTdx:
    #     f = sim.dTdx
    #     d = sim.φ
    #     dd = None
    #     title = r"Gradient {d}T/{d}x"
    #     cbar_label = r"$\mathrm{d}T/\mathrm{d}x$  [-]"
    #     cmap = "bwr"
    #     do_centered_norm = True
    # elif do_dTdz:
    #     f = sim.dTdz
    #     d = sim.φ
    #     dd = None
    #     title = r"Gradient {d}T/{d}z"
    #     cbar_label = r"$\mathrm{d}T/\mathrm{d}z$  [-]"
    #     cmap = "bwr"
    #     do_centered_norm = True
    elif do_beta:
        f = np.rad2deg(sim.β)
        d = sim.φ_next
        dd = sim.φ
        title = r"Surface slope angle  \beta"
        cbar_label = r"$\beta$  [$\degree$]"
        cmap = "hsv" 
        do_centered_norm = True
    elif do_speed:
        f = sim.ξ
        d = sim.φ_next
        dd = sim.φ
        title = r"Surface erosion speed  \it{\xi^{\perp}}"
        cbar_label = r"$\xi^{\!\perp}$  [-]"
        cmap = "viridis"
        do_centered_norm = False
    elif do_aux:
        f = sim.φ_aux
        d = sim.φ_next
        dd = sim.φ
        title = r"Signed distance (aux)  {\varphi}_\mathrm{next}"
        cbar_label = "signed distance (aux)  [-]"
        cmap = "bwr"
        do_centered_norm = True
    elif do_ξ0:
        f = sim.ξ0
        d = None #sim.φ
        dd = None
        title = r"Substrate erodiblity   {\xi}_0"
        cbar_label = r"$\xi_0$  [-]"
        cmap = "managua"
        do_centered_norm = False
    # elif do_travel_time:
    #     f = np.clip(sim.T_signed, *clip,)
    #     d = sim.φ_next
    #     dd = sim.φ
    #     title = r"Travel time  \Delta{T}"
    #     cbar_label = r"$\Delta{T}$  [-]"
    #     cmap = "RdGy_r"
    #     do_centered_norm = True
    elif do_arrival_time and sim.T_arrival is not None:
        f = np.clip(sim.T_arrival, *clip,)
        d = sim.φ_next
        dd = sim.φ
        title = r"Surface arrival time  T"
        cbar_label = r"${T}$  [-]"
        cmap = "pink_r"
        do_centered_norm = False
    else:
        return
    if f is None:
        return
    plt.title(
        self.make_title(sim, title, sim.gma,),
        fontdict={"fontsize": title_font_size,},
    )
    plt.xlabel(r"$x$  [-]")
    plt.ylabel(r"$z$  [-]")
    if (extent:=tuple(sim.get_extent())) is not None:
        plt.imshow(
            f, 
            cmap=cmap, 
            extent=extent, 
            norm=(CenteredNorm() if do_centered_norm else None),
        )
    plt.plot(*sim.get_points_xz(), color="k", lw=0.5,)
    if dd is not None:
        plt.plot(*sim.get_front_points(dd), lw=0.5, color="k", alpha=1,)
    lc: str = (
        "g" if do_arrival_time or do_beta or do_speed # or do_travel_time 
        else "k"
    )
    lw: float = (
        1 if do_arrival_time #or do_travel_time
        else 0.5
    )

    if d is not None:
        plt.plot(*sim.get_front_points(d), lw=lw, color=lc, alpha=1,)

    ticks: NDArray = (
        np.arange(-180,180+45,45,) if cbar_ticks is None else cbar_ticks
    )
    tick_label_fn: Callable = lambda x: f"{'+' if x>0 else ''}{x:1.0f}"
    tick_labels: list[str] = list(map(tick_label_fn, ticks))
    grid_aspect_ratio: float = f.shape[0]/f.shape[1]
    shrink: float = (
        0.65 if grid_aspect_ratio>0.65
        else grid_aspect_ratio
    )
    cbar: Colorbar = plt.colorbar(
        shrink=shrink, 
        pad=0.05, 
        aspect=10,
        ticks=ticks if do_fix_ticks else None,
        format=ticker.FixedFormatter(tick_labels) if do_fix_ticks else None,
    )
    cbar.set_label(cbar_label, size=10,)
    cbar.ax.tick_params(labelsize=9)

    plt.xlim(*sim.get_x_limits())
    plt.ylim(*sim.get_z_limits())
    plt.grid(ls=":", color="g",)
    axes = plt.gca()
    axes.set_aspect(1)

stretch

stretch(
    fig: Figure,
    xs: tuple[float, float] | None = None,
    ys: tuple[float, float] | None = None,
) -> None

Stretch graph axes by respective factors.

Source code in erosionfront/visualization/base.py
def stretch(
    self,
    fig: Figure,
    xs: tuple[float, float] | None = None,
    ys: tuple[float, float] | None = None,
) -> None:
    """Stretch graph axes by respective factors."""
    axes: plt.Axes = fig.gca()
    if xs is not None:
        x_lim = axes.get_xlim()
        x_range = x_lim[1] - x_lim[0]
        axes.set_xlim(
            x_lim[0] - x_range * xs[0], x_lim[1] + x_range * xs[1]
        )
    if ys is not None:
        y_lim = axes.get_ylim()
        y_range = y_lim[1] - y_lim[0]
        axes.set_ylim(
            y_lim[0] - y_range * ys[0], y_lim[1] + y_range * ys[1]
        )