# scope_profiler.plotting_scripts

*module*

Plotting utilities for visualizing profiling data using maxplotlib.

This package provides plotting functions that can export to both matplotlib
and plotly backends using maxplotlib as the unified interface. It is split
into one module per chart type; everything is re-exported here so
``scope_profiler.plotting_scripts`` keeps behaving like a single module for
callers and tests (including attribute-level monkeypatching).

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/__init__.py#L1-L1)

## scope_profiler.plotting_scripts.DEFAULT_CMAP

*attribute* · *module attribute*

```python
DEFAULT_CMAP = 'tab20'
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L154-L154)

## scope_profiler.plotting_scripts.FLAME_CMAP

*attribute* · *module attribute*

```python
FLAME_CMAP = 'inferno'
```

Re-exported from: `scope_profiler.plotting_scripts.flame`

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/flame.py#L24-L24)

## scope_profiler.plotting_scripts.plot_flame

*attribute* · *module attribute*

```python
plot_flame = plot_flame_chart
```

Re-exported from: `scope_profiler.plotting_scripts.flame`

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/flame.py#L555-L555)

## scope_profiler.plotting_scripts._add_pyvis_controls

*function*

```python
def _add_pyvis_controls(filepath: str | Path) -> None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Add lightweight search/focus/collapse controls to a PyVis document.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L91-L126)

## scope_profiler.plotting_scripts._aggregate_gantt_intervals

*function*

```python
def _aggregate_gantt_intervals(intervals: Sequence[tuple[float, float]], *, min_duration: float = 0.0, start_time: float | None = None, end_time: float | None = None, block_size: int = 1) -> list[tuple[float, float, int]]
```

Re-exported from: `scope_profiler.plotting_scripts.gantt`

Filter and optionally coalesce timeline intervals.

``start_time``/``end_time`` are relative to the plot origin. Intervals
crossing a window boundary are clipped. Coalescing preserves event order
and reports the number of calls represented by each returned bar.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/gantt.py#L148-L189)

## scope_profiler.plotting_scripts._as_runs

*function*

```python
def _as_runs(profiling_data: ProfilingResults | Sequence[ProfilingResults]) -> list[ProfilingResults]
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Normalize the input, dropping result sets this rank must not draw.

Under MPI only rank 0 holds the run's data; every other rank gets an empty,
non-root result set from ``finalize(return_results=True)``. Dropping those
here is what lets a parallel script call the plot functions and exporters
unguarded and still produce exactly one set of figures. An empty list back
therefore means "not this rank's job" - callers return quietly - while an
empty input is a mistake and raises.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L467-L484)

## scope_profiler.plotting_scripts._close_matplotlib_figure

*function*

```python
def _close_matplotlib_figure(canvas, fig=None) -> None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Release the figure maxplotlib keeps open after rendering.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L339-L346)

## scope_profiler.plotting_scripts._display_matplotlib_figure_in_notebook

*function*

```python
def _display_matplotlib_figure_in_notebook(fig) -> bool
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Use IPython rich display when running inside a Jupyter kernel.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L310-L325)

## scope_profiler.plotting_scripts._duration_timeseries

*function*

```python
def _duration_timeseries(region, ranks: list[int] | None, first_start_time: float) -> dict[str, np.ndarray] | None
```

Re-exported from: `scope_profiler.plotting_scripts.duration_timeseries`

Aggregate one region's calls over ranks into a duration-versus-time series.

Calls are matched across ranks by call index, so point ``i`` describes the
i-th call of the region on every rank that got that far. Ranks that stopped
calling the region earlier simply drop out of the later points, which keeps
ragged call counts (e.g. a rank-dependent number of iterations) usable.

Returns ``None`` if no selected rank recorded any call.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/duration_timeseries.py#L25-L78)

## scope_profiler.plotting_scripts._filename_slug

*function*

```python
def _filename_slug(label: str) -> str
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Make a label safe to paste into a filename.

Labels are free text and are used to name exported files, so a perfectly
reasonable one like ``"128 ranks"`` would otherwise produce
``profile_128 ranks_rank0.prof``. Only the path is sanitized; the label
inside the exported document stays as the user wrote it.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L487-L496)

## scope_profiler.plotting_scripts._get_canvas

*function*

```python
def _get_canvas()
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Get maxplotlib Canvas for plotting.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L141-L151)

## scope_profiler.plotting_scripts._get_cmap_colors

*function*

```python
def _get_cmap_colors(cmap: str, n_colors: int) -> list[str]
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Sample ``n_colors`` ``#rrggbb`` strings from a matplotlib colormap.

Hex strings (rather than RGBA tuples) are returned so the colors can be
handed to any maxplotlib backend unchanged.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L171-L186)

## scope_profiler.plotting_scripts._group_regions

*function*

```python
def _group_regions(region_names: list[str], combine_regions: dict[str, list[str] | str] | None) -> tuple[list[str], dict[str, list[str]]]
```

Re-exported from: `scope_profiler.plotting_scripts.durations`

Collapse regions matching a pattern into a single combined bar.

``combine_regions`` maps a display name (e.g. ``"setup"``) to one or more
regex patterns (matched the same way as ``include``); every region in
``region_names`` matching one of a group's patterns is pooled into a
single bar under that display name, in the position of its first match.
A region matching patterns from more than one group is claimed by
whichever group is listed first. Regions matching no group pass through
unchanged, one bar each.

Returns the ordered list of bar display names, plus a ``{display_name:
[member region names]}`` map used to pool each bar's underlying data.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/durations.py#L138-L192)

## scope_profiler.plotting_scripts._hover_region

*function*

```python
def _hover_region(region, ranks: list[int] | None, num_ranks: int | None = None)
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Pick the region object whose summary matches what is being plotted.

A plot restricted to a single rank should not describe itself with
statistics pooled over every rank, and ``MPIRegion[rank]`` is the same
``get_summary()`` one level down. ``num_ranks`` is the run's rank count,
which decides whether the title names the rank.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L289-L299)

## scope_profiler.plotting_scripts._hover_summary

*function*

```python
def _hover_summary(region, title: str | None = None, extra: Sequence[tuple[str, object]] = ()) -> str
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Render a region's own ``get_summary()`` as Plotly hover text.

Both :class:`~scope_profiler.region.Region` (one rank) and
:class:`~scope_profiler.mpi_region.MPIRegion` (pooled over ranks) expose
``get_summary()``, so hovering shows exactly the statistics that region
object reports - there is no second, parallel definition of "the usual
information" to keep in step with it.

``extra`` lines (the hovered call's own start and duration, a bar's
value, ...) are placed above the summary, since they are what identifies
the point being hovered.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L245-L275)

## scope_profiler.plotting_scripts._hover_value

*function*

```python
def _hover_value(key: str, value) -> str
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Format one ``get_summary()`` entry for the hover box.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L212-L218)

## scope_profiler.plotting_scripts._normalize_ranks

*function*

```python
def _normalize_ranks(ranks: list[int] | int | None) -> list[int] | None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L511-L518)

## scope_profiler.plotting_scripts._panel_gridspec

*function*

```python
def _panel_gridspec(fig_width: float, fig_height: float, label_chars: int, multi_panel: bool) -> dict
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Reserve figure margins for tick labels, axis labels and titles.

maxplotlib renders without ``tight_layout``, so long y-tick labels (region
names) and the x-axis label would otherwise be cut off at the figure edge.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L427-L447)

## scope_profiler.plotting_scripts._prepare_gantt_data

*function*

```python
def _prepare_gantt_data(profiling_data: ProfilingResults, ranks: list[int] | int | None, include: list[str] | str | None, exclude: list[str] | str | None) -> tuple[list, list[int], float]
```

Re-exported from: `scope_profiler.plotting_scripts.gantt`

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/gantt.py#L99-L125)

## scope_profiler.plotting_scripts._region_color_map

*function*

```python
def _region_color_map(region_names, cmap: str = DEFAULT_CMAP) -> dict
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Assign each region name a stable color from a canonical sorted order.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L460-L464)

## scope_profiler.plotting_scripts._region_summary

*function*

```python
def _region_summary(region) -> dict
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

A region's ``get_summary()``, minus what a broken call graph withholds.

``get_summary()`` reports exclusive time, which is reconstructed from
timestamp containment and therefore unavailable on a rank whose calls
are not properly nested. That is a reason to leave one line out of a
hover box, not to fail the plot.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L221-L242)

## scope_profiler.plotting_scripts._render

*function*

```python
def _render(canvas, filepath: str | None, show: bool, backend: str, plotly_layout: dict | None = None, x_tick_rotation: float | None = None, return_fig: bool = False, matplotlib_postprocess=None, plotly_postprocess=None) -> tuple[object, object] | object
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Save and/or display a canvas.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L349-L424)

## scope_profiler.plotting_scripts._save_matplotlib_figure

*function*

```python
def _save_matplotlib_figure(fig, canvas, filepath: str | Path) -> None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Save a materialized Matplotlib figure using canvas-level DPI if present.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L302-L307)

## scope_profiler.plotting_scripts._set_xticks

*function*

```python
def _set_xticks(canvas, ticks, labels=None, **kwargs) -> bool
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Set x ticks, returning whether optional tick-label kwargs were accepted.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L450-L457)

## scope_profiler.plotting_scripts._show_matplotlib_figure

*function*

```python
def _show_matplotlib_figure(fig) -> bool
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Display a Matplotlib figure in notebooks and regular Python sessions.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L328-L336)

## scope_profiler.plotting_scripts._stacked_segments

*function*

```python
def _stacked_segments(run: ProfilingResults, region_members: dict[str, list[str]], ranks: list[int] | None = None) -> dict[str, dict[str, float]]
```

Re-exported from: `scope_profiler.plotting_scripts.durations`

Split each bar's inclusive time into self time plus its direct children.

Regions record no call graph, so the nesting is reconstructed from
timestamp containment (:func:`~scope_profiler.call_stack.build_call_arrays`)
- the same call graph the flame chart draws, over *all* the run's
regions, not just the plotted ones, since a region filtered out of the
bars is still somebody's parent.

Every call is credited to the bar its parent belongs to. A call whose
parent is in the same bar (a recursive region, or two members of one
``combine_regions`` group nested in each other) is left in that bar's
self time rather than becoming a segment of itself, so a bar's segments
always sum to time spent inside it, counted once.

Returns ``{bar name: {segment label: total nanoseconds}}``, where the
``"self"`` segment is exclusive time and every other key is a child
region's name - its bar name when that child is itself a plotted bar.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/durations.py#L246-L321)

## scope_profiler.plotting_scripts._to_hex

*function*

```python
def _to_hex(color) -> str
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Convert a matplotlib color (e.g. an RGBA tuple) to a ``#rrggbb`` string.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L129-L138)

## scope_profiler.plotting_scripts._unique_labels

*function*

```python
def _unique_labels(labels: Sequence[str]) -> list[str]
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L499-L508)

## scope_profiler.plotting_scripts._write_csv

*function*

```python
def _write_csv(filepath: str | Path, header: Sequence[str], rows: Sequence[Sequence]) -> None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Write rows of plotting data to a plain-text CSV file.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L22-L33)

## scope_profiler.plotting_scripts._write_json

*function*

```python
def _write_json(filepath: str | Path, payload: dict, plot: str) -> None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Write the exact data behind a plot to a JSON file.

Every plot-data document carries the same envelope - ``format``,
``format_version`` and the ``plot`` kind that produced it - so a consumer
(e.g. the ``@scope-profiler/plotly`` package) can dispatch on the file
itself instead of guessing from its keys. Stamping it here rather than at
each call site is what keeps the envelope on every kind.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L65-L88)

## scope_profiler.plotting_scripts._write_parquet

*function*

```python
def _write_parquet(filepath: str | Path, header: Sequence[str], rows: Sequence[Sequence]) -> None
```

Re-exported from: `scope_profiler.plotting_scripts._utils`

Write the same rows ``_write_csv`` would to a columnar Parquet file.

Same tabular shape as the CSV export, for a caller that wants a typed,
columnar file to load with pandas/polars/DuckDB rather than parse a
delimited text file.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/_utils.py#L36-L62)

## scope_profiler.plotting_scripts.available_likwid_metrics

*function*

```python
def available_likwid_metrics(profiling_data: ProfilingResults | Sequence[ProfilingResults]) -> list[str]
```

Re-exported from: `scope_profiler.plotting_scripts.likwid`

List the LIKWID metric/event names available for :func:`plot_likwid`.

Union over every run, rank and region, in the order LIKWID reported them
(derived metrics first, then raw events) - so a caller who does not know
what a run measured can list the valid ``metric`` values before plotting.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/likwid.py#L24-L43)

## scope_profiler.plotting_scripts.available_perf_event_metrics

*function*

```python
def available_perf_event_metrics(profiling_data: ProfilingResults | Sequence[ProfilingResults]) -> list[str]
```

Re-exported from: `scope_profiler.plotting_scripts.perf_events`

List available raw events and valid derived perf-event ratios.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/perf_events.py#L31-L47)

## scope_profiler.plotting_scripts.collect_region_statistics

*function*

```python
def collect_region_statistics(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, labels: Sequence[str] | None = None) -> dict
```

Re-exported from: `scope_profiler.plotting_scripts.statistics`

Collect aggregate region-duration statistics for one or more profiling files.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/statistics.py#L206-L289)

## scope_profiler.plotting_scripts.collect_roofline_points

*function*

```python
def collect_roofline_points(profiling_data: ProfilingResults | Sequence[ProfilingResults], *, flops_metric: str | None = None, bandwidth_metric: str | None = None, ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None) -> list[dict]
```

Re-exported from: `scope_profiler.plotting_scripts.roofline`

Derive one roofline point per selected LIKWID region and rank.

``flops_metric`` and ``bandwidth_metric`` select exact LIKWID derived
metric names.  When omitted, the first names containing ``FLOP/s`` and
``bandwidth`` respectively are selected for each region.  Supplying exact
names is recommended when a group offers both single- and double-precision
FLOP rates.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/roofline.py#L94-L153)

## scope_profiler.plotting_scripts.plot_callgraph

*function*

```python
def plot_callgraph(profiling_data: ProfilingResults, rank: int = 0, include=None, exclude=None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False, compact: bool = False, fluid: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.callgraph`

Plot the explicit call graph, without using timestamps or durations.

When ``compact`` is true, all invocations of a region are represented by
one node named after that region.  Edges then describe distinct
caller/callee region relationships rather than individual call IDs.
``fluid`` applies a deterministic force-directed layout to the compact
graph, similar to an Obsidian-style node graph.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/callgraph.py#L22-L450)

## scope_profiler.plotting_scripts.plot_duration_histogram

*function*

```python
def plot_duration_histogram(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, bins: int = 30, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, log_scale: bool = False, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib') -> None
```

Re-exported from: `scope_profiler.plotting_scripts.histogram`

Plot each region's call-duration distribution as a frequency line.

One panel per file, one line per region, giving the count of calls
falling in each duration bin - so a region whose calls are mostly fast
with an occasional slow outlier shows up as a peak with a long tail,
something the mean/min/max in :func:`plot_durations` cannot distinguish
from a uniformly slower region.

Parameters
----------
bins : int
    Number of histogram bins spanning each file's observed duration
    range (default: 30). All regions in a panel share the same bin edges,
    so the curves are directly comparable.
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/histogram.py#L26-L202)

## scope_profiler.plotting_scripts.plot_duration_timeseries

*function*

```python
def plot_duration_timeseries(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, log_scale: bool = False, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> None
```

Re-exported from: `scope_profiler.plotting_scripts.duration_timeseries`

Plot each region's call duration over wall-clock time, with a min-max band.

One line per region tracks the mean duration over the ranks that recorded
each call, shaded between the minimum and maximum duration seen across
those ranks, so rank imbalance shows up as a widening band.

Parameters
----------
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".
return_fig : bool
    Return the rendered figure instead of the default ``None``. Matplotlib
    returns ``(fig, axes)``; Plotly returns its figure object.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/duration_timeseries.py#L81-L275)

## scope_profiler.plotting_scripts.plot_durations

*function*

```python
def plot_durations(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, labels: Sequence[str] | None = None, metric: str = 'total', metrics: Sequence[str] | None = None, sort_by: str | None = None, top_n: int | None = None, combine_regions: dict[str, list[str] | str] | None = None, stack_children: bool = False, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, log_scale: bool = False, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> list[str] | list[object] | object
```

Re-exported from: `scope_profiler.plotting_scripts.durations`

Plot duration bar charts for one or more profiling files using maxplotlib.

Parameters
----------
combine_regions : dict[str, list[str] | str], optional
    Merge several regions into a single bar, e.g. ``{"setup": ["setup:
    .*"]}`` combines every ``setup: ...`` region into one bar named
    "setup", pooling their calls the same way ``sort_by`` and the other
    duration statistics pool a single region's calls. Each value is one
    or more regex patterns (matched like ``include``); a region matching
    several groups is claimed by whichever group is listed first.
metric : str
    Duration metric to render (``avg``, ``min``, ``max``, ``total``,
    ``first`` or ``last``). ``first``/``last`` are the durations of the
    chronologically first and last call, which show how much of a
    region's cost is one-off warmup rather than steady state.
metrics : Sequence[str], optional
    Render several metrics instead of one. Each gets its own figure --
    ``filepath`` is suffixed with the metric name, as it always was for
    multiple metrics - but a single ``data_filepath`` holds them all,
    with the metric named per row, so one export can back a chart whose
    metric the viewer switches. Overrides ``metric`` when given.
stack_children : bool
    Split each bar into the region's own (exclusive) time plus one
    segment per region called directly from it, stacked on top of each
    other, so a bar shows where its time went instead of only how much
    there was. The nesting comes from timestamp containment, the same
    reconstruction the flame chart uses, over every region in the run --
    a child that is filtered out of the bars still gets its own segment.
    Only ``total`` and ``avg`` decompose this way; ``min``/``max`` are
    rejected. Colors then identify segments rather than runs, so with
    several runs the bars are still grouped per region in run order but
    the legend names the segments.
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".
return_fig : bool
    Return the rendered figure instead of the saved filepath list.

Returns
-------
list[str]
    List of filepaths that were written (empty if filepath is None).
    With ``return_fig``, the rendered figure, or the list of figures
    when several metrics were requested.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/durations.py#L379-L763)

## scope_profiler.plotting_scripts.plot_flame_chart

*function*

```python
def plot_flame_chart(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = FLAME_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.flame`

Plot a flame chart reconstructing the call stack from region timings.

Parameters
----------
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".
return_fig : bool
    Return the rendered figure instead of the default ``None``. Matplotlib
    returns ``(fig, axes)``; Plotly returns its figure object.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/flame.py#L32-L330)

## scope_profiler.plotting_scripts.plot_flame_graph

*function*

```python
def plot_flame_graph(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = FLAME_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.flame`

Plot an aggregated flame graph whose x-axis represents total time.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/flame.py#L400-L551)

## scope_profiler.plotting_scripts.plot_gantt

*function*

```python
def plot_gantt(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False, min_duration: float = 0.0, start_time: float | None = None, end_time: float | None = None, aggregate_calls: int = 1, collapse_depth: int | None = None) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.gantt`

Plot a Gantt chart of all (or selected) regions with per-rank lanes using maxplotlib.

Parameters
----------
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".
return_fig : bool
    Return the rendered figure instead of the default ``None``. Matplotlib
    returns ``(fig, axes)``; Plotly returns its figure object.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/gantt.py#L192-L468)

## scope_profiler.plotting_scripts.plot_imbalance

*function*

```python
def plot_imbalance(profiling_data: ProfilingResults | Sequence[ProfilingResults], metric: str = 'total', ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, log_scale: bool = False, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib') -> None
```

Re-exported from: `scope_profiler.plotting_scripts.imbalance`

Plot each region's duration statistic per rank, to surface load imbalance.

One point per (region, rank), connected by a line in rank order, with a
dashed horizontal line at the mean over ranks - so a straggler rank shows
up as a point sitting well off its region's line. This is a per-rank view
of the same statistics :func:`plot_durations` aggregates across ranks.

Parameters
----------
metric : str
    Which per-call duration statistic to plot per rank; one of
    ``"avg"``, ``"min"``, ``"max"``, ``"total"`` (default: ``"total"``,
    the total time a rank spent in the region).
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/imbalance.py#L27-L222)

## scope_profiler.plotting_scripts.plot_likwid

*function*

```python
def plot_likwid(profiling_data: ProfilingResults | Sequence[ProfilingResults], metric: str, ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, labels: Sequence[str] | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, log_scale: bool = False, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib') -> None
```

Re-exported from: `scope_profiler.plotting_scripts.likwid`

Plot one LIKWID derived metric or raw event, grouped by region and rank.

LIKWID counters are otherwise only visible as text tables
(:func:`~scope_profiler.summary.print_likwid_tables`); this gives the same
numbers a bar chart, one group of bars per region and one bar per rank, so
a metric like memory bandwidth or CPI can be compared across regions (or
across files, for a single rank) the same way :func:`plot_durations`
compares timings.

Parameters
----------
metric : str
    Name of a LIKWID derived metric (e.g. ``"CPI"``) or raw event/event
    label (e.g. ``"CAS_COUNT_RD"``). See :func:`available_likwid_metrics`
    for the names a run actually recorded.
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/likwid.py#L87-L252)

## scope_profiler.plotting_scripts.plot_perf_events

*function*

```python
def plot_perf_events(profiling_data: ProfilingResults | Sequence[ProfilingResults], metric: str = 'ipc', ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, labels: Sequence[str] | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, backend: str = 'matplotlib') -> None
```

Re-exported from: `scope_profiler.plotting_scripts.perf_events`

Plot one raw perf event or derived ratio for every region and rank.

``metric`` may be an event name recorded in the run, ``"ipc"``
(instructions/cycle), or ``"cache-misses-per-ki"``. Derived metrics are
calculated from the region's aggregated counters, not averages of call
ratios, which preserves their proper weighting.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/perf_events.py#L62-L149)

## scope_profiler.plotting_scripts.plot_rank_heatmap

*function*

```python
def plot_rank_heatmap(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = 'viridis', data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False, exclusive: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.heatmap`

Plot total or exclusive region time as a rank-by-region heatmap.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/heatmap.py#L21-L164)

## scope_profiler.plotting_scripts.plot_roofline

*function*

```python
def plot_roofline(profiling_data: ProfilingResults | Sequence[ProfilingResults], *, flops_metric: str | None = None, bandwidth_metric: str | None = None, peak_flops: float | None = None, peak_bandwidth: float | None = None, ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib') -> dict
```

Re-exported from: `scope_profiler.plotting_scripts.roofline`

Plot attained performance against arithmetic intensity for LIKWID regions.

``peak_flops`` (GFLOP/s) and ``peak_bandwidth`` (GB/s) should be measured
hardware ceilings for a true roofline.  If either is absent, the largest
selected observation supplies that ceiling and the plot labels it
*empirical*; it is useful for comparing regions but must not be read as a
machine limit.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/roofline.py#L187-L301)

## scope_profiler.plotting_scripts.plot_scaling_efficiency

*function*

```python
def plot_scaling_efficiency(profiling_data: ProfilingResults | Sequence[ProfilingResults], x_field: str = 'num_ranks', ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.scaling`

Plot parallel scaling efficiency (measured speedup / ideal speedup).

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/scaling.py#L610-L743)

## scope_profiler.plotting_scripts.plot_speedup

*function*

```python
def plot_speedup(profiling_data: ProfilingResults | Sequence[ProfilingResults], x_field: str = 'num_ranks', ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.scaling`

Plot scope speedup versus a chosen parallelism/metadata field using maxplotlib.

Parameters
----------
backend : str
    Backend to use for rendering: "matplotlib" (default) or "plotly".

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/scaling.py#L84-L266)

## scope_profiler.plotting_scripts.plot_timeline_density

*function*

```python
def plot_timeline_density(profiling_data: ProfilingResults | Sequence[ProfilingResults], ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = 'magma', bins: int = 200, start_time: float | None = None, end_time: float | None = None, min_duration: float = 0.0, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.timeline`

Plot binned region occupancy instead of individual timeline bars.

Each cell contains the seconds of a region overlapping that time bin.
This is intentionally an aggregate visualization: it remains readable
when a run contains millions of short calls.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/timeline.py#L20-L159)

## scope_profiler.plotting_scripts.plot_weak_scaling

*function*

```python
def plot_weak_scaling(profiling_data: ProfilingResults | Sequence[ProfilingResults], x_field: str = 'num_ranks', ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.scaling`

Plot weak-scaling runtime versus a chosen parallelism/metadata field.

Runtime is normalized to the smallest scale, so ideal weak scaling is a
horizontal line at 1.0. Lower values are not inherently better here: the
useful signal is how closely each region stays near that line.

See :func:`plot_weak_scaling_efficiency` for the same data read as a
fraction of ideal instead.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/scaling.py#L489-L528)

## scope_profiler.plotting_scripts.plot_weak_scaling_efficiency

*function*

```python
def plot_weak_scaling_efficiency(profiling_data: ProfilingResults | Sequence[ProfilingResults], x_field: str = 'num_ranks', ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, work_per_rank: Sequence[float] | None = None, filepath: str | None = None, show: bool = False, verbose: bool = True, cmap: str = DEFAULT_CMAP, data_filepath: str | Path | None = None, data_format: str = 'csv', backend: str = 'matplotlib', return_fig: bool = False) -> object | None
```

Re-exported from: `scope_profiler.plotting_scripts.scaling`

Plot weak-scaling efficiency: baseline runtime over runtime at each scale.

A weak-scaling study grows the problem with the machine, so every run
does the same work per rank and ideal efficiency is a flat 1.0. A region
at 0.6 on 64 ranks is spending 40% of its time on costs that only appear
at that scale - communication, load imbalance, or contention.

This differs from :func:`plot_scaling_efficiency`, which is for a
*strong*-scaling study: there the problem size is fixed, so the ideal is
a speedup proportional to the rank count and efficiency divides the
measured speedup by that. Here the ideal is constant runtime, so no such
division applies - using the strong-scaling plot on weak-scaling runs
reports a near-zero efficiency that means nothing.

Parameters
----------
work_per_rank : Sequence[float], optional
    Work per rank for each profiling run, in whatever unit suits the
    problem (grid cells, particles, unknowns). Only the caller can know
    this - it is a property of the problem, not of the profile - so it
    is optional, but when given it is checked: the runs must agree, and
    a mismatch raises rather than plotting an efficiency that silently
    compares runs doing different amounts of work. The value is recorded
    in the exported plot data.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/scaling.py#L531-L607)

## scope_profiler.plotting_scripts.write_region_statistics_json

*function*

```python
def write_region_statistics_json(profiling_data: ProfilingResults | Sequence[ProfilingResults], filepath: str | Path, ranks: list[int] | int | None = None, include: list[str] | str | None = None, exclude: list[str] | str | None = None, labels: Sequence[str] | None = None) -> dict
```

Re-exported from: `scope_profiler.plotting_scripts.statistics`

Write aggregate region-duration statistics to a JSON file.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/plotting_scripts/statistics.py#L292-L312)

**Modules**

- `scope_profiler.plotting_scripts.callgraph`
- `scope_profiler.plotting_scripts.duration_timeseries`
- `scope_profiler.plotting_scripts.durations`
- `scope_profiler.plotting_scripts.flame`
- `scope_profiler.plotting_scripts.gantt`
- `scope_profiler.plotting_scripts.heatmap`
- `scope_profiler.plotting_scripts.histogram`
- `scope_profiler.plotting_scripts.imbalance`
- `scope_profiler.plotting_scripts.likwid`
- `scope_profiler.plotting_scripts.perf_events`
- `scope_profiler.plotting_scripts.roofline`
- `scope_profiler.plotting_scripts.scaling`
- `scope_profiler.plotting_scripts.statistics`
- `scope_profiler.plotting_scripts.timeline`
