def plot_filter(h, sfreq, freq=None, gain=None, title=None, color='#1f77b4', flim=None, fscale='log', alim=_DEFAULT_ALIM, show=True, compensate=False, plot=('time', 'magnitude', 'delay'), axes=None):
    'Plot properties of a filter.\n\n    Parameters\n    ----------\n    h : dict or ndarray\n        An IIR dict or 1D ndarray of coefficients (for FIR filter).\n    sfreq : float\n        Sample rate of the data (Hz).\n    freq : array-like or None\n        The ideal response frequencies to plot (must be in ascending order).\n        If None (default), do not plot the ideal response.\n    gain : array-like or None\n        The ideal response gains to plot.\n        If None (default), do not plot the ideal response.\n    title : str | None\n        The title to use. If None (default), determine the title based\n        on the type of the system.\n    color : color object\n        The color to use (default \'#1f77b4\').\n    flim : tuple or None\n        If not None, the x-axis frequency limits (Hz) to use.\n        If None, freq will be used. If None (default) and freq is None,\n        ``(0.1, sfreq / 2.)`` will be used.\n    fscale : str\n        Frequency scaling to use, can be "log" (default) or "linear".\n    alim : tuple\n        The y-axis amplitude limits (dB) to use (default: (-60, 10)).\n    show : bool\n        Show figure if True (default).\n    compensate : bool\n        If True, compensate for the filter delay (phase will not be shown).\n\n        - For linear-phase FIR filters, this visualizes the filter coefficients\n          assuming that the output will be shifted by ``N // 2``.\n        - For IIR filters, this changes the filter coefficient display\n          by filtering backward and forward, and the frequency response\n          by squaring it.\n\n        .. versionadded:: 0.18\n    plot : list | tuple | str\n        A list of the requested plots from ``time``, ``magnitude`` and\n        ``delay``. Default is to plot all three filter properties\n        (\'time\', \'magnitude\', \'delay\').\n\n        .. versionadded:: 0.21.0\n    axes : instance of Axes | list | None\n        The axes to plot to. If list, the list must be a list of Axes of\n        the same length as the number of requested plot types. If instance of\n        Axes, there must be only one filter property plotted.\n        Defaults to ``None``.\n\n        .. versionadded:: 0.21.0\n\n    Returns\n    -------\n    fig : matplotlib.figure.Figure\n        The figure containing the plots.\n\n    See Also\n    --------\n    mne.filter.create_filter\n    plot_ideal_filter\n\n    Notes\n    -----\n    .. versionadded:: 0.14\n    '
    from scipy.signal import freqz, group_delay, lfilter, filtfilt, sosfilt, sosfiltfilt
    import matplotlib.pyplot as plt
    sfreq = float(sfreq)
    _check_option('fscale', fscale, ['log', 'linear'])
    if isinstance(plot, str):
        plot = [plot]
    for (xi, x) in enumerate(plot):
        _check_option(('plot[%d]' % xi), x, ('magnitude', 'delay', 'time'))
    flim = _get_flim(flim, fscale, freq, sfreq)
    if (fscale == 'log'):
        omega = np.logspace(np.log10(flim[0]), np.log10(flim[1]), 1000)
    else:
        omega = np.linspace(flim[0], flim[1], 1000)
    (xticks, xticklabels) = _filter_ticks(flim, fscale)
    omega /= (sfreq / (2 * np.pi))
    if isinstance(h, dict):
        if ('sos' in h):
            H = np.ones(len(omega), np.complex128)
            gd = np.zeros(len(omega))
            for section in h['sos']:
                this_H = freqz(section[:3], section[3:], omega)[1]
                H *= this_H
                if compensate:
                    H *= this_H.conj()
                else:
                    with warnings.catch_warnings(record=True):
                        warnings.simplefilter('ignore')
                        gd += group_delay((section[:3], section[3:]), omega)[1]
            n = estimate_ringing_samples(h['sos'])
            delta = np.zeros(n)
            delta[0] = 1
            if compensate:
                delta = np.pad(delta, [((n - 1), 0)], 'constant')
                func = sosfiltfilt
                gd += ((len(delta) - 1) // 2)
            else:
                func = sosfilt
            h = func(h['sos'], delta)
        else:
            H = freqz(h['b'], h['a'], omega)[1]
            if compensate:
                H *= H.conj()
            with warnings.catch_warnings(record=True):
                warnings.simplefilter('ignore')
                gd = group_delay((h['b'], h['a']), omega)[1]
                if compensate:
                    gd += group_delay(h['b'].conj(), h['a'].conj(), omega)[1]
            n = estimate_ringing_samples((h['b'], h['a']))
            delta = np.zeros(n)
            delta[0] = 1
            if compensate:
                delta = np.pad(delta, [((n - 1), 0)], 'constant')
                func = filtfilt
            else:
                func = lfilter
            h = func(h['b'], h['a'], delta)
        if (title is None):
            title = 'SOS (IIR) filter'
        if compensate:
            title += ' (forward-backward)'
    else:
        H = freqz(h, worN=omega)[1]
        with warnings.catch_warnings(record=True):
            warnings.simplefilter('ignore')
            gd = group_delay((h, [1.0]), omega)[1]
        title = ('FIR filter' if (title is None) else title)
        if compensate:
            title += ' (delay-compensated)'
    fig = None
    if (axes is None):
        (fig, axes) = plt.subplots(len(plot), 1)
    if isinstance(axes, plt.Axes):
        axes = [axes]
    elif isinstance(axes, np.ndarray):
        axes = list(axes)
    if (fig is None):
        fig = axes[0].get_figure()
    if (len(axes) != len(plot)):
        raise ValueError(('Length of axes (%d) must be the same as number of requested filter properties (%d)' % (len(axes), len(plot))))
    t = np.arange(len(h))
    dlim = (np.abs(t).max() / 2.0)
    dlim = [(- dlim), dlim]
    if compensate:
        n_shift = ((len(h) - 1) // 2)
        t -= n_shift
        assert (t[0] == (- t[(- 1)]))
        gd -= n_shift
    t = (t / sfreq)
    gd = (gd / sfreq)
    f = ((omega * sfreq) / (2 * np.pi))
    sl = slice((0 if (fscale == 'linear') else 1), None, None)
    mag = (10 * np.log10(np.maximum((H * H.conj()).real, 1e-20)))
    if ('time' in plot):
        ax_time_idx = np.where([(p == 'time') for p in plot])[0][0]
        axes[ax_time_idx].plot(t, h, color=color)
        axes[ax_time_idx].set(xlim=t[[0, (- 1)]], xlabel='Time (s)', ylabel='Amplitude', title=title)
    if ('magnitude' in plot):
        ax_mag_idx = np.where([(p == 'magnitude') for p in plot])[0][0]
        axes[ax_mag_idx].plot(f[sl], mag[sl], color=color, linewidth=2, zorder=4)
        if ((freq is not None) and (gain is not None)):
            plot_ideal_filter(freq, gain, axes[ax_mag_idx], fscale=fscale, show=False)
        axes[ax_mag_idx].set(ylabel='Magnitude (dB)', xlabel='', xscale=fscale)
        if (xticks is not None):
            axes[ax_mag_idx].set(xticks=xticks)
            axes[ax_mag_idx].set(xticklabels=xticklabels)
        axes[ax_mag_idx].set(xlim=flim, ylim=alim, xlabel='Frequency (Hz)', ylabel='Amplitude (dB)')
    if ('delay' in plot):
        ax_delay_idx = np.where([(p == 'delay') for p in plot])[0][0]
        axes[ax_delay_idx].plot(f[sl], gd[sl], color=color, linewidth=2, zorder=4)
        for (start, stop) in zip(*_mask_to_onsets_offsets((mag <= (- 39.9)))):
            axes[ax_delay_idx].axvspan(f[start], f[(stop - 1)], facecolor='k', alpha=0.05, zorder=5)
        axes[ax_delay_idx].set(xlim=flim, ylabel='Group delay (s)', xlabel='Frequency (Hz)', xscale=fscale)
        if (xticks is not None):
            axes[ax_delay_idx].set(xticks=xticks)
            axes[ax_delay_idx].set(xticklabels=xticklabels)
        axes[ax_delay_idx].set(xlim=flim, ylim=dlim, xlabel='Frequency (Hz)', ylabel='Delay (s)')
    adjust_axes(axes)
    tight_layout()
    plt_show(show)
    return fig
Plot properties of a filter.

Parameters
----------
h : dict or ndarray
    An IIR dict or 1D ndarray of coefficients (for FIR filter).
sfreq : float
    Sample rate of the data (Hz).
freq : array-like or None
    The ideal response frequencies to plot (must be in ascending order).
    If None (default), do not plot the ideal response.
gain : array-like or None
    The ideal response gains to plot.
    If None (default), do not plot the ideal response.
title : str | None
    The title to use. If None (default), determine the title based
    on the type of the system.
color : color object
    The color to use (default '#1f77b4').
flim : tuple or None
    If not None, the x-axis frequency limits (Hz) to use.
    If None, freq will be used. If None (default) and freq is None,
    ``(0.1, sfreq / 2.)`` will be used.
fscale : str
    Frequency scaling to use, can be "log" (default) or "linear".
alim : tuple
    The y-axis amplitude limits (dB) to use (default: (-60, 10)).
show : bool
    Show figure if True (default).
compensate : bool
    If True, compensate for the filter delay (phase will not be shown).

    - For linear-phase FIR filters, this visualizes the filter coefficients
      assuming that the output will be shifted by ``N // 2``.
    - For IIR filters, this changes the filter coefficient display
      by filtering backward and forward, and the frequency response
      by squaring it.

    .. versionadded:: 0.18
plot : list | tuple | str
    A list of the requested plots from ``time``, ``magnitude`` and
    ``delay``. Default is to plot all three filter properties
    ('time', 'magnitude', 'delay').

    .. versionadded:: 0.21.0
axes : instance of Axes | list | None
    The axes to plot to. If list, the list must be a list of Axes of
    the same length as the number of requested plot types. If instance of
    Axes, there must be only one filter property plotted.
    Defaults to ``None``.

    .. versionadded:: 0.21.0

Returns
-------
fig : matplotlib.figure.Figure
    The figure containing the plots.

See Also
--------
mne.filter.create_filter
plot_ideal_filter

Notes
-----
.. versionadded:: 0.14
def plot_filter(h, sfreq, freq=None, gain=None, title=None, color='#1f77b4', flim=None, fscale='log', alim=_DEFAULT_ALIM, show=True, compensate=False, plot=('time', 'magnitude', 'delay'), axes=None):
    'Plot properties of a filter.\n\n    Parameters\n    ----------\n    h : dict or ndarray\n        An IIR dict or 1D ndarray of coefficients (for FIR filter).\n    sfreq : float\n        Sample rate of the data (Hz).\n    freq : array-like or None\n        The ideal response frequencies to plot (must be in ascending order).\n        If None (default), do not plot the ideal response.\n    gain : array-like or None\n        The ideal response gains to plot.\n        If None (default), do not plot the ideal response.\n    title : str | None\n        The title to use. If None (default), determine the title based\n        on the type of the system.\n    color : color object\n        The color to use (default \'#1f77b4\').\n    flim : tuple or None\n        If not None, the x-axis frequency limits (Hz) to use.\n        If None, freq will be used. If None (default) and freq is None,\n        ``(0.1, sfreq / 2.)`` will be used.\n    fscale : str\n        Frequency scaling to use, can be "log" (default) or "linear".\n    alim : tuple\n        The y-axis amplitude limits (dB) to use (default: (-60, 10)).\n    show : bool\n        Show figure if True (default).\n    compensate : bool\n        If True, compensate for the filter delay (phase will not be shown).\n\n        - For linear-phase FIR filters, this visualizes the filter coefficients\n          assuming that the output will be shifted by ``N // 2``.\n        - For IIR filters, this changes the filter coefficient display\n          by filtering backward and forward, and the frequency response\n          by squaring it.\n\n        .. versionadded:: 0.18\n    plot : list | tuple | str\n        A list of the requested plots from ``time``, ``magnitude`` and\n        ``delay``. Default is to plot all three filter properties\n        (\'time\', \'magnitude\', \'delay\').\n\n        .. versionadded:: 0.21.0\n    axes : instance of Axes | list | None\n        The axes to plot to. If list, the list must be a list of Axes of\n        the same length as the number of requested plot types. If instance of\n        Axes, there must be only one filter property plotted.\n        Defaults to ``None``.\n\n        .. versionadded:: 0.21.0\n\n    Returns\n    -------\n    fig : matplotlib.figure.Figure\n        The figure containing the plots.\n\n    See Also\n    --------\n    mne.filter.create_filter\n    plot_ideal_filter\n\n    Notes\n    -----\n    .. versionadded:: 0.14\n    '
    from scipy.signal import freqz, group_delay, lfilter, filtfilt, sosfilt, sosfiltfilt
    import matplotlib.pyplot as plt
    sfreq = float(sfreq)
    _check_option('fscale', fscale, ['log', 'linear'])
    if isinstance(plot, str):
        plot = [plot]
    for (xi, x) in enumerate(plot):
        _check_option(('plot[%d]' % xi), x, ('magnitude', 'delay', 'time'))
    flim = _get_flim(flim, fscale, freq, sfreq)
    if (fscale == 'log'):
        omega = np.logspace(np.log10(flim[0]), np.log10(flim[1]), 1000)
    else:
        omega = np.linspace(flim[0], flim[1], 1000)
    (xticks, xticklabels) = _filter_ticks(flim, fscale)
    omega /= (sfreq / (2 * np.pi))
    if isinstance(h, dict):
        if ('sos' in h):
            H = np.ones(len(omega), np.complex128)
            gd = np.zeros(len(omega))
            for section in h['sos']:
                this_H = freqz(section[:3], section[3:], omega)[1]
                H *= this_H
                if compensate:
                    H *= this_H.conj()
                else:
                    with warnings.catch_warnings(record=True):
                        warnings.simplefilter('ignore')
                        gd += group_delay((section[:3], section[3:]), omega)[1]
            n = estimate_ringing_samples(h['sos'])
            delta = np.zeros(n)
            delta[0] = 1
            if compensate:
                delta = np.pad(delta, [((n - 1), 0)], 'constant')
                func = sosfiltfilt
                gd += ((len(delta) - 1) // 2)
            else:
                func = sosfilt
            h = func(h['sos'], delta)
        else:
            H = freqz(h['b'], h['a'], omega)[1]
            if compensate:
                H *= H.conj()
            with warnings.catch_warnings(record=True):
                warnings.simplefilter('ignore')
                gd = group_delay((h['b'], h['a']), omega)[1]
                if compensate:
                    gd += group_delay(h['b'].conj(), h['a'].conj(), omega)[1]
            n = estimate_ringing_samples((h['b'], h['a']))
            delta = np.zeros(n)
            delta[0] = 1
            if compensate:
                delta = np.pad(delta, [((n - 1), 0)], 'constant')
                func = filtfilt
            else:
                func = lfilter
            h = func(h['b'], h['a'], delta)
        if (title is None):
            title = 'SOS (IIR) filter'
        if compensate:
            title += ' (forward-backward)'
    else:
        H = freqz(h, worN=omega)[1]
        with warnings.catch_warnings(record=True):
            warnings.simplefilter('ignore')
            gd = group_delay((h, [1.0]), omega)[1]
        title = ('FIR filter' if (title is None) else title)
        if compensate:
            title += ' (delay-compensated)'
    fig = None
    if (axes is None):
        (fig, axes) = plt.subplots(len(plot), 1)
    if isinstance(axes, plt.Axes):
        axes = [axes]
    elif isinstance(axes, np.ndarray):
        axes = list(axes)
    if (fig is None):
        fig = axes[0].get_figure()
    if (len(axes) != len(plot)):
        raise ValueError(('Length of axes (%d) must be the same as number of requested filter properties (%d)' % (len(axes), len(plot))))
    t = np.arange(len(h))
    dlim = (np.abs(t).max() / 2.0)
    dlim = [(- dlim), dlim]
    if compensate:
        n_shift = ((len(h) - 1) // 2)
        t -= n_shift
        assert (t[0] == (- t[(- 1)]))
        gd -= n_shift
    t = (t / sfreq)
    gd = (gd / sfreq)
    f = ((omega * sfreq) / (2 * np.pi))
    sl = slice((0 if (fscale == 'linear') else 1), None, None)
    mag = (10 * np.log10(np.maximum((H * H.conj()).real, 1e-20)))
    if ('time' in plot):
        ax_time_idx = np.where([(p == 'time') for p in plot])[0][0]
        axes[ax_time_idx].plot(t, h, color=color)
        axes[ax_time_idx].set(xlim=t[[0, (- 1)]], xlabel='Time (s)', ylabel='Amplitude', title=title)
    if ('magnitude' in plot):
        ax_mag_idx = np.where([(p == 'magnitude') for p in plot])[0][0]
        axes[ax_mag_idx].plot(f[sl], mag[sl], color=color, linewidth=2, zorder=4)
        if ((freq is not None) and (gain is not None)):
            plot_ideal_filter(freq, gain, axes[ax_mag_idx], fscale=fscale, show=False)
        axes[ax_mag_idx].set(ylabel='Magnitude (dB)', xlabel=, xscale=fscale)
        if (xticks is not None):
            axes[ax_mag_idx].set(xticks=xticks)
            axes[ax_mag_idx].set(xticklabels=xticklabels)
        axes[ax_mag_idx].set(xlim=flim, ylim=alim, xlabel='Frequency (Hz)', ylabel='Amplitude (dB)')
    if ('delay' in plot):
        ax_delay_idx = np.where([(p == 'delay') for p in plot])[0][0]
        axes[ax_delay_idx].plot(f[sl], gd[sl], color=color, linewidth=2, zorder=4)
        for (start, stop) in zip(*_mask_to_onsets_offsets((mag <= (- 39.9)))):
            axes[ax_delay_idx].axvspan(f[start], f[(stop - 1)], facecolor='k', alpha=0.05, zorder=5)
        axes[ax_delay_idx].set(xlim=flim, ylabel='Group delay (s)', xlabel='Frequency (Hz)', xscale=fscale)
        if (xticks is not None):
            axes[ax_delay_idx].set(xticks=xticks)
            axes[ax_delay_idx].set(xticklabels=xticklabels)
        axes[ax_delay_idx].set(xlim=flim, ylim=dlim, xlabel='Frequency (Hz)', ylabel='Delay (s)')
    adjust_axes(axes)
    tight_layout()
    plt_show(show)
    return fig