Skip to content

speedviz.py

ErosionSpeedViz

ErosionSpeedViz(dpi: int = 100, font_size: int = 11)

              flowchart TD
              erosionfront.visualization.speedviz.ErosionSpeedViz[ErosionSpeedViz]
              erosionfront.visualization.base.GraphingBase[GraphingBase]

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


              click erosionfront.visualization.speedviz.ErosionSpeedViz href "" "erosionfront.visualization.speedviz.ErosionSpeedViz"
              click erosionfront.visualization.base.GraphingBase href "" "erosionfront.visualization.base.GraphingBase"
            

XXXX

Parameters

XXX

Attributes

TBD

Returns

XXX

Methods:

  • create_figure

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

  • get_aspect

    Get aspect ratio of graph.

  • get_fonts

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

  • naturalize

    Adjust graph aspect ratio into 'natural' ratio.

  • plot_model_erosion_speed

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

  • stretch

    Stretch graph axes by respective factors.

Source code in erosionfront/visualization/base.py
def __init__(self, dpi: int = 100, font_size: int = 11) -> None:
    """Initialize."""
    self.dpi = dpi
    self.font_size = font_size
    self.fdict: dict[Any, Any] = {}
    prop_cycle = plt.rcParams["axes.prop_cycle"]
    self.colors = prop_cycle.by_key()["color"]  # type: ignore
    self.n_colors = len(self.colors)  # type: ignore
    self.color_cycle = cycle(self.colors)  # type: ignore
    self.markers = ("o", "s", "v", "p", "*", "D", "X", "^", "h", "P")
    self.n_markers = len(self.markers)
    self.marker_cycle = cycle(self.markers)
    self.linestyle_list = ("solid", "dashdot", "dashed", (0, (3, 1, 1, 1)))

    color_ = lambda i_: self.colors[i_ % self.n_colors]  # type: ignore
    marker_ = lambda i_: self.markers[i_ % self.n_markers]  # type: ignore
    self.color = color_  # type: ignore
    self.marker = marker_  # type: ignore
    #if "Arial" in self.get_fonts() else "Helvetica"
    self.font_family = "Arial" 
    try:
        mpl.rc("font", size=self.font_size, family=self.font_family)
    except:
        mpl.rc("font", size=self.font_size, family="")

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_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=":")

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]
        )