Skip to content

vizdp.py

VizDP

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

              flowchart TD
              langevin.dp.vizdp.VizDP[VizDP]
              langevin.base.viz.Viz[Viz]

                              langevin.base.viz.Viz --> langevin.dp.vizdp.VizDP
                


              click langevin.dp.vizdp.VizDP href "" "langevin.dp.vizdp.VizDP"
              click langevin.base.viz.Viz href "" "langevin.base.viz.Viz"
            

Visualization class for directed percolation simulations.

Methods:

Source code in .venv/lib/python3.14/site-packages/langevin/base/viz.py
def __init__(self, dpi: int = 100, font_size: int = 11) -> None:
    """Initialize."""
    self.dpi = dpi
    self.font_size = font_size
    self.fdict = {}
    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
    font_size = 11
    fonts = self.get_fonts()
    if "Arial" in fonts:
        self.font_family="Arial"
    elif "DejaVu Sans" in fonts:
        self.font_family="DejaVu Sans"
    else:
        self.font_family="Helvetica"
    mpl.rc("font", size=font_size, family=self.font_family)

create_figure

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

Initialize a MatPlotLib 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

    (str) –

    name of figure; used as key in figures dictionary

  • fig_size

    (tuple[float, float] | None, default: None ) –

    optional width and height of figure in inches

  • dpi

    (int | None, default: None ) –

    rasterization resolution

Returns:

  • Figure

    reference to figure

Source code in .venv/lib/python3.14/site-packages/langevin/base/viz.py
def create_figure(
    self,
    fig_name: str,
    fig_size: tuple[float, float] | None = None,
    dpi: int | None = None,
) -> Figure:
    """
    Initialize a `MatPlotLib` figure.

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

    Args:
        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:
        reference to 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})
    if fig_size_ is not None:
        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

    (Axes) –

    the axes object of the figure

Returns:

Source code in .venv/lib/python3.14/site-packages/langevin/base/viz.py
def get_aspect(self, axes: Axes) -> float: #type: ignore
    """
    Get aspect ratio of graph.

    Args:
        axes:
            the `axes` object of the figure

    Returns:
        aspect ratio
    """
    # Total figure size
    figWH: tuple[float, float] \
        = tuple(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 .venv/lib/python3.14/site-packages/langevin/base/viz.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

multiplot_mean_density_evolution

multiplot_mean_density_evolution(
    name: str,
    sims_info: dict,
    sims_list: list[Any],
    do_loglog: bool = True,
    do_rescale: bool = False,
    y_sf: float = 1,
    n_digits: int = 6,
    do_label_Δ: bool = True,
    color_palette: str = "coolwarm",
) -> Figure

Plot an ensemble graph of the mean density ρ(t) versus time t for all sims.

Depending on the arguments, the graph may plot DP-rescaled values, and may have log-log axes.

Parameters:

  • name

    (str) –

    of figure to be used as key in viz dictionary

  • sims_info

    (dict) –

    dictionary of ensemble

  • sims_list

    (list[Any]) –

    list of all sim instances in the ensemble

  • do_rescale

    (bool, default: False ) –

    plot DP-rescaled values

  • do_loglog

    (bool, default: True ) –

    use log axes

  • y_sf

    (float, default: 1 ) –

    scale ρ values by this amount

  • n_digits

    (int, default: 6 ) –

    number of digits to be used in title when printing linear coefficient a

  • do_label_Δ

    (bool, default: True ) –

    compute Δ=a-a_c and label curves with it, instead of just a

Returns:

  • Figure

    Matplotlib figure instance.

Source code in .venv/lib/python3.14/site-packages/langevin/dp/vizdp.py
def multiplot_mean_density_evolution(
        self,
        name: str, 
        sims_info: dict,
        sims_list: list[Any],
        do_loglog: bool=True,
        do_rescale: bool=False,
        y_sf: float=1,
        n_digits: int=6,
        do_label_Δ: bool=True,
        color_palette: str="coolwarm",
    ) -> Figure:
    """
    Plot an ensemble graph of the mean density ρ(t) versus time t for all sims.

    Depending on the arguments, the graph may plot DP-rescaled values, 
    and may have log-log axes.

    Args:
        name: of figure to be used as key in viz dictionary
        sims_info: dictionary of ensemble
        sims_list: list of all sim instances in the ensemble
        do_rescale: plot DP-rescaled values
        do_loglog: use log axes
        y_sf: scale ρ values by this amount
        n_digits: number of digits to be used in title when printing linear coefficient a
        do_label_Δ: compute Δ=a-a_c and label curves with it, instead of just a

    Returns:
        Matplotlib figure instance.

    """
    fig_size: tuple[float,float] = (6, 4,)
    fig = self.create_figure(fig_name=name, fig_size=fig_size,)
    sim_: Any
    parameters_list: list[dict] = [
        sim_.parameters for sim_ in sims_list
    ]
    analysis_list: list[dict] = [
        sim_.analysis for sim_ in sims_list
    ]
    t_epochs_list: list[NDArray] = [
        sim_.t_epochs for sim_ in sims_list
    ]
    mean_densities_list: list[NDArray] = [
        sim_.mean_densities for sim_ in sims_list
    ]
    title = make_sim_title(
        parameters_list[0], analysis_list[0], dplvn, do_omit_a=True,
    )
    plt.title(title, fontdict={"size":11},)

    # See Hinrichsen 2010, table 2; Henkel et al 2008, tables 4.1, 4.3
    dp_β: float    = analysis_list[0]["dp_β"]
    dp_ν_pp: float = analysis_list[0]["dp_ν_pp"]
    dp_ν_ll: float = analysis_list[0]["dp_ν_ll"]
    dp_δ: float    = analysis_list[0]["dp_δ"]
    dp_z: float    = analysis_list[0]["dp_z"]

    n_sims: int = len(sims_list)
    cmap: ListedColormap = mpl.colormaps[color_palette] #type: ignore
    color_list: NDArray = cmap(np.linspace(0, 1, n_sims,))*0.75 #type: ignore
    i_: int
    for (i_, (
        parameters_, analysis_, t_epochs_, mean_densities_, 
        color_
    )) in enumerate(zip(
        parameters_list, 
        analysis_list, 
        t_epochs_list, 
        mean_densities_list,
        color_list[::-1],
    )):
        t : NDArray= t_epochs_[mean_densities_>0]
        md: NDArray = mean_densities_[mean_densities_>0]
        md = md[t>=5e-1]
        t = t[t>=5e-1]

        t_: NDArray
        md_: NDArray
        Δ: float = parameters_["linear"]-analysis_["a_c"]
        # n_x: int = parameters_["grid_size"][0]
        # n_y: int = parameters_["grid_size"][1]
        # t_ = t**(dp_ν_ll)/(float(n_x*n_y))**dp_z
        if do_rescale:
            t_ = np.abs(Δ) * t**(dp_ν_ll)
            md_ = md * t**(dp_β/dp_ν_ll)
        else:
            t_ = t
            md_ = md

        if not do_rescale and np.abs(Δ)<1e-10:
            plt.plot(
                t_trend, md_trend*y_sf, "k-",  lw=2, alpha=0.4,
                zorder=10,
            )
        if np.abs(Δ)<1e-10 and do_rescale:
            continue

        t_trend: NDArray 
        if do_loglog:
            t_trend = 10**np.arange(
                np.log10(t_[0]), max(5.0, np.log10(t_[-1]))+0.1, 0.1,
            )
        else:
            t_trend = t_
        md_trend: NDArray = (t_trend)**(-dp_δ) * (md_[0])

        label_: str = (
            f"{round(Δ*100,n_digits-2):01.1f}" if do_label_Δ 
            else f"{parameters_["linear"]:01.6f}"
        )
        plt.plot(
            t_, md_, "-", 
            color=color_, lw=0.5, alpha=0.7, zorder=n_sims-i_,
        )
        plt.plot(
            0*t_, 0*md_, "-", 
            color=color_, lw=1.5, alpha=1, label=label_, zorder=n_sims-i_,
        )

    if do_rescale:
        plt.xlabel(r"Rescaled time $|a-a_c|^{\nu_{||}}\, t$  [-]")
        plt.ylabel(
            r"Rescaled grid-mean density  "
            + r"$t^{\beta/\nu_{\perp}}\overline{\rho} $  [-]"
        )
        if do_loglog:
            plt.ylim(sims_info["Misc"]["ylimits_rescaled"])
            plt.xlim(sims_info["Misc"]["xlimits_rescaled"])
        else:
            plt.ylim(0, None,)
            plt.xlim(1e0, None,)
    else:
        plt.xlabel(r"Time $t$  [-]")
        plt.ylabel(r"Grid-mean density  $\overline{\rho}(t)$  [-]")
        if do_loglog:
            plt.ylim(sims_info["Misc"]["ylimits_log"])
            plt.xlim(sims_info["Misc"]["xlimits_log"])
        else:
            plt.autoscale(
                enable=True, axis='both', tight=True,
            )
            plt.ylim(0, None,)
    if do_loglog:
        plt.loglog()

    plt.legend(
        fontsize=7, 
        title=r"$100(a-a_c)$", title_fontsize=8,
        loc=("upper left" if do_rescale else "lower left"),
    )
    plt.grid(ls=":")
    plt.close()
    return fig

naturalize

naturalize(fig: Figure) -> None

Adjust graph aspect ratio into 'natural' ratio.

Source code in .venv/lib/python3.14/site-packages/langevin/base/viz.py
def naturalize(self, fig: Figure) -> None:
    """Adjust graph aspect ratio into 'natural' ratio."""
    axes: Axes = fig.gca() #type: ignore
    # 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_density_image

plot_density_image(
    name: str,
    parameters: dict,
    analysis: dict,
    t_epoch: float,
    density: NDArray,
    density_max: float = 0.5,
    tick_Δρ: float = 0.5,
    do_extend_if_periodic: bool = False,
    n_digits: int = 6,
    color_palette: str = "plasma",
) -> Figure

Generate an image grid of the Langevin density field.

Parameters:

  • name

    (str) –

    of figure to be used as key in viz dictionary

  • parameters

    (dict) –

    sim parameters dictionary

  • analysis

    (dict) –

    sim analysis dictionary

  • t_epoch

    (float) –

    time slice of density grid

  • density

    (NDArray) –

    the sliced density field

  • density_max

    (float, default: 0.5 ) –

    upper bound for rendering density

  • tick_Δρ

    (float, default: 0.5 ) –

    step in density colorbar labeling

  • do_extend_if_periodic

    (bool, default: False ) –

    artificially extend grid by ~20% in periodic directions

  • n_digits

    (int, default: 6 ) –

    number of digits to be used in title when printing linear coefficient a

  • color_palette

    (str, default: 'plasma' ) –

    for image grid rendering

Returns:

  • Figure

    Matplotlib figure instance.

Source code in .venv/lib/python3.14/site-packages/langevin/dp/vizdp.py
def plot_density_image(
        self,
        name: str, 
        parameters: dict,
        analysis: dict,
        t_epoch: float, 
        density: NDArray,
        density_max: float=0.5,
        tick_Δρ: float=0.5,
        do_extend_if_periodic: bool=False,
        n_digits: int=6,
        color_palette: str="plasma",
    ) -> Figure:
    """
    Generate an image grid of the Langevin density field.

    Args:
        name: of figure to be used as key in viz dictionary
        parameters: sim parameters dictionary
        analysis: sim analysis dictionary
        t_epoch: time slice of density grid
        density: the sliced density field
        density_max: upper bound for rendering density
        tick_Δρ: step in density colorbar labeling
        do_extend_if_periodic: artificially extend grid by ~20% in periodic directions
        n_digits: number of digits to be used in title when printing linear coefficient a
        color_palette: for image grid rendering

    Returns:
        Matplotlib figure instance.
    """
    aspect_ratio: float = reduce(lambda nx, ny: nx/ny, parameters["grid_size"])
    sf: float = (aspect_ratio)**(0.3)/1.15
    fig_size: tuple[float,float] = (6.5*sf, 6.5/sf,)
    fig = self.create_figure(fig_name=name, fig_size=fig_size,)

    prefix: str = (
        r"$\rho(\mathbf{x},t=$" + f"{t_epoch:0{n_digits-1}.0f}" + r"$)$  "
        # r"$\rho(\mathbf{x},t=$" + f"{t_epoch:0{n_digits+2}.1f}" + r"$)$  "
    )
    title = make_sim_title(
        parameters, analysis, dplvn,
    )
    plt.title(prefix+title, fontdict={"size":10},)

    grid_: NDArray = np.flipud(density.T)
    n_pad_ud: int
    n_pad_lr: int
    if (
        do_extend_if_periodic 
        and parameters["grid_topologies"][0]==dplvn.PERIODIC
    ):
        n_pad_ud = max(grid_.shape[0]//5, 10)
        grid_ = np.vstack([grid_, grid_[:n_pad_ud]])
    if (
        do_extend_if_periodic 
        and parameters["grid_topologies"][1]==dplvn.PERIODIC
    ):
        n_pad_lr = max(grid_.shape[1]//5, 10)
        grid_ = np.hstack([grid_, grid_[:,:n_pad_lr]])
    (n_ud, n_lr,) = grid_.shape
    # Fix absorbing phase ρ=0 to be gray
    color_map: Colormap = mpl.colormaps[color_palette].resampled(1000)
    color_map.colors[0] = [0.9, 0.9, 0.9, 0.9]
    plt.imshow(
        grid_,  
        extent=(0, n_lr, 0, n_ud), 
        cmap=color_map,
        vmin=0, 
        vmax=density_max,
    )
    ticks: NDArray = np.arange(0, density_max+1, tick_Δρ,)
    bar_shrink: float
    if n_lr/n_ud<3:
        bar_shrink = 0.35 
    elif n_lr/n_ud<4:
        bar_shrink = 0.23
    else:
        bar_shrink = 0.23 #0.17
    color_bar: Any = plt.colorbar(
        shrink=bar_shrink, pad=0.05, aspect=12, ticks=ticks, extend="max",
    )
    color_bar.set_label(r"$\rho(\mathbf{x},t)$  [-]")
    plt.xlabel(r"$x$   [-]")
    plt.ylabel(r"$y$   [-]")
    plt.close()
    return fig

plot_density_profile

plot_density_profile(
    name: str,
    parameters: dict,
    analysis: dict,
    density_dict: dict,
    t_epochs: NDArray,
    t_begin: float,
    t_end: float,
    y_offset: float,
    do_loglog: bool = True,
    do_loglinear: bool = False,
    do_powerlawtrend: bool = True,
    do_exponentialtrend: bool = False,
    exponential_factor: float = 10,
    y_sf: float = 0.71,
    x_limits: None | tuple[float | None, float | None] = None,
    y_limits: None | tuple[float | None, float | None] = None,
) -> Figure

Plot a graph of the time- and transverse-mean density ρ(t) versus wall distance.

Parameters:

  • name

    (str) –

    of figure to be used as key in viz dictionary

  • parameters

    (dict) –

    sim parameters dictionary

  • analysis

    (dict) –

    sim analysis dictionary

  • density_dict

    (dict) –

    density field snapshots

  • t_epochs

    (NDArray) –

    time slices of simulation

  • t_begin

    (float) –

    when to begin time integration

  • t_end

    (float) –

    when to end time integration

  • y_offset

    (float) –

    effective distance of wall cell from boundary condition

  • do_loglog

    (bool, default: True ) –

    use log axes

  • do_powerlawtrend

    (bool, default: True ) –

    plot DP model wall scaling curve

  • y_sf

    (float, default: 0.71 ) –

    scale ρ values by this amount

  • x_limits

    (None | tuple[float | None, float | None], default: None ) –

    optionally control x axis limits

  • y_limits

    (None | tuple[float | None, float | None], default: None ) –

    optionally control y axis limits

Returns:

  • Figure

    Matplotlib figure instance.

Source code in .venv/lib/python3.14/site-packages/langevin/dp/vizdp.py
def plot_density_profile(
        self,
        name: str, 
        parameters: dict,
        analysis: dict,
        density_dict: dict,
        t_epochs: NDArray,
        t_begin: float,
        t_end: float,
        y_offset: float,
        do_loglog: bool=True,
        do_loglinear: bool=False,
        do_powerlawtrend: bool=True,
        do_exponentialtrend: bool=False,
        exponential_factor: float=10,
        y_sf: float=0.71,
        x_limits: None | tuple[float|None, float|None]=None,
        y_limits: None | tuple[float|None, float|None]=None,
    ) -> Figure:
    """
    Plot a graph of the time- and transverse-mean density ρ(t) versus wall distance.

    Args:
        name: of figure to be used as key in viz dictionary
        parameters: sim parameters dictionary
        analysis: sim analysis dictionary
        density_dict: density field snapshots
        t_epochs: time slices of simulation
        t_begin: when to begin time integration
        t_end: when to end time integration
        y_offset: effective distance of wall cell from boundary condition
        do_loglog: use log axes
        do_powerlawtrend: plot DP model wall scaling curve
        y_sf: scale ρ values by this amount
        x_limits: optionally control x axis limits
        y_limits: optionally control y axis limits

    Returns:
        Matplotlib figure instance.
    """
    fig_size: tuple[float,float] = (6, 4,)
    fig = self.create_figure(fig_name=name, fig_size=fig_size,)

    title = make_sim_title(
        parameters, analysis, dplvn,
    )
    plt.title(title, fontdict={"size":11},)

    dp_β: float    = analysis["dp_β"]
    dp_ν_pp: float = analysis["dp_ν_pp"]

    t_final = t_epochs[-1]
    subset_t_epochs = tuple(
        filter(lambda t: t>=t_begin and t<=t_end, density_dict.keys())
    )
    n_x, n_y = parameters["grid_size"]
    density_profile = reduce(
        lambda x, y: x + y, 
        [np.sum(density_dict[t_epoch_], axis=0,) 
        for t_epoch_ in subset_t_epochs]
    )/(len(subset_t_epochs)*n_x)
    dy = parameters["dx"]
    y_ = np.arange(n_y, 0, -1)*dy - dy/2 + y_offset
    plt.plot(
        y_, density_profile, 
        "-", 
        lw=1,
        label=(r"DP simulation" if do_powerlawtrend else None)
    )
    if do_exponentialtrend:
        plt.plot(
            y_, np.exp(-y_/exponential_factor)*y_sf, ":", 
            label=r"$\widebar\rho \sim e^{-y/"+f"{exponential_factor}"+r"}$"
        )
    elif do_powerlawtrend:
        plt.plot(
            y_, y_**(-dp_β/dp_ν_pp)*y_sf, ":", 
            label=r"$\widebar\rho \sim y^{-\beta/\nu_{\!\perp}} \sim y^{-0.796}$"
        )
    axes = plt.gca()
    if do_loglinear | do_loglog:
        axes.set_yscale("log")
    if do_loglog:
        axes.set_xscale("log")
    plt.autoscale(enable=True, axis="x", tight=True,)
    if x_limits is not None:
        plt.xlim(*x_limits)
    if y_limits is not None:
        plt.ylim(*y_limits)
    plt.ylabel(r"Time- & wall-parallel-averaged density  $\rho$")
    plt.xlabel(r"Distance from wall $y$")
    plt.legend(fontsize=11,)
    plt.grid(ls=":")
    plt.close()
    return fig

plot_mean_density_evolution

plot_mean_density_evolution(
    name: str,
    parameters: dict,
    analysis: dict,
    misc: dict,
    t_epochs: NDArray,
    mean_densities: NDArray,
    do_rescale: bool = False,
    do_loglog: bool = True,
    y_sf: float = 1,
    n_digits: int = 6,
    t_begin: float = 0.5,
    t_end: float | None = None,
) -> Figure

Plot a graph of the mean density ρ(t) versus time t.

Depending on the arguments, the graph may plot DP-rescaled values, and may have log-log axes.

Parameters:

  • name

    (str) –

    of figure to be used as key in viz dictionary

  • parameters

    (dict) –

    sim parameters dictionary

  • analysis

    (dict) –

    sim analysis dictionary

  • misc

    (dict) –

    sim miscellaneous dictionary

  • t_epochs

    (NDArray) –

    time slices of simulation

  • mean_densities

    (NDArray) –

    grid-averaged density field during simulation

  • do_rescale

    (bool, default: False ) –

    plot DP-rescaled values

  • do_loglog

    (bool, default: True ) –

    use log axes

  • y_sf

    (float, default: 1 ) –

    scale ρ values by this amount

  • n_digits

    (int, default: 6 ) –

    number of digits to be used in title when printing linear coefficient a

Returns:

  • Figure

    Matplotlib figure instance.

Source code in .venv/lib/python3.14/site-packages/langevin/dp/vizdp.py
def plot_mean_density_evolution(
        self,
        name: str, 
        parameters: dict,
        analysis: dict,
        misc: dict,
        t_epochs: NDArray,
        mean_densities: NDArray,
        do_rescale: bool=False,
        do_loglog: bool=True,
        y_sf: float=1,
        n_digits: int=6,
        t_begin: float=0.5,
        t_end: float | None=None,
    ) -> Figure:
    """
    Plot a graph of the mean density ρ(t) versus time t.

    Depending on the arguments, the graph may plot DP-rescaled values, 
    and may have log-log axes.

    Args:
        name: of figure to be used as key in viz dictionary
        parameters: sim parameters dictionary
        analysis: sim analysis dictionary
        misc: sim miscellaneous dictionary
        t_epochs: time slices of simulation
        mean_densities: grid-averaged density field during simulation
        do_rescale: plot DP-rescaled values
        do_loglog: use log axes
        y_sf: scale ρ values by this amount
        n_digits: number of digits to be used in title when printing linear coefficient a

    Returns:
        Matplotlib figure instance.
    """
    fig_size: tuple[float,float] = (6, 4,)
    fig = self.create_figure(fig_name=name, fig_size=fig_size,)
    title = make_sim_title(
        parameters, analysis, dplvn,
    )
    plt.title(title, fontdict={"size":11},)

    # See Hinrichsen 2010, table 2; Henkel et al 2008, tables 4.1, 4.3
    dp_β: float    = analysis["dp_β"]
    dp_ν_pp: float = analysis["dp_ν_pp"]
    dp_ν_ll: float = analysis["dp_ν_ll"]
    dp_δ: float    = analysis["dp_δ"]

    t : NDArray= t_epochs[mean_densities>0]
    md: NDArray = mean_densities[mean_densities>0]
    if (t[t>=t_begin].shape[0])>0:
        md = md[t>=t_begin]
        t = t[t>=t_begin]

    t_: NDArray
    md_: NDArray
    Δ_: float = np.abs(parameters["linear"]-analysis["a_c"])
    Δ: float = (Δ_ if np.abs(Δ_)>1e-20 else 10**(-n_digits))
    if do_rescale:
        # print(f"Δ={Δ}")
        t_ = Δ * t**(dp_ν_ll)
        md_ = md * t**(dp_β/dp_ν_ll)
        # md_ = md * t**(dp_δ)
    else:
        t_ = t
        md_ = md

    t_trend: NDArray 
    if do_loglog:
        t_trend = 10**np.arange(
            np.log10(t_[0]), max(5.0, np.log10(t_[-1]))+0.1, 0.1,
        )
    else:
        t_trend = t_
    md_trend: NDArray = (t_trend)**(-dp_δ) * (md_[0])

    plt.plot(t_, md_, "-", lw=0.5,)
    if not do_rescale:
        plt.plot(t_trend, md_trend*y_sf, "-",  lw=1, alpha=0.5,)

    if do_rescale:
        plt.xlabel(r"Rescaled time $|a-a_c|^{\nu_{||}}\, t$  [-]")
        plt.ylabel(
            r"Rescaled grid-mean density  "
            + r"$t^{\beta/\nu_{\perp}}\overline{\rho} $  [-]"
        )
        if do_loglog:
            plt.ylim(misc["ylimits_rescaled"])
            plt.xlim(misc["xlimits_rescaled"])
        else:
            plt.ylim(0, None,)
            plt.xlim(1e0, None,)
    else:
        plt.xlabel(r"Time $t$  [-]")
        plt.ylabel(r"Grid-mean density  $\overline{\rho}(t)$  [-]")
        if do_loglog:
            plt.ylim(misc["ylimits_log"])
            plt.xlim(misc["xlimits_log"])
        else:
            plt.autoscale(
                enable=True, axis='both', tight=True,
            )
            plt.ylim(0, None)
            # print(t_begin, t_[-1])
            # plt.xlim(t_begin, t_[-1])
    if do_loglog:
        plt.loglog()

    plt.grid(ls=":")
    plt.close()
    return fig

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 .venv/lib/python3.14/site-packages/langevin/base/viz.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: Axes = fig.gca() #type: ignore
    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]
        )