Repository: pyfar/pyfar
Pull request #615 (2024-05-27 18:29:58)

Plot complex signals
### Which issue(s) are closed by this pull request?

Closes #

### Changes proposed in this pull request:

-
-
-



Patch:
diff --git a/pyfar/plot/_line.py b/pyfar/plot/_line.py
index 8d51bccf..8393b56f 100644
--- a/pyfar/plot/_line.py
+++ b/pyfar/plot/_line.py
@@ -11,7 +11,7 @@ from matplotlib.ticker import NullFormatter
 
 
 def _time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
-          ax=None, **kwargs):
+          ax=None, mode='real', **kwargs):
     """Plot the time data of a signal."""
 
     # check input
@@ -28,6 +28,9 @@ def _time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
         ymin = ymax - 100
     else:
         data = signal.time.T
+    # get data defined in 'show_real_imag_abs'
+    data, y_label = _utils._assert_and_match_data_to_mode(data, mode)
+
     # auto detect the time unit
     if unit in [None, "auto"]:
         unit = _utils._time_auto_unit(signal.times[..., -1])
@@ -42,10 +45,10 @@ def _time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
     _, ax = _utils._prepare_plot(ax)
     ax.set_xlabel(f"Time in {unit}")
     if dB:
-        ax.set_ylabel("Amplitude in dB")
+        ax.set_ylabel(y_label + ' in dB')
         _utils._set_axlim(ax, ax.set_ylim, ymin, ymax, ax.get_ylim())
     else:
-        ax.set_ylabel("Amplitude")
+        ax.set_ylabel(y_label)
     _utils._set_axlim(ax, ax.set_xlim, times[0], times[-1],
                       ax.get_xlim())
 
@@ -56,7 +59,7 @@ def _time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
 
 
 def _freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
-          ax=None, **kwargs):
+          ax=None, side='right', **kwargs):
     """
     Plot the logarithmic absolute spectrum on the positive frequency axis.
     """
@@ -77,6 +80,9 @@ def _freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
     else:
         data = np.abs(signal.freq)
 
+    data, frequencies = _utils._assert_and_match_data_to_side(
+        data, signal, side)
+
     # prepare figure
     _, ax = _utils._prepare_plot(ax)
     ax.grid(True, 'both')
@@ -87,13 +93,13 @@ def _freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
         ax.set_ylabel("Magnitude")
     ax.set_xlabel("Frequency in Hz")
     _utils._set_axlim(ax, ax.set_xlim, _utils._lower_frequency_limit(signal),
-                      signal.frequencies[-1], ax.get_xlim())
+                      frequencies[-1], ax.get_xlim())
 
     # plot data
     if freq_scale == 'log':
-        ax.semilogx(signal.frequencies, data.T, **kwargs)
+        ax.semilogx(frequencies, data.T, **kwargs)
     else:
-        ax.plot(signal.frequencies, data.T, **kwargs)
+        ax.plot(frequencies, data.T, **kwargs)
 
     # set and format ticks
     if freq_scale == 'log':
@@ -105,7 +111,7 @@ def _freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
 
 
 def _phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
-           **kwargs):
+           side='right', **kwargs):
     """Plot the phase of the spectrum on the positive frequency axis."""
 
     # check input
@@ -121,6 +127,9 @@ def _phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
     kwargs = _utils._return_default_colors_rgb(**kwargs)
     phase_data = dsp.phase(signal, deg=deg, unwrap=unwrap)
 
+    phase_data, frequencies = _utils._assert_and_match_data_to_side(
+        phase_data, signal, side)
+
     # Construct the correct label string
     ylabel_string = _utils._phase_label(unwrap, deg)
 
@@ -176,14 +185,14 @@ def _phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
     ax.set_ylabel(ylabel_string)
     ax.grid(True, 'both')
     _utils._set_axlim(ax, ax.set_xlim, _utils._lower_frequency_limit(signal),
-                      signal.frequencies[-1], ax.get_xlim())
+                      frequencies[-1], ax.get_xlim())
     _utils._set_axlim(ax, ax.set_ylim, ymin, ymax, ax.get_ylim())
 
     # plot data
     if freq_scale == 'log':
-        ax.semilogx(signal.frequencies, phase_data.T, **kwargs)
+        ax.semilogx(frequencies, phase_data.T, **kwargs)
     else:
-        ax.plot(signal.frequencies, phase_data.T, **kwargs)
+        ax.plot(frequencies, phase_data.T, **kwargs)
 
     # set and format ticks
     if freq_scale == 'log':
@@ -194,7 +203,8 @@ def _phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
     return ax
 
 
-def _group_delay(signal, unit="s", freq_scale='log', ax=None, **kwargs):
+def _group_delay(signal, unit="s", freq_scale='log', ax=None, side='right',
+                 **kwargs):
     """Plot the group delay on the positive frequency axis."""
 
     # check input
@@ -215,21 +225,24 @@ def _group_delay(signal, unit="s", freq_scale='log', ax=None, **kwargs):
         factor, unit = _utils._deal_time_units(unit)
         data = data / signal.sampling_rate * factor
 
+    data, frequencies = _utils._assert_and_match_data_to_side(
+        data, signal, side)
+
     # prepare figure
     _, ax = _utils._prepare_plot(ax)
     ax.set_xlabel("Frequency in Hz")
     ax.set_ylabel(f"Group delay in {unit}")
     ax.grid(True, 'both')
     _utils._set_axlim(ax, ax.set_xlim, _utils._lower_frequency_limit(signal),
-                      signal.frequencies[-1], ax.get_xlim())
+                      frequencies[-1], ax.get_xlim())
     _utils._set_axlim(ax, ax.set_ylim, .5 * np.nanmin(data),
                       1.5 * np.nanmax(data), ax.get_ylim())
 
     # plot data
     if freq_scale == 'log':
-        ax.semilogx(signal.frequencies, data.T, **kwargs)
+        ax.semilogx(frequencies, data.T, **kwargs)
     else:
-        ax.plot(signal.frequencies, data.T, **kwargs)
+        ax.plot(frequencies, data.T, **kwargs)
 
     # set and format ticks
     if freq_scale == 'log':
@@ -242,7 +255,8 @@ def _group_delay(signal, unit="s", freq_scale='log', ax=None, **kwargs):
 
 def _time_freq(signal, dB_time=False, dB_freq=True, log_prefix_time=20,
                log_prefix_freq=None, log_reference=1, freq_scale='log',
-               unit="s", ax=None, **kwargs):
+               unit="s", ax=None, side='right', mode='real',
+               **kwargs):
     """
     Plot the time signal and magnitude spectrum in a 2 by 1 subplot layout.
     """
@@ -251,23 +265,25 @@ def _time_freq(signal, dB_time=False, dB_freq=True, log_prefix_time=20,
     kwargs = _utils._return_default_colors_rgb(**kwargs)
 
     _time(signal, dB_time, log_prefix_time, log_reference, unit, ax[0],
-          **kwargs)
+          mode, **kwargs)
     _freq(signal, dB_freq, log_prefix_freq, log_reference, freq_scale, ax[1],
-          **kwargs)
+          side, **kwargs)
     fig.align_ylabels()
 
     return ax
 
 
 def _freq_phase(signal, dB=True, log_prefix=None, log_reference=1,
-                freq_scale='log', deg=False, unwrap=False, ax=None, **kwargs):
+                freq_scale='log', deg=False, unwrap=False, ax=None,
+                side='right', **kwargs):
     """Plot the magnitude and phase spectrum in a 2 by 1 subplot layout."""
 
     fig, ax = _utils._prepare_plot(ax, (2, 1))
     kwargs = _utils._return_default_colors_rgb(**kwargs)
 
-    _freq(signal, dB, log_prefix, log_reference, freq_scale, ax[0], **kwargs)
-    _phase(signal, deg, unwrap, freq_scale, ax[1], **kwargs)
+    _freq(signal, dB, log_prefix, log_reference, freq_scale, ax[0], side,
+          **kwargs)
+    _phase(signal, deg, unwrap, freq_scale, ax[1], side, **kwargs)
     ax[0].set_xlabel(None)
     fig.align_ylabels()
 
@@ -275,7 +291,8 @@ def _freq_phase(signal, dB=True, log_prefix=None, log_reference=1,
 
 
 def _freq_group_delay(signal, dB=True, log_prefix=None, log_reference=1,
-                      unit="s", freq_scale='log', ax=None, **kwargs):
+                      unit="s", freq_scale='log', ax=None, side='right',
+                      **kwargs):
     """
     Plot the magnitude and group delay spectrum in a 2 by 1 subplot layout.
     """
@@ -283,8 +300,9 @@ def _freq_group_delay(signal, dB=True, log_prefix=None, log_reference=1,
     fig, ax = _utils._prepare_plot(ax, (2, 1))
     kwargs = _utils._return_default_colors_rgb(**kwargs)
 
-    _freq(signal, dB, log_prefix, log_reference, freq_scale, ax[0], **kwargs)
-    _group_delay(signal, unit, freq_scale, ax[1], **kwargs)
+    _freq(signal, dB, log_prefix, log_reference, freq_scale, ax[0], side,
+          **kwargs)
+    _group_delay(signal, unit, freq_scale, ax[1], side, **kwargs)
     ax[0].set_xlabel(None)
     fig.align_ylabels()
 
diff --git a/pyfar/plot/_utils.py b/pyfar/plot/_utils.py
index a75871e1..6f1e676f 100644
--- a/pyfar/plot/_utils.py
+++ b/pyfar/plot/_utils.py
@@ -425,3 +425,42 @@ def _phase_label(unwrap, deg):
         raise ValueError(f"unwrap is {unwrap} but must be True, False, or 360")
 
     return phase_label
+
+
+def _assert_and_match_data_to_side(data, signal, side):
+    """Adjust data and frequency vector for plotting as specified by side."""
+
+    if side == 'left':
+        mask = signal.frequencies <= 0
+    elif side == 'right':
+        mask = signal.frequencies >= 0
+    else:
+        raise ValueError('Invalid `side` parameter, pass either `left` or '
+                         '`right`.')
+
+    if mask.sum() < 2:
+        raise ValueError(f'The {side} side of the spectrum is not defined.')
+
+    # get corresponding data
+    frequencies = signal.frequencies[mask]
+    data = data[..., mask]
+
+    if side == 'left':
+        frequencies = np.flipud(np.abs(frequencies))
+        data = data[..., ::-1]
+
+    return data, frequencies
+
+
+def _assert_and_match_data_to_mode(data, mode):
+    """Adjust data and y-label for plotting according to specified mode."""
+
+    if mode == 'real':
+        return np.real(data), 'Amplitude'
+    elif mode == 'imag':
+        return np.imag(data), 'Amplitude (imaginary)'
+    elif mode == 'abs':
+        return np.abs(data), 'Amplitude (absolute)'
+    else:
+        raise ValueError('`mode` has to be `real`, `imag`, or '
+                         f'`abs`, but is {mode}.')
diff --git a/pyfar/plot/line.py b/pyfar/plot/line.py
index 6d9abdd3..16b7b498 100644
--- a/pyfar/plot/line.py
+++ b/pyfar/plot/line.py
@@ -4,7 +4,7 @@ from . import _interaction as ia
 
 
 def time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
-         ax=None, style='light', **kwargs):
+         ax=None, style='light', mode='real', **kwargs):
     """Plot the time signal.
 
     Plots ``signal.time`` and passes keyword arguments (`kwargs`) to
@@ -50,6 +50,10 @@ def time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
         ``style = {'axes.facecolor':'black'}``. Pass an empty dictionary
         ``style = {}`` to use the currently active plotstyle. The default is
         ``light``.
+    mode : str
+        ``real``, ``imag``, or ``abs`` to specify if the real part, imaginary
+        part or absolute value of a complex-valued time domain signal is
+        plotted. The default is ``real``.
     **kwargs
         Keyword arguments that are passed to :py:func:`matplotlib.pyplot.plot`.
 
@@ -71,7 +75,7 @@ def time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
 
     with context(style):
         ax = _line._time(signal.flatten(), dB, log_prefix, log_reference, unit,
-                         ax, **kwargs)
+                         ax, mode, **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(
@@ -85,7 +89,7 @@ def time(signal, dB=False, log_prefix=20, log_reference=1, unit="s",
 
 
 def freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
-         ax=None, style='light', **kwargs):
+         ax=None, style='light', side='right', **kwargs):
     """
     Plot the magnitude spectrum.
 
@@ -122,6 +126,8 @@ def freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
         ``style = {'axes.facecolor':'black'}``. Pass an empty dictionary
         ``style = {}`` to use the currently active plotstyle. The default is
         ``light``.
+    side : str
+        ``left`` or ``right`` to specify which side of a spectrum is plotted.
     **kwargs
         Keyword arguments that are passed to :py:func:`matplotlib.pyplot.plot`.
 
@@ -142,7 +148,7 @@ def freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
 
     with context(style):
         ax = _line._freq(signal.flatten(), dB, log_prefix, log_reference,
-                         freq_scale, ax, **kwargs)
+                         freq_scale, ax, side, **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(
@@ -156,7 +162,7 @@ def freq(signal, dB=True, log_prefix=None, log_reference=1, freq_scale='log',
 
 
 def phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
-          style='light', **kwargs):
+          style='light', side='right', **kwargs):
     """Plot the phase of the spectrum.
 
     Plots ``angle(signal.freq)`` and passes keyword arguments (`kwargs`) to
@@ -207,7 +213,7 @@ def phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
 
     with context(style):
         ax = _line._phase(
-            signal.flatten(), deg, unwrap, freq_scale, ax, **kwargs)
+            signal.flatten(), deg, unwrap, freq_scale, ax, side=side, **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(
@@ -220,7 +226,7 @@ def phase(signal, deg=False, unwrap=False, freq_scale='log', ax=None,
 
 
 def group_delay(signal, unit="s", freq_scale='log', ax=None, style='light',
-                **kwargs):
+                side='right', **kwargs):
     """Plot the group delay.
 
     Plots ``pyfar.dsp.group_delay(signal.freq)`` and passes keyword arguments
@@ -279,7 +285,7 @@ def group_delay(signal, unit="s", freq_scale='log', ax=None, style='light',
 
     with context(style):
         ax = _line._group_delay(
-            signal.flatten(), unit, freq_scale, ax, **kwargs)
+            signal.flatten(), unit, freq_scale, ax, side=side, **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(
@@ -293,7 +299,8 @@ def group_delay(signal, unit="s", freq_scale='log', ax=None, style='light',
 
 def time_freq(signal, dB_time=False, dB_freq=True, log_prefix_time=20,
               log_prefix_freq=None, log_reference=1, freq_scale='log',
-              unit="s", ax=None, style='light', **kwargs):
+              unit="s", ax=None, style='light',
+              mode='real', side='right', **kwargs):
     """
     Plot the time signal and magnitude spectrum (2 by 1 subplot).
 
@@ -372,7 +379,9 @@ def time_freq(signal, dB_time=False, dB_freq=True, log_prefix_time=20,
     with context(style):
         ax = _line._time_freq(signal.flatten(), dB_time, dB_freq,
                               log_prefix_time, log_prefix_freq,
-                              log_reference, freq_scale, unit, ax, **kwargs)
+                              log_reference, freq_scale, unit, ax,
+                              mode=mode, side=side,
+                              **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(
@@ -388,7 +397,7 @@ def time_freq(signal, dB_time=False, dB_freq=True, log_prefix_time=20,
 
 def freq_phase(signal, dB=True, log_prefix=None, log_reference=1,
                freq_scale='log', deg=False, unwrap=False, ax=None,
-               style='light', **kwargs):
+               style='light', side='right', **kwargs):
     """Plot the magnitude and phase spectrum (2 by 1 subplot).
 
     Plots ``abs(signal.freq)`` and ``angle(signal.freq)`` and passes keyword
@@ -449,7 +458,8 @@ def freq_phase(signal, dB=True, log_prefix=None, log_reference=1,
 
     with context(style):
         ax = _line._freq_phase(signal.flatten(), dB, log_prefix, log_reference,
-                               freq_scale, deg, unwrap, ax, **kwargs)
+                               freq_scale, deg, unwrap, ax, side=side,
+                               **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(
@@ -465,7 +475,7 @@ def freq_phase(signal, dB=True, log_prefix=None, log_reference=1,
 
 def freq_group_delay(signal, dB=True, log_prefix=None, log_reference=1,
                      unit="s", freq_scale='log', ax=None, style='light',
-                     **kwargs):
+                     side='right', **kwargs):
     """Plot the magnitude and group delay spectrum (2 by 1 subplot).
 
     Plots ``abs(signal.freq)`` and ``pyfar.dsp.group_delay(signal.freq)`` and
@@ -535,7 +545,7 @@ def freq_group_delay(signal, dB=True, log_prefix=None, log_reference=1,
     with context(style):
         ax = _line._freq_group_delay(
             signal.flatten(), dB, log_prefix, log_reference,
-            unit, freq_scale, ax, **kwargs)
+            unit, freq_scale, ax, side=side, **kwargs)
 
     # manage interaction
     plot_parameter = ia.PlotParameter(


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index ec073913..4e11800c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -513,6 +513,24 @@ def handsome_complex_signal():
     return signal
 
 
+@pytest.fixture
+def handsome_complex_signal_v2():
+    """
+    Windowed 1kHz sine signal for testing plots
+
+    Returns
+    -------
+    signal : Signal
+        Windowed sine
+    """
+
+    signal = pf.signals.sine(2000, 4410)
+    signal = pf.dsp.time_window(signal, (500, 1000, 2000, 2500))
+    signal = pf.Signal(data=signal.time, sampling_rate=signal.sampling_rate,
+                       is_complex=True)
+    return signal
+
+
 @pytest.fixture
 def handsome_signal_2d():
     """
diff --git a/tests/test_plot.py b/tests/test_plot.py
index 1cce11d0..3186f2bf 100644
--- a/tests/test_plot.py
+++ b/tests/test_plot.py
@@ -74,6 +74,55 @@ def test_line_plots(function, handsome_signal, handsome_signal_v2):
                      file_type, compare_output)
 
 
+@pytest.mark.parametrize('mode', [
+    'real', 'imag', 'abs'])
+def test_complex_time_plots(mode,
+                            handsome_complex_signal,
+                            handsome_complex_signal_v2):
+    """Test all line plots with default arguments and hold functionality."""
+    print(f"Testing: {plot.time.__name__}, mode "
+          f"= {mode}")
+
+    # initial plot
+    filename = f'{plot.time.__name__}_{mode}_default'
+    create_figure()
+    plot.time(handsome_complex_signal, mode=mode)
+    save_and_compare(create_baseline, baseline_path, output_path, filename,
+                     file_type, compare_output)
+
+    # test hold functionality
+    filename = f'{plot.time.__name__}_{mode}_hold'
+    plot.time(handsome_complex_signal_v2,
+              mode=mode)
+    save_and_compare(create_baseline, baseline_path, output_path, filename,
+                     file_type, compare_output)
+
+
+@pytest.mark.parametrize('function', [
+    (plot.freq), (plot.phase), (plot.group_delay),
+    (plot.freq_phase), (plot.freq_group_delay)])
+@pytest.mark.parametrize('side_flag', [
+                         'left', 'right'])
+def test_complex_freq_plots(function, side_flag,
+                            handsome_complex_signal,
+                            handsome_complex_signal_v2):
+    """Test all line plots with default arguments and hold functionality."""
+    print(f"Testing: {function.__name__}")
+
+    # initial plot
+    filename = f'{function.__name__}_{side_flag}_default'
+    create_figure()
+    function(handsome_complex_signal, side=side_flag)
+    save_and_compare(create_baseline, baseline_path, output_path, filename,
+                     file_type, compare_output)
+
+    # test hold functionality
+    filename = f'{function.__name__}_{side_flag}_hold'
+    function(handsome_complex_signal_v2, side=side_flag)
+    save_and_compare(create_baseline, baseline_path, output_path, filename,
+                     file_type, compare_output)
+
+
 @pytest.mark.parametrize('signal', ['handsome_signal', 'impulse'])
 @pytest.mark.parametrize('param', [
     ['phase_deg', True, False],
diff --git a/tests/test_plot__utils.py b/tests/test_plot__utils.py
index 1e86a2fe..84d4271e 100644
--- a/tests/test_plot__utils.py
+++ b/tests/test_plot__utils.py
@@ -3,6 +3,8 @@ import pytest
 from pytest import raises
 import pyfar.plot as plot
 import pyfar as pf
+import numpy as np
+import numpy.testing as npt
 
 
 def test_prepare_plot():
@@ -141,3 +143,84 @@ def test__deal_time_units_mus():
     """Test previous bugfix for unit micro seconds in labels."""
     s = pf.signals.impulse(10, sampling_rate=44100)
     pf.plot.time(s)
+
+
+def test_assert_and_match_data_to_side_wrong_parameter():
+    signal = pf.signals.sine(20, 32)
+
+    with raises(ValueError, match='Invalid `side` parameter, pass either '
+                '`left` or `right`.'):
+        plot._utils._assert_and_match_data_to_side(
+            signal.freq, signal, side='quatsch')
+
+
+def test_assert_and_match_data_to_side():
+    signal = pf.signals.sine(20, 32)
+
+    with raises(ValueError, match='The left side of the spectrum is not '
+                'defined.'):
+        plot._utils._assert_and_match_data_to_side(
+            signal.freq, signal, side='left')
+
+    signal.fft_norm = 'none'
+    signal.complex = True
+
+    data, frequencies = plot._utils._assert_and_match_data_to_side(
+        signal.freq, signal, side='left')
+
+    assert not np.any(frequencies < 0.0)
+    assert data.shape[-1] == frequencies.shape[0]
+
+    data, frequencies = plot._utils._assert_and_match_data_to_side(
+        signal.freq, signal, side='right')
+
+    assert not np.any(frequencies < 0.0)
+    assert data.shape[-1] == frequencies.shape[0]
+
+
+def test_assert_and_match_data_to_side_freq():
+    signal = pf.FrequencyData([3, 4, 5, 6, 7],
+                              [1, 2, 3, 4, 5])
+
+    with raises(ValueError, match='The left side of the spectrum is not '
+                'defined.'):
+        plot._utils._assert_and_match_data_to_side(
+            signal.freq, signal, side='left')
+
+    data, frequencies = plot._utils._assert_and_match_data_to_side(
+        signal.freq, signal, side='right')
+    assert not np.any(frequencies < 0.0)
+    assert data.shape[-1] == frequencies.shape[0]
+
+    signal = pf.FrequencyData([3, 4, 5, 6, 7],
+                              [-5, -4, -3, -2, -1])
+    with raises(ValueError, match='The right side of the spectrum is not '
+                'defined.'):
+        plot._utils._assert_and_match_data_to_side(
+            signal.freq, signal, side='right')
+
+    data, frequencies = plot._utils._assert_and_match_data_to_side(
+        signal.freq, signal, side='left')
+    assert not np.any(frequencies < 0.0)
+    assert data.shape[-1] == frequencies.shape[0]
+
+
+@pytest.mark.parametrize("mode, ylabel", [('real', 'Amplitude'),
+                                          ('imag', 'Amplitude (imaginary)'),
+                                          ('abs', 'Amplitude (absolute)')])
+def test_assert_and_match_data_to_mode(mode, ylabel):
+    signal = pf.signals.sine(20, 32)
+
+    data, _ylabel = plot._utils._assert_and_match_data_to_mode(signal.time,
+                                                               mode)
+
+    if mode == 'real':
+        npt.assert_allclose(data,
+                            np.real(signal.time), atol=1e-15)
+    elif mode == 'imag':
+        npt.assert_allclose(data,
+                            np.imag(signal.time), atol=1e-15)
+    else:
+        npt.assert_allclose(data,
+                            np.abs(signal.time), atol=1e-15)
+    assert _ylabel == ylabel