base_plotter Module#

Abstract base class and configuration for all Episia plotters.

This module defines the contract that every rendering backend must satisfy, as well as configuration classes for plots and animations.

Classes#

Animation#

class episia.viz.plotters.base_plotter.AnimationType(value)[source]#

Bases: Enum

Animation types supported across backends.

FRAME_BY_FRAME discrete frames (e.g. day-by-day epidemic curve buildup). CONTINUOUS smooth interpolated transition (e.g. model trajectory). SLIDER interactive parameter slider (Plotly only). PLAY_PAUSE auto-play with play/pause button (Plotly / Browser). LOOP continuous loop, no controls (Matplotlib FuncAnimation).

CONTINUOUS = 'continuous'#
FRAME_BY_FRAME = 'frame_by_frame'#
LOOP = 'loop'#
PLAY_PAUSE = 'play_pause'#
SLIDER = 'slider'#
class episia.viz.plotters.base_plotter.AnimationConfig(enabled=False, anim_type=AnimationType.PLAY_PAUSE, duration_ms=3000, frame_ms=50, transition_ms=30, loop=True, show_controls=True, easing='cubic-in-out', fps=25, MAX_ANIMATION_FRAMES=60)[source]#

Bases: object

Configuration for animated plots.

Parameters:
enabled#

Whether animation is active.

Type:

bool

anim_type#

AnimationType how frames are driven.

Type:

episia.viz.plotters.base_plotter.AnimationType

duration_ms#

Total animation duration in milliseconds.

Type:

int

frame_ms#

Duration of each frame in milliseconds.

Type:

int

transition_ms#

Transition time between frames (Plotly).

Type:

int

loop#

Whether the animation loops automatically.

Type:

bool

show_controls#

Show play/pause/slider controls in the output.

Type:

bool

easing#

CSS/Plotly easing function for transitions.

Type:

str

fps#

Frames per second (Matplotlib backend).

Type:

int

MAX_ANIMATION_FRAMES: int = 60#
__init__(enabled=False, anim_type=AnimationType.PLAY_PAUSE, duration_ms=3000, frame_ms=50, transition_ms=30, loop=True, show_controls=True, easing='cubic-in-out', fps=25, MAX_ANIMATION_FRAMES=60)#
Parameters:
Return type:

None

anim_type: AnimationType = 'play_pause'#
classmethod default()[source]#

Return a sensible default config (disabled).

Return type:

AnimationConfig

duration_ms: int = 3000#
easing: str = 'cubic-in-out'#
enabled: bool = False#
fps: int = 25#
classmethod frame_buildup(n_frames, total_ms=5000)[source]#

Frame-by-frame buildup — good for epidemic curves / time-series.

Automatically downsamples to at most MAX_ANIMATION_FRAMES (60) frames so the animation stays smooth regardless of how many data points the model produced. A 365-day SEIR run at 10 pts/day = 3 650 points is reduced to 60 evenly-spaced frames.

Parameters:
  • n_frames (int)

  • total_ms (int)

Return type:

AnimationConfig

frame_ms: int = 50#
classmethod interactive_slider()[source]#

Interactive parameter slider Plotly only.

Return type:

AnimationConfig

loop: bool = True#
show_controls: bool = True#
classmethod smooth(duration_ms=4000)[source]#

Smooth continuous animation good for model trajectories.

Parameters:

duration_ms (int)

Return type:

AnimationConfig

transition_ms: int = 30#
exception episia.viz.plotters.base_plotter.UnsupportedAnimationError[source]#

Bases: NotImplementedError

Raised when a backend does not support the requested animation type.

Plot Configuration#

class episia.viz.plotters.base_plotter.PlotConfig(title='', subtitle='', xlabel='', ylabel='', width=800, height=500, theme='scientific', palette=None, show_grid=True, show_legend=True, font_size=13, confidence=0.95, animation=<factory>, extra=<factory>)[source]#

Bases: object

Unified plot configuration passed to every plot method.

Parameters:
title#

Figure title.

Type:

str

subtitle#

Optional subtitle (rendered below title).

Type:

str

xlabel#

X-axis label.

Type:

str

ylabel#

Y-axis label.

Type:

str

width#

Figure width in pixels (Plotly) or inches (Matplotlib).

Type:

int

height#

Figure height in pixels (Plotly) or inches (Matplotlib).

Type:

int

theme#

Theme name ‘scientific’, ‘minimal’, ‘dark’, ‘colorblind’.

Type:

str

palette#

List of hex color strings to use in sequence.

Type:

List[str] | None

show_grid#

Whether to show grid lines.

Type:

bool

show_legend#

Whether to show the legend.

Type:

bool

font_size#

Base font size.

Type:

int

confidence#

Confidence level for CI bands (e.g. 0.95).

Type:

float

animation#

AnimationConfig object.

Type:

episia.viz.plotters.base_plotter.AnimationConfig

extra#

Backend-specific kwargs forwarded as-is.

Type:

Dict[str, Any]

__init__(title='', subtitle='', xlabel='', ylabel='', width=800, height=500, theme='scientific', palette=None, show_grid=True, show_legend=True, font_size=13, confidence=0.95, animation=<factory>, extra=<factory>)#
Parameters:
Return type:

None

animation: AnimationConfig#
confidence: float = 0.95#
classmethod dark(title='', **kwargs)[source]#
Parameters:

title (str)

Return type:

PlotConfig

extra: Dict[str, Any]#
font_size: int = 13#
height: int = 500#
classmethod minimal(title='', **kwargs)[source]#
Parameters:

title (str)

Return type:

PlotConfig

palette: List[str] | None = None#
classmethod publication(title='', **kwargs)[source]#

Suitable for paper figures no grid, serif fonts, high contrast.

Parameters:

title (str)

Return type:

PlotConfig

show_grid: bool = True#
show_legend: bool = True#
subtitle: str = ''#
theme: str = 'scientific'#
title: str = ''#
width: int = 800#
xlabel: str = ''#
ylabel: str = ''#

Output Format#

class episia.viz.plotters.base_plotter.OutputFormat(value)[source]#

Bases: Enum

Output format when saving or exporting a figure.

GIF = 'gif'#
HTML = 'html'#
JSON = 'json'#
MP4 = 'mp4'#
PDF = 'pdf'#
PNG = 'png'#
SVG = 'svg'#

Base Plotter#

class episia.viz.plotters.base_plotter.BasePlotter(config=None)[source]#

Bases: ABC

Abstract base class for Episia rendering backends.

Subclasses implement each plot_* method for their engine. The constructor accepts a PlotConfig that sets defaults for every figure produced by this instance.

Usage:

plotter = PlotlyPlotter(config=PlotConfig(theme="dark"))
fig = plotter.plot_epicurve(result, config=PlotConfig(title="Ebola 2014"))
Parameters:

config (Optional[PlotConfig])

BACKEND_NAME: str = 'base'#

Human-readable backend name used in error messages.

SUPPORTED_ANIMATIONS: Tuple[AnimationType, ...] = ()#

AnimationTypes this backend can handle.

__init__(config=None)[source]#
Parameters:

config (PlotConfig | None)

abstract plot_association(result, config=None)[source]#

Plot a single association measure (RR / OR / RD) with CI.

No animation static by design.

Parameters:
  • result (Any) – AssociationResult.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

abstract plot_contingency(result, config=None)[source]#

Plot 2x2 contingency table with annotated cells and risk summary.

No animation static by design.

Parameters:
  • result (Any) – Table2x2 or AssociationResult with table metadata.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

abstract plot_diagnostic(result, config=None)[source]#

Plot diagnostic test performance dashboard (confusion matrix + metrics bar chart).

Supports animations:

FRAME_BY_FRAME metrics bars fill in sequence.

Parameters:
  • result (Any) – DiagnosticResult.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

abstract plot_epicurve(result, config=None)[source]#

Plot an epidemic curve (cases over time).

Supports animations:

FRAME_BY_FRAME bars build up day by day. PLAY_PAUSE auto-play buildup with controls.

Parameters:
  • result (Any) – TimeSeriesResult from stats.time_series.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

abstract plot_forest(result, config=None)[source]#

Plot forest plot for stratified or regression results.

Supports animations:

FRAME_BY_FRAME strata / variables appear one by one.

Parameters:
  • result (Any) – StratifiedResult or RegressionResult.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

abstract plot_model(result, config=None)[source]#

Plot compartmental model trajectories (SIR / SEIR / SEIRD).

Supports animations:

CONTINUOUS smooth line drawing from t=0 to t=end. PLAY_PAUSE play/pause controls over time axis. SLIDER interactive time slider (Plotly only).

Parameters:
  • result (Any) – ModelResult from models.sir / seir / seird.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

abstract plot_roc(result, config=None)[source]#

Plot ROC curve with AUC annotation.

Supports animations:

CONTINUOUS threshold sweeps from 0 to 1, tracing the curve.

Parameters:
  • result (Any) – ROCResult from stats.diagnostic.

  • config (PlotConfig | None) – Per-call PlotConfig.

Returns:

Native figure object.

Return type:

Any

save(fig, path, fmt=OutputFormat.PNG, dpi=150)[source]#

Save a figure to disk.

Default implementation raises NotImplementedError. Subclasses override as needed.

Parameters:
  • fig (Any) – Native figure object returned by a plot_* method.

  • path (str) – Destination file path (extension appended if missing).

  • fmt (OutputFormat) – OutputFormat enum value.

  • dpi (int) – Resolution for raster formats.

Returns:

Absolute path to the saved file.

Return type:

str

Examples#

Creating a plot configuration:

from episia.viz.plotters.base_plotter import PlotConfig, AnimationConfig

# Basic configuration
config = PlotConfig(
    title="COVID-19 Cases",
    xlabel="Date",
    ylabel="Count",
    width=1000,
    height=600,
    theme="scientific",
    show_grid=True
)

# Publication-ready configuration
pub_config = PlotConfig.publication(
    title="Figure 1: Epidemic Curve",
    width=700,
    height=450
)

# Animation configuration
anim_config = PlotConfig(
    title="Epidemic Progression",
    animation=AnimationConfig.frame_buildup(n_frames=52)
)

Using the base plotter:

from episia.viz.plotters.base_plotter import BasePlotter

class CustomPlotter(BasePlotter):
    BACKEND_NAME = "custom"
    SUPPORTED_ANIMATIONS = (AnimationType.FRAME_BY_FRAME,)

    def plot_epicurve(self, result, config=None):
        # Implementation here
        pass