Source code for vocalpy.plot.spect

"""Functions for plotting spectrograms."""

from __future__ import annotations

from typing import TYPE_CHECKING

import matplotlib.pyplot as plt
import numpy as np
if TYPE_CHECKING:
    import matplotlib.figure
    import matplotlib.axes

from .._spectrogram.data_type import Spectrogram
from ..annotation import Annotation
from .annot import annotation


[docs] def spectrogram( spect: Spectrogram, tlim: tuple | list | None = None, flim: tuple | list | None = None, ax: plt.Axes | None = None, pcolormesh_kwargs: dict | None = None, ) -> tuple[matplotlib.figure.Figure, matplotlib.axes.Axes]: """Plot a spectrogram. Parameters ---------- spectrogram : vocalpy.Spectrogram tlim : tuple, list limits of time axis (min, max) (i.e., x-axis). Default is None, in which case entire range of t will be plotted. flim : tuple, list limits of frequency axis (min, max) (i.e., x-axis). Default is None, in which case entire range of f will be plotted. limits of time axis (min, max) (i.e., x-axis). Default is None, in which case entire range of t will be plotted. flim : tuple, list limits of frequency axis (min, max) (i.e., x-axis). Default is None, in which case entire range of f will be plotted. ax : matplotlib.axes.Axes axes on which to plot spectrogram pcolormesh_kwargs : dict keyword arguments passed to :meth:`matplotlib.axes.Axes.pcolormesh` method used to plot spectrogram. Default is None. Returns ------- fig : matplotlib.figure.Figure ax : matplotlib.axes.Axes Examples -------- .. plot:: >>> samba = voc.example("samba.wav") >>> spect = voc.spectrogram(samba) >>> fig, ax = voc.plot.spectrogram(spect) """ if spect.data.shape[0] > 1: raise ValueError( f"Spectrogram data has more than one channel. Number of channels was: {spect.data.shape[0]}." "This happens when spectral representations are generated from multi-channel audio. " "Plotting multiple channels is not currently supported. " "To plot individual channels, either index into the spectrogram " "to get a new spectrogram of a specific channel:\n" ">>> spect0 = spect[0] # gets channel 0\n" "Or iterate through the spectrogram to get all the channels:\n" ">>> per_channel_spects = [channel_spect for channel_spect in spect]" ) if ax is None: fig, ax = plt.subplots() else: fig = ax.get_figure() if pcolormesh_kwargs is None: pcolormesh_kwargs = {} ax.pcolormesh( spect.times, spect.frequencies, np.squeeze(spect.data, axis=0), **pcolormesh_kwargs, ) if tlim is not None: ax.set_xlim(tlim) if flim is not None: ax.set_ylim(flim) return fig, ax
[docs] def annotated_spectrogram( spect: Spectrogram, annot: Annotation, tlim: tuple | list | None = None, flim: tuple | list | None = None, y_segments: float = 0.5, h_segments: float = 0.4, y_labels: float = 0.3, label_color_map: dict | None = None, pcolormesh_kwargs: dict | None = None, text_kwargs=None, ) -> tuple[plt.Figure, dict]: """Plot a :class:`vocalpy.Spectrogram` with a :class:`vocalpy.Annotation` below it. Convenience function that calls :func:`vocalpy.plot.spectrogram` and :func:`vocalpy.plot.annotation`. Parameters ---------- spect : vocalpy.Spectrogram annot : vocalpy.Annotation Annotation that has segments to be plotted (the `annot.seq.segments` attribute) tlim : tuple, list Limits of time axis (min, max) (i.e., x-axis). Default is None, in which case entire range of t will be plotted. flim : tuple, list limits of frequency axis (min, max) (i.e., x-axis). Default is None, in which case entire range of f will be plotted. y_segments : float Height at which segments should be plotted. Default is 0.5 (assumes y-limits of 0 and 1). h_segments : float, int Height of rectangles that represent segments. Default is 0.4. y_labels : float Height on y-axis at which segment labels (if any) are plotted. Default is 0.4. label_color_map : dict, optional A :class:`dict` that maps string labels to colors (that are valid `color` arguments for matplotlib). pcolormesh_kwargs : dict Keyword arguments that will get passed to :meth:`matplotlib.axes.Axes.pcolormesh` when using that method to plot spectrogram. text_kwargs : dict keyword arguments for :meth:`matplotlib.axes.Axes.text`. Passed to the function :func:`vocalpy.plot.annot.labels` that plots labels using Axes.text method. Defaults are defined as :data:`vocalpy.plot.annot.DEFAULT_TEXT_KWARGS`. Returns ------- fig, axes : Matplotlib Figure and :class:`dict` of Axes instances. The axes containing the spectrogram is ``axes['spect']`` and the axes containing the annotated segments is ``axes['annot']``. Examples -------- .. plot:: >>> bfsongrepo = voc.example("bfsongrepo") >>> spect_maker = voc.SpectrogramMaker(callback=voc.spectrogram) >>> spects = spect_maker.make(bfsongrepo.sound) >>> voc.plot.annotated_spectrogram(spect=spects[0], annot=bfsongrepo.annotation[0], tlim = [3.2, 3.9], flim=[500,12500]) """ fig, axs = plt.subplot_mosaic( [ ["spect"], ["spect"], ["annot"], ], layout="constrained", sharex=True, ) _, _ = spectrogram( spect, tlim, flim, ax=axs["spect"], pcolormesh_kwargs=pcolormesh_kwargs ) annotation( annot, tlim, y_segments=y_segments, h_segments=h_segments, y_labels=y_labels, text_kwargs=text_kwargs, ax=axs["annot"], label_color_map=label_color_map, ) return fig, axs