Skip to content

carto_flow.flow_cartogram.animation

Animation utilities for cartogram results.

Animation functions for visualizing morphing results, including geometry transitions, density field evolution, and velocity field dynamics.

Functions:

Examples:

>>> from carto_flow import CartogramWorkflow, MorphOptions
>>> from carto_flow.flow_cartogram.animation import animate_morph_history, save_animation
>>>
>>> workflow = CartogramWorkflow(gdf, 'population')
>>> cartogram = workflow.morph(options=MorphOptions(save_history=True))
>>> anim = animate_morph_history(cartogram, duration=5.0, fps=15)
>>> save_animation(anim, "morph.gif", fps=15)

animate_density_field

animate_density_field(
    cartogram: Cartogram,
    *,
    duration: float = 5.0,
    fps: int = 15,
    interpolation: str = "nearest",
    position_mapper: PositionMapper | None = None,
    bounds: Any | None = None,
    density: Optional[DensityPlotOptions] = None,
    show_axes: bool = True,
    title: str | bool | None = None,
    figsize: tuple[float, float] = (10, 8),
) -> FuncAnimation

Animate density field evolution. Convenience wrapper for animate_fields.

See animate_fields for full documentation.

animate_fields

animate_fields(
    cartogram: Cartogram,
    *,
    duration: float = 5.0,
    fps: int = 15,
    interpolation: str = "nearest",
    position_mapper: PositionMapper | None = None,
    bounds: Any | None = None,
    show_density: bool = True,
    show_velocity: bool = False,
    density: Optional[DensityPlotOptions] = None,
    velocity: Optional[VelocityPlotOptions] = None,
    show_axes: bool = True,
    title: str | bool | None = None,
    figsize: tuple[float, float] = (10, 8),
) -> FuncAnimation

Animate density and/or velocity fields over iterations.

Parameters:

  • cartogram (Cartogram) –

    Cartogram result with internals (requires save_internals=True)

  • duration (float, default: 5.0 ) –

    Animation duration in seconds

  • fps (int, default: 15 ) –

    Frames per second

  • interpolation (str, default: "nearest" ) –

    Interpolation method: "nearest" or "linear"

  • position_mapper (callable, default: None ) –

    Function to control animation timing. Use linear_over() factory.

  • bounds (str, float, or tuple, default: None ) –

    Clip view to specified bounds

  • show_density (bool, default: True ) –

    Whether to show density field heatmap

  • show_velocity (bool, default: False ) –

    Whether to show velocity field arrows

  • density (DensityPlotOptions, default: None ) –

    Rendering options for the density field. Key fields:

    • normalize: None (absolute), "difference", or "ratio".
    • clip_percentile / max_scale: outlier control for difference mode.
    • cmap / alpha: colormap and transparency.
    • vmin / vmax: override the global color-scale limits.
    • colorbar_kwargs: passed to fig.colorbar().
    • imshow_kwargs: passed to ax.imshow().
  • velocity (VelocityPlotOptions, default: None ) –

    Rendering options for the velocity field. Key fields:

    • skip: plot every nth arrow (default 4).
    • velocity_scale / ref_magnitude: arrow length control.
    • color / alpha: base arrow color and transparency.
    • color_by: None, "magnitude", or "direction".
    • colorbar: whether to show a colorbar (default False in animations).
    • colorbar_kwargs: passed to fig.colorbar().
    • quiver_kwargs: passed to ax.quiver().
  • show_axes (bool, default: True ) –

    If False, hides the axes frame, ticks, and labels (ax.axis("off")). Useful for clean map-style animations.

  • title (str, bool, or None, default: None ) –

    Controls the axes title each frame.

    • None: auto-title ("Density Field (iteration N)").
    • False or "": no title.
    • str: format-string expanded each frame. Available keys: {iteration}, {field} (e.g. "Density Field"), {t}.
  • figsize (tuple, default: (10, 8) ) –

    Figure size (width, height)

Returns:

  • FuncAnimation

    Matplotlib animation object

Examples:

>>> from carto_flow.flow_cartogram.visualization import DensityPlotOptions, VelocityPlotOptions
>>> # Density field only (default)
>>> anim = animate_fields(cartogram, density=DensityPlotOptions(normalize="ratio"))
>>> # Velocity field only
>>> anim = animate_fields(cartogram, show_density=False, show_velocity=True)
>>> # Combined: density with velocity overlay
>>> anim = animate_fields(
...     cartogram, show_velocity=True,
...     density=DensityPlotOptions(normalize="ratio"),
...     velocity=VelocityPlotOptions(color="black", alpha_by_magnitude=True),
... )

animate_geometry_keyframes

animate_geometry_keyframes(
    keyframes: list[Any],
    duration: float = 5.0,
    fps: int = 15,
    interpolation: str = "linear",
    position_mapper: PositionMapper | None = None,
    keyframe_times: ndarray | None = None,
    hold_frames: int = 0,
    column: str | None = None,
    color_values: list[ndarray] | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    cmap: str = "viridis",
    colorbar: bool = False,
    colorbar_label: str | None = None,
    show_axes: bool = True,
    colorbar_kwargs: dict | None = None,
    title: str | bool | None = None,
    precompute: bool = True,
    figsize: tuple[float, float] = (10, 8),
    **kwargs: Any,
) -> FuncAnimation

Animate between arbitrary geometry states (keyframes).

Parameters:

  • keyframes (list) –

    List of geometry sources. Each can be: - GeoDataFrame - Cartogram (uses latest snapshot's geometry)

  • duration (float, default: 5.0 ) –

    Animation duration in seconds

  • fps (int, default: 15 ) –

    Frames per second

  • interpolation (str, default: "linear" ) –

    Interpolation method between keyframes: - "nearest": Jump between keyframes (no interpolation) - "linear": Linearly interpolate geometry vertices between keyframes

  • position_mapper (callable, default: None ) –

    Function to control animation timing. Maps progress [0,1] to position in keyframe space [0, n_keyframes-1]. Use linear_over() factory: - linear_over("index"): Linear time-to-keyframe index (default) - linear_over("time"): Linear time-to-time (requires keyframe_times) - linear_over(custom_values): Linear over any custom array Use weights_to_position_mapper() for weight-based functions.

  • keyframe_times (array - like, default: None ) –

    Time values for each keyframe. Must have same length as keyframes. Enables linear_over("time") position mapper. Values should be monotonically increasing.

  • hold_frames (int, default: 0 ) –

    Number of frames to hold at each keyframe before transitioning. Note: When using a position_mapper, hold_frames is ignored.

  • column (str, default: None ) –

    Column to use for coloring geometries. Values are read from each keyframe's GeoDataFrame and color limits are computed globally.

  • color_values (list of arrays, default: None ) –

    Per-keyframe color values. Each array has one value per geometry. When provided, takes precedence over column. Color values are interpolated when using linear geometry interpolation.

  • vmin (float, default: None ) –

    Minimum value for color scale. If None, computed from all values.

  • vmax (float, default: None ) –

    Maximum value for color scale. If None, computed from all values.

  • cmap (str, default: "viridis" ) –

    Colormap name for coloring geometries.

  • colorbar (bool, default: False ) –

    Whether to show a colorbar.

  • colorbar_label (str, default: None ) –

    Label for the colorbar. Defaults to column name if using column.

  • show_axes (bool, default: True ) –

    If False, hides the axes frame, ticks, and labels (ax.axis("off")). Useful for clean map-style animations.

  • colorbar_kwargs (dict, default: None ) –

    Additional keyword arguments passed to fig.colorbar(). Example: dict(shrink=0.8, pad=0.02). The "label" key overrides the auto-set label.

  • title (str, bool, or None, default: None ) –

    Controls the axes title each frame.

    • None: auto-title ("Keyframe X/N" or transition label).
    • False or "": no title.
    • str: format-string expanded with str.format_map(ctx) each frame. Available keys: {keyframe} (1-based), {n_keyframes}, {t} (inter-keyframe fraction in [0, 1]).
  • precompute (bool, default: True ) –

    If True, all frames are computed before the animation starts. Eliminates per-frame geometry interpolation and GeoDataFrame copying, giving a significant speedup especially for interpolation="linear". Set to False to reduce peak memory usage for very long animations.

  • figsize (tuple, default: (10, 8) ) –

    Figure size (width, height)

  • **kwargs (Any, default: {} ) –

    Additional arguments passed to GeoDataFrame.plot()

Returns:

  • FuncAnimation

    Matplotlib animation object

Notes

Available variables for position_mapper: - "index": Keyframe indices [0, 1, 2, ...] - "time": Keyframe times (if keyframe_times is provided)

Color limits are computed globally across all keyframes to ensure consistent coloring throughout the animation.

Examples:

>>> # Animate with smooth interpolation (default: linear over index)
>>> anim = animate_geometry_keyframes(
...     keyframes=[gdf, result1, result2],
...     duration=6.0,
...     interpolation="linear",
... )
>>> save_animation(anim, "keyframes.gif", fps=15)
>>> # Animate with changing colors (e.g., population over years)
>>> anim = animate_geometry_keyframes(
...     keyframes=[gdf_2020, gdf_2021, gdf_2022],
...     color_values=[pop_2020, pop_2021, pop_2022],
...     interpolation="linear",
...     cmap="plasma",
...     colorbar=True,
...     colorbar_label="Population"
... )
>>> # Use column from GeoDataFrames with consistent limits
>>> anim = animate_geometry_keyframes(
...     keyframes=[gdf1, gdf2, gdf3],
...     column="value",
...     cmap="RdYlGn",
... )
>>> # Linear over custom times
>>> from carto_flow.flow_cartogram.animation import linear_over
>>> anim = animate_geometry_keyframes(
...     keyframes=[gdf, result1, result2],
...     keyframe_times=[0.0, 0.3, 1.0],
...     position_mapper=linear_over("time"),
... )
>>> # Hold at each keyframe before transitioning (legacy mode)
>>> anim = animate_geometry_keyframes(
...     keyframes=[gdf, result1, result2],
...     hold_frames=5,
... )

animate_morph_history

animate_morph_history(
    cartogram: Cartogram,
    duration: float = 5.0,
    fps: int = 15,
    interpolation: str = "nearest",
    position_mapper: PositionMapper | None = None,
    color_by: str | ndarray | list | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    cmap: str = "viridis",
    colorbar: bool = False,
    colorbar_label: str | None = None,
    show_axes: bool = True,
    colorbar_kwargs: dict | None = None,
    title: str | bool | None = None,
    precompute: bool = True,
    figsize: tuple[float, float] = (10, 8),
    **kwargs: Any,
) -> FuncAnimation

Animate through algorithm snapshots from a Cartogram's history.

Parameters:

  • cartogram (Cartogram) –

    Cartogram result with snapshots containing geometry history

  • duration (float, default: 5.0 ) –

    Animation duration in seconds

  • fps (int, default: 15 ) –

    Frames per second

  • interpolation (str, default: "nearest" ) –

    Interpolation method between snapshots: - "nearest": Show the nearest snapshot (no interpolation) - "linear": Linearly interpolate geometry vertices between snapshots

  • position_mapper (callable, default: None ) –

    Function to control animation timing. Maps progress [0,1] to position in snapshot space [0, n_snapshots-1]. Use linear_over() factory: - linear_over("iteration"): Linear time-to-iteration (default) - linear_over("mean_error"): Linear time-to-mean-error - linear_over("max_error"): Linear time-to-max-error - linear_over(custom_values): Linear over any custom array Use weights_to_position_mapper() for weight-based functions.

  • color_by (str, np.ndarray, or list of np.ndarray, default: None ) –

    What to color geometries by: - "errors_pct": per-geometry percentage error at each snapshot - "density": per-geometry density (values/area) at each snapshot - "original": values from the column used to build the cartogram (static across snapshots; requires cartogram._value_column) - any other str: column name looked up in cartogram._source_gdf (static across snapshots) - np.ndarray: single array broadcast to all snapshots (static) - list of np.ndarray: one array per snapshot

  • vmin (float, default: None ) –

    Minimum value for color scale. If None, computed from all values.

  • vmax (float, default: None ) –

    Maximum value for color scale. If None, computed from all values.

  • cmap (str, default: "viridis" ) –

    Colormap name for coloring geometries.

  • colorbar (bool, default: False ) –

    Whether to show a colorbar.

  • colorbar_label (str, default: None ) –

    Label for the colorbar. Auto-set from color_by if not provided.

  • show_axes (bool, default: True ) –

    If False, hides the axes frame, ticks, and labels (ax.axis("off")). Useful for clean map-style animations.

  • colorbar_kwargs (dict, default: None ) –

    Additional keyword arguments passed to fig.colorbar(). Example: dict(shrink=0.8, pad=0.02). The "label" key overrides the auto-set label.

  • title (str, bool, or None, default: None ) –

    Controls the axes title each frame. - None: auto-generated title showing iteration and error (default) - False or "": no title - str: format template rendered with str.format_map() each frame. Available keys: {iteration}, {mean_error}, {max_error}, {mean_error_pct}, {max_error_pct}, {t}. Unavailable keys (e.g. when no error history was saved) yield nan.

  • precompute (bool, default: True ) –

    If True, all frames are computed before the animation starts. Eliminates per-frame geometry interpolation and GeoDataFrame copying, giving a significant speedup especially for interpolation="linear". Set to False to reduce peak memory usage for very long animations.

  • figsize (tuple, default: (10, 8) ) –

    Figure size (width, height)

  • **kwargs (Any, default: {} ) –

    Additional arguments passed to GeoDataFrame.plot()

Returns:

  • FuncAnimation

    Matplotlib animation object

Raises:

  • ValueError

    If cartogram.snapshots doesn't contain geometry snapshots

Notes

Available variables for position_mapper (extracted from snapshots): - "iteration": Iteration numbers - "mean_error": Mean log2 errors (if available) - "max_error": Maximum log2 errors (if available) - "index": Snapshot indices [0, 1, 2, ...]

Color limits are computed globally across all snapshots to ensure consistent coloring throughout the animation.

Examples:

>>> workflow = CartogramWorkflow(gdf, 'pop')
>>> cartogram = workflow.morph(options=MorphOptions(save_history=True))
>>> anim = animate_morph_history(cartogram, duration=5.0, fps=15)
>>> save_animation(anim, "morph.gif", fps=15)
>>> # Color by per-geometry error percentage
>>> anim = animate_morph_history(
...     cartogram, color_by="errors_pct", cmap="RdYlGn_r", colorbar=True
... )
>>> # Color by per-snapshot density
>>> anim = animate_morph_history(cartogram, color_by="density", cmap="plasma", colorbar=True)
>>> # Color by original data column (static)
>>> anim = animate_morph_history(cartogram, color_by="original", colorbar=True)
>>> anim = animate_morph_history(cartogram, color_by="population", colorbar=True)
>>> # Single static array
>>> anim = animate_morph_history(cartogram, color_by=gdf["population"].values)
>>> # Per-snapshot arrays
>>> anim = animate_morph_history(cartogram, color_by=[snap.density for snap in cartogram.snapshots])

animate_velocity_field

animate_velocity_field(
    cartogram: Cartogram,
    *,
    duration: float = 5.0,
    fps: int = 15,
    interpolation: str = "nearest",
    position_mapper: PositionMapper | None = None,
    bounds: Any | None = None,
    velocity: Optional[VelocityPlotOptions] = None,
    show_axes: bool = True,
    title: str | bool | None = None,
    figsize: tuple[float, float] = (10, 8),
) -> FuncAnimation

Animate velocity field evolution. Convenience wrapper for animate_fields.

See animate_fields for full documentation.

animate_workflow

animate_workflow(
    workflow: CartogramWorkflow,
    duration: float = 8.0,
    fps: int = 15,
    interpolation: str = "linear",
    hold_at_keyframes: float = 0.5,
    color_by: str | ndarray | list | None = "errors_pct",
    cmap: str = "RdYlGn_r",
    vmin: float | None = None,
    vmax: float | None = None,
    colorbar: bool = True,
    colorbar_label: str | None = None,
    show_run_info: bool = True,
    show_axes: bool = True,
    colorbar_kwargs: dict | None = None,
    title: str | bool | None = None,
    precompute: bool = True,
    figsize: tuple[float, float] = (10, 8),
    **kwargs: Any,
) -> FuncAnimation

Animate through all cartograms in a workflow.

Shows smooth transitions from original through all morphing results, with optional hold time at each keyframe (final state of each run).

Parameters:

  • workflow (CartogramWorkflow) –

    Workflow containing cartogram results.

  • duration (float, default: 8.0 ) –

    Total animation duration in seconds.

  • fps (int, default: 15 ) –

    Frames per second.

  • interpolation (str, default: "linear" ) –

    Interpolation between keyframes: "nearest" or "linear".

  • hold_at_keyframes (float, default: 0.5 ) –

    Seconds to pause at each cartogram's final state.

  • color_by (str, array, list, or None, default: "errors_pct" ) –

    What to use for coloring geometries. Accepted values:

    • "errors_pct" (default): per-geometry percentage error from each cartogram's get_errors().errors_pct.
    • "density": per-geometry density from each cartogram's get_density().
    • "original": static values from the column used to build the cartogram (requires _value_column + _source_gdf; set automatically by CartogramWorkflow).
    • Any other str: column looked up in _source_gdf for every cartogram (raises ValueError if not found).
    • np.ndarray: single array broadcast to every keyframe.
    • list of arrays: one array per cartogram in the workflow.
    • None: no coloring.
  • cmap (str, default: "RdYlGn_r" ) –

    Colormap for coloring geometries.

  • vmin (float, default: None ) –

    Minimum value for color scale. If None, computed from all values.

  • vmax (float, default: None ) –

    Maximum value for color scale. If None, computed from all values.

  • colorbar (bool, default: True ) –

    Whether to show a colorbar.

  • colorbar_label (str, default: None ) –

    Label for the colorbar. Auto-set from color_by if not provided.

  • show_run_info (bool, default: True ) –

    Show "Run X/N" in title during animation.

  • show_axes (bool, default: True ) –

    If False, hides the axes frame, ticks, and labels (ax.axis("off")). Useful for clean map-style animations.

  • colorbar_kwargs (dict, default: None ) –

    Additional keyword arguments passed to fig.colorbar(). Example: dict(shrink=0.8, pad=0.02). The "label" key overrides the auto-set label.

  • title (str, bool, or None, default: None ) –

    Controls the axes title each frame.

    • None: auto-title (uses show_run_info logic).
    • False or "": no title.
    • str: format-string expanded each frame. Available keys: {run} (0-based keyframe index), {n_runs}, {t} (elapsed seconds), {duration} (total seconds), {iteration}, {n_iterations}, {mean_error}, {max_error}, {mean_error_pct}, {max_error_pct}.
  • precompute (bool, default: True ) –

    If True, all frames are computed before the animation starts. Eliminates per-frame geometry interpolation and GeoDataFrame copying, giving a significant speedup especially for interpolation="linear". Set to False to reduce peak memory usage for very long animations.

  • figsize (tuple, default: (10, 8) ) –

    Figure size (width, height).

  • **kwargs (Any, default: {} ) –

    Additional arguments passed to GeoDataFrame.plot().

Returns:

  • FuncAnimation

    Matplotlib animation object.

Examples:

>>> workflow = CartogramWorkflow(gdf, 'population')
>>> workflow.morph_multiresolution(levels=3)
>>> anim = animate_workflow(workflow, duration=10.0)
>>> save_animation(anim, "workflow.gif")
>>> # Color by density with custom colormap
>>> anim = animate_workflow(workflow, color_by="density", cmap="viridis")
>>> # No coloring, just geometry transitions
>>> anim = animate_workflow(workflow, color_by=None)

animate_workflow_fields

animate_workflow_fields(
    workflow: CartogramWorkflow,
    *,
    duration: float = 8.0,
    fps: int = 15,
    interpolation: str = "nearest",
    bounds: Any | None = None,
    show_density: bool = True,
    show_velocity: bool = False,
    density: Optional[DensityPlotOptions] = None,
    velocity: Optional[VelocityPlotOptions] = None,
    show_axes: bool = True,
    title: str | bool | None = None,
    figsize: tuple[float, float] = (10, 8),
) -> FuncAnimation

Animate density and/or velocity fields across all cartograms in a workflow.

Shows how the fields evolve through multiple morphing runs. Each run displays at its native grid resolution, allowing visualization of multi-resolution workflows where grid detail increases progressively.

Parameters:

  • workflow (CartogramWorkflow) –

    Workflow containing cartogram results with internals (requires save_internals=True in MorphOptions for each run).

  • duration (float, default: 8.0 ) –

    Animation duration in seconds.

  • fps (int, default: 15 ) –

    Frames per second.

  • interpolation (str, default: "nearest" ) –

    Interpolation method: "nearest" or "linear".

  • bounds (str, float, or tuple, default: None ) –

    Clip view to specified bounds (same as animate_fields).

  • show_density (bool, default: True ) –

    Whether to show density field heatmap.

  • show_velocity (bool, default: False ) –

    Whether to show velocity field arrows.

  • density (DensityPlotOptions, default: None ) –

    Rendering options for the density field. Defaults to DensityPlotOptions(normalize="ratio") for workflow animations. See :class:~carto_flow.flow_cartogram.visualization.DensityPlotOptions.

  • velocity (VelocityPlotOptions, default: None ) –

    Rendering options for the velocity field. See :class:~carto_flow.flow_cartogram.visualization.VelocityPlotOptions.

  • show_axes (bool, default: True ) –

    If False, hides the axes frame, ticks, and labels (ax.axis("off")). Useful for clean map-style animations.

  • title (str, bool, or None, default: None ) –

    Controls the axes title each frame.

    • None: auto-title ("Density Field (Run X/N, iter Y)").
    • False or "": no title.
    • str: format-string expanded each frame. Available keys: {iteration}, {run} (0-based), {n_runs}, {field} (e.g. "Density Field"), {t}.
  • figsize (tuple, default: (10, 8) ) –

    Figure size (width, height).

Returns:

  • FuncAnimation

    Matplotlib animation object.

Examples:

>>> from carto_flow.flow_cartogram.visualization import DensityPlotOptions, VelocityPlotOptions
>>> workflow = CartogramWorkflow(gdf, 'population')
>>> workflow.morph(options=MorphOptions(save_internals=True))
>>> workflow.morph(options=MorphOptions(save_internals=True))
>>> anim = animate_workflow_fields(workflow, density=DensityPlotOptions(normalize="ratio"))
>>> save_animation(anim, "workflow_fields.gif")
>>> # Show velocity overlaid on density
>>> anim = animate_workflow_fields(
...     workflow, show_velocity=True,
...     density=DensityPlotOptions(normalize="ratio"),
...     velocity=VelocityPlotOptions(color="black", alpha_by_magnitude=True),
... )

linear_over

linear_over(
    key_or_values: str | ndarray,
    decreasing: bool | None = None,
) -> PositionMapper

Create a position mapper that linearizes animation progress over values.

This factory creates a position mapper where animation progress [0, 1] maps linearly to the specified values. Use this to control which variable determines animation pacing.

Parameters:

  • key_or_values (str or array) –
    • str: Variable name to extract from the variables dict. Common keys for animate_morph_history: "iteration", "mean_error", "max_error" Common keys for animate_geometry_keyframes: "index", "time"
    • array: Values to linearize over directly
  • decreasing (bool, default: None ) –

    Whether values decrease over time (e.g., error values). If None (default), auto-detected: True for keys containing "error", False otherwise.

Returns:

  • PositionMapper

    Position mapper function with signature (progress, variables) -> position

Examples:

>>> # Linearize over iteration (default for morph_history)
>>> anim = animate_morph_history(result, position_mapper=linear_over("iteration"))
>>> # Linearize over mean error
>>> anim = animate_morph_history(result, position_mapper=linear_over("mean_error"))
>>> # Linearize over max error
>>> anim = animate_morph_history(result, position_mapper=linear_over("max_error"))
>>> # Custom values
>>> times = np.array([0, 0.2, 0.5, 1.0])
>>> anim = animate_geometry_keyframes(keyframes, position_mapper=linear_over(times))

save_animation

save_animation(
    anim: FuncAnimation,
    path: str | Path,
    fps: int = 15,
    dpi: int = 100,
    **kwargs: Any,
) -> None

Save an animation to file.

Parameters:

  • anim (FuncAnimation) –

    Animation object to save

  • path (str or Path) –

    Output path. Format determined by extension: - .gif: Uses pillow writer - .mp4: Uses ffmpeg writer - Directory path: Saves individual PNG frames

  • fps (int, default: 15 ) –

    Frames per second

  • dpi (int, default: 100 ) –

    Resolution in dots per inch

  • **kwargs (Any, default: {} ) –

    Additional arguments passed to the writer

Raises:

  • ValueError

    If the output format is not supported or required writer is unavailable

weights_to_position_mapper

weights_to_position_mapper(
    weight_fn: Callable[[dict[str, ndarray]], ndarray],
) -> PositionMapper

Convert a weight-based function to a position mapper.

This allows users to define mappers using the simpler weight-based interface (where higher weight = more time at that snapshot) while using the unified position mapper internally.

Parameters:

  • weight_fn (callable) –

    Function with signature (variables: dict) -> weights array. Higher weights mean more animation time allocated to that item.

Returns:

  • PositionMapper

    Position mapper function with signature (progress, variables) -> position

Examples:

>>> def slow_at_changes(variables):
...     errors = variables["mean_error"]
...     d_error = np.abs(np.gradient(errors))
...     return 1 + 5 * (d_error / d_error.max())
>>>
>>> anim = animate_morph_history(
...     result,
...     position_mapper=weights_to_position_mapper(slow_at_changes)
... )