Skip to content

Visualization Layers

This module provides a system of layer classes that implement different visualization techniques for ISO plots. Each layer encapsulates a specific visualization method and knows how to render itself on a given context.

Layer-based visualization components for plotting.

This module provides a system of layer classes that implement different visualization techniques for ISO plots. Each layer encapsulates a specific visualization method and knows how to render itself on a given context.

CLASS DESCRIPTION
DensityLayer

Layer for rendering kernel density plots.

Layer

Base class for all visualization layers.

SPIDensityLayer

Layer for rendering simplified SPI plots with fewer contour levels.

SPILayer

Layer for rendering SPI plots.

SPIScatterLayer

Layer for rendering simplified SPI plots with fewer contour levels.

SPISimpleLayer

Layer for rendering simplified SPI plots with fewer contour levels.

ScatterLayer

Layer for rendering scatter plots.

SimpleDensityLayer

Layer for rendering simplified density plots with fewer contour levels.

DensityLayer

DensityLayer(custom_data=None, *, param_model=DensityParams, include_outline=False, **params)

Bases: Layer

Layer for rendering kernel density plots.

Initialize a DensityLayer.

PARAMETER DESCRIPTION
custom_data

Optional custom data for this specific layer

TYPE: DataFrame | None DEFAULT: None

include_outline

Whether to include an outline around the density plot

TYPE: bool DEFAULT: False

**params

Parameters for the density plot

TYPE: dict DEFAULT: {}

Source code in soundscapy/plotting/layers.py
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
def __init__(
    self,
    custom_data: pd.DataFrame | None = None,
    *,
    param_model: type[DensityParams] = DensityParams,
    include_outline: bool = False,
    **params: Any,
) -> None:
    """
    Initialize a DensityLayer.

    Parameters
    ----------
    custom_data : pd.DataFrame | None
        Optional custom data for this specific layer
    include_outline : bool
        Whether to include an outline around the density plot
    **params : dict
        Parameters for the density plot

    """
    self.include_outline = include_outline
    self.params: DensityParams
    super().__init__(custom_data=custom_data, param_model=param_model, **params)

Layer

Layer(custom_data=None, param_model=SeabornParams, **params)

Base class for all visualization layers.

A Layer encapsulates a specific visualization technique and its associated parameters. Layers know how to render themselves onto a PlotContext's axes.

ATTRIBUTE DESCRIPTION
custom_data

Optional custom data for this specific layer, overriding context data

TYPE: DataFrame | None

params

Parameter model instance for this layer

TYPE: ParamModel

Initialize a Layer.

PARAMETER DESCRIPTION
custom_data

Optional custom data for this specific layer, overriding context data

TYPE: DataFrame | None DEFAULT: None

param_model

The parameter model class to use, if None uses a generic ParamModel

TYPE: type[ParamModel] | None DEFAULT: SeabornParams

**params

Parameters for the layer

TYPE: dict DEFAULT: {}

METHOD DESCRIPTION
render

Render this layer on the given context.

Source code in soundscapy/plotting/layers.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def __init__(
    self,
    custom_data: pd.DataFrame | None = None,
    param_model: type[SeabornParams] = SeabornParams,
    **params: Any,
) -> None:
    """
    Initialize a Layer.

    Parameters
    ----------
    custom_data : pd.DataFrame | None
        Optional custom data for this specific layer, overriding context data
    param_model : type[ParamModel] | None
        The parameter model class to use, if None uses a generic ParamModel
    **params : dict
        Parameters for the layer

    """
    self.custom_data = custom_data
    # Create parameter model instance
    self.params = param_model(**params)

render

render(context)

Render this layer on the given context.

PARAMETER DESCRIPTION
context

The context containing data and axes for rendering

TYPE: PlotContext

Source code in soundscapy/plotting/layers.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def render(self, context: PlotContext) -> None:
    """
    Render this layer on the given context.

    Parameters
    ----------
    context : PlotContext
        The context containing data and axes for rendering

    """
    if context.ax is None:
        msg = "Cannot render layer: context has no associated axes"
        raise ValueError(msg)

    # Use custom data if provided, otherwise context data
    data = self.custom_data if self.custom_data is not None else context.data

    if data is None:
        msg = "No data available for rendering layer"
        raise ValueError(msg)

    self._render_implementation(data, context, context.ax)

SPIDensityLayer

SPIDensityLayer()

Bases: SPILayer, DensityLayer

Layer for rendering simplified SPI plots with fewer contour levels.

Initialize SPIDensityLayer.

This initialization is not supported and will raise NotImplementedError. Use SPISimpleLayer instead.

Source code in soundscapy/plotting/layers.py
686
687
688
689
690
691
692
693
694
695
696
697
def __init__(self) -> None:
    """
    Initialize SPIDensityLayer.

    This initialization is not supported and will raise NotImplementedError.
    Use SPISimpleLayer instead.
    """
    msg = (
        "Only the simple density layer type is currently supported for SPI plots. "
        "Please use SPISimpleLayer"
    )
    raise NotImplementedError(msg)

SPILayer

SPILayer(spi_target_data=None, *, msn_params=None, n=10000, param_model=SPISeabornParams, **params)

Bases: Layer

Layer for rendering SPI plots.

Initialize an SPILayer.

PARAMETER DESCRIPTION
spi_target_data

Pre-sampled data for SPI target distribution. When None, msn_params must be provided.

TYPE: DataFrame | ndarray | None DEFAULT: None

msn_params

Parameters to generate SPI data if no spi_target_data is provided

TYPE: DirectParams | CentredParams | None DEFAULT: None

n

Number of samples to generate if using msn_params

TYPE: int DEFAULT: 10000

param_model

The parameter model class to use

TYPE: type[SPISeabornParams] DEFAULT: SPISeabornParams

**params

Parameters for the layer. For compatibility with other layers, if 'custom_data' is present and spi_target_data is None, custom_data will be used as the SPI target data.

TYPE: dict DEFAULT: {}

Notes

Either spi_target_data or msn_params must be provided, but not both. The test data for SPI calculations will be retrieved from the plot context.

METHOD DESCRIPTION
render

Render this layer on the given context.

show_score

Show the SPI score on the plot.

Source code in soundscapy/plotting/layers.py
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def __init__(
    self,
    spi_target_data: pd.DataFrame | np.ndarray | None = None,
    *,
    # TODO(MitchellAcoustics): Allow passing raw param values,  # noqa: TD003
    #  not just Param objects
    msn_params: DirectParams | CentredParams | None = None,
    n: int = 10000,
    param_model: type[SPISeabornParams] = SPISeabornParams,
    **params: Any,
) -> None:
    """
    Initialize an SPILayer.

    Parameters
    ----------
    spi_target_data : pd.DataFrame | np.ndarray | None
        Pre-sampled data for SPI target distribution.
        When None, msn_params must be provided.
    msn_params : DirectParams | CentredParams | None
        Parameters to generate SPI data if no spi_target_data is provided
    n : int
        Number of samples to generate if using msn_params
    param_model : type[SPISeabornParams]
        The parameter model class to use
    **params : dict
        Parameters for the layer. For compatibility with other layers,
        if 'custom_data' is present and spi_target_data is None,
        custom_data will be used as the SPI target data.

    Notes
    -----
    Either spi_target_data or msn_params must be provided, but not both.
    The test data for SPI calculations will be retrieved from the plot context.

    """
    # The custom_data passed when adding this layer should be the spi_data.
    # We will retrieve the test_data from the subplot context, so real data layers
    # need to be passed before this one, or use the data from the
    # main ISOPlot context
    custom_data = params.pop("custom_data", None)
    if custom_data is not None and spi_target_data is None:
        logger.warning(
            "`spi_target_data` not found, but `custom_data` was found. "
            "Using `custom_data` as the SPI target data. "
            "\nNote: Passing the SPI data to `spi_target_data` is preferred."
        )
        spi_target_data = custom_data

    # Check that we have the information needed to generate SPI target data
    # (either the spi_data or msn_params)
    spi_target_data, self.spi_params = self._validate_spi_inputs(
        spi_target_data, msn_params
    )
    # Generate the spi target data
    self.spi_data: pd.DataFrame = self._generate_spi_data(
        spi_target_data, self.spi_params, n
    )
    params["n"] = n
    self.params: SPISeabornParams

    super().__init__(custom_data=self.spi_data, param_model=param_model, **params)

render

render(context)

Render this layer on the given context.

PARAMETER DESCRIPTION
context

The context containing data and axes for rendering

TYPE: PlotContext

Source code in soundscapy/plotting/layers.py
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
def render(self, context: PlotContext) -> None:
    """
    Render this layer on the given context.

    Parameters
    ----------
    context : PlotContext
        The context containing data and axes for rendering

    """
    if context.ax is None:
        msg = "Cannot render layer: context has no associated axes"
        raise ValueError(msg)

    target_data = self.spi_data
    # Mutate spi_data to match the context test_data.
    target_data = self._process_spi_data(target_data, context)

    if target_data is None:
        msg = "No data available for rendering layer"
        raise ValueError(msg)

    # Now we have the SPI target_data and the test data in context.data
    # SPILayer._render_implementation() will handle calculating the SPI score
    # against this particular context / ax test data

    self._render_implementation(target_data, context, context.ax)

show_score

show_score(spi_sc, show_score, context, ax, axis_text_kwargs)

Show the SPI score on the plot.

PARAMETER DESCRIPTION
spi_sc

The SPI score to show

TYPE: int | None

show_score

Where to show the score

TYPE: Literal['on axis', 'under title']

context

The context containing data and axes for rendering

TYPE: PlotContext

ax

The axes to render the score on

TYPE: Axes

axis_text_kwargs

Additional arguments for the axis text

TYPE: dict[str, Any]

Source code in soundscapy/plotting/layers.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
def show_score(
    self,
    spi_sc: int | None,
    show_score: Literal["on axis", "under title"],
    context: PlotContext,
    ax: Axes,
    axis_text_kwargs: dict[str, Any],
) -> None:
    """
    Show the SPI score on the plot.

    Parameters
    ----------
    spi_sc : int | None
        The SPI score to show
    show_score : Literal["on axis", "under title"]
        Where to show the score
    context : PlotContext
        The context containing data and axes for rendering
    ax : Axes
        The axes to render the score on
    axis_text_kwargs : dict[str, Any]
        Additional arguments for the axis text

    """
    if spi_sc is not None:
        if show_score == "on axis":
            self._add_score_as_text(
                ax=ax,
                spi_sc=spi_sc,
                **axis_text_kwargs,
            )
        elif show_score == "under title":
            self._add_score_under_title(
                context=context,
                ax=ax,
                spi_sc=spi_sc,
            )

SPIScatterLayer

SPIScatterLayer()

Bases: SPILayer, ScatterLayer

Layer for rendering simplified SPI plots with fewer contour levels.

Initialize SPIScatterLayer.

This initialization is not supported and will raise NotImplementedError. Use SPISimpleLayer instead.

Source code in soundscapy/plotting/layers.py
703
704
705
706
707
708
709
710
711
712
713
714
def __init__(self) -> None:
    """
    Initialize SPIScatterLayer.

    This initialization is not supported and will raise NotImplementedError.
    Use SPISimpleLayer instead.
    """
    msg = (
        "Only the simple density layer type is currently supported for SPI plots. "
        "Please use SPISimpleLayer"
    )
    raise NotImplementedError(msg)

SPISimpleLayer

SPISimpleLayer(spi_target_data=None, *, msn_params=None, include_outline=True, **params)

Bases: SPILayer, SimpleDensityLayer

Layer for rendering simplified SPI plots with fewer contour levels.

Initialize an SPISimpleLayer.

PARAMETER DESCRIPTION
custom_data

Optional custom data for this specific layer

TYPE: DataFrame | None

msn_params

Parameters to generate SPI data if no custom data is provided

TYPE: DirectParams | CentredParams | None DEFAULT: None

include_outline

Whether to include an outline around the density plot

TYPE: bool DEFAULT: True

**params

Parameters for the density plot

TYPE: dict DEFAULT: {}

Source code in soundscapy/plotting/layers.py
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
def __init__(
    self,
    spi_target_data: pd.DataFrame | np.ndarray | None = None,
    *,
    msn_params: DirectParams | CentredParams | None = None,
    include_outline: bool = True,
    **params: Any,
) -> None:
    """
    Initialize an SPISimpleLayer.

    Parameters
    ----------
    custom_data : pd.DataFrame | None
        Optional custom data for this specific layer
    msn_params : DirectParams | CentredParams | None
        Parameters to generate SPI data if no custom data is provided
    include_outline : bool
        Whether to include an outline around the density plot
    **params : dict
        Parameters for the density plot

    """
    self.params: SPISimpleDensityParams
    super().__init__(
        spi_target_data=spi_target_data,
        include_outline=include_outline,
        param_model=SPISimpleDensityParams,
        msn_params=msn_params,
        **params,
    )

ScatterLayer

ScatterLayer(custom_data=None, **params)

Bases: Layer

Layer for rendering scatter plots.

Initialize a ScatterLayer.

PARAMETER DESCRIPTION
custom_data

Optional custom data for this specific layer

TYPE: DataFrame | None DEFAULT: None

**params

Parameters for the scatter plot

TYPE: dict DEFAULT: {}

Source code in soundscapy/plotting/layers.py
123
124
125
126
127
128
129
130
131
132
133
134
135
def __init__(self, custom_data: pd.DataFrame | None = None, **params: Any) -> None:
    """
    Initialize a ScatterLayer.

    Parameters
    ----------
    custom_data : pd.DataFrame | None
        Optional custom data for this specific layer
    **params : dict
        Parameters for the scatter plot

    """
    super().__init__(custom_data=custom_data, param_model=ScatterParams, **params)

SimpleDensityLayer

SimpleDensityLayer(custom_data=None, *, include_outline=True, param_model=SimpleDensityParams, **params)

Bases: DensityLayer

Layer for rendering simplified density plots with fewer contour levels.

Initialize a SimpleDensityLayer.

PARAMETER DESCRIPTION
custom_data

Optional custom data for this specific layer

TYPE: DataFrame | None DEFAULT: None

include_outline

Whether to include an outline around the density plot

TYPE: bool DEFAULT: True

**params

Parameters for the density plot

TYPE: dict DEFAULT: {}

Source code in soundscapy/plotting/layers.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
def __init__(
    self,
    custom_data: pd.DataFrame | None = None,
    *,
    include_outline: bool = True,
    param_model: type[SimpleDensityParams] = SimpleDensityParams,
    **params: Any,
) -> None:
    """
    Initialize a SimpleDensityLayer.

    Parameters
    ----------
    custom_data : pd.DataFrame | None
        Optional custom data for this specific layer
    include_outline : bool
        Whether to include an outline around the density plot
    **params : dict
        Parameters for the density plot

    """
    super().__init__(
        custom_data=custom_data,
        include_outline=include_outline,  # Could move into params now
        param_model=param_model,
        **params,
    )

show_submodules: true