# Buggy code
def _plot_lines(
    data,
    info,
    picks,
    fig,
    axes,
    spatial_colors,
    unit,
    units,
    scalings,
    hline,
    gfp,
    types,
    zorder,
    xlim,
    ylim,
    times,
    bad_ch_idx,
    titles,
    ch_types_used,
    selectable,
    psd,
    line_alpha,
    nave,
    time_unit,
    sphere,
):
    """Plot data as butterfly plot."""
    from matplotlib import patheffects, pyplot as plt
    from matplotlib.widgets import SpanSelector

    assert len(axes) == len(ch_types_used)
    texts = list()
    idxs = list()
    lines = list()
    sphere = _check_sphere(sphere, info)
    path_effects = [patheffects.withStroke(linewidth=2, foreground="w", alpha=0.75)]
    gfp_path_effects = [patheffects.withStroke(linewidth=5, foreground="w", alpha=0.75)]
    if selectable:
        selectables = np.ones(len(ch_types_used), dtype=bool)
        for type_idx, this_type in enumerate(ch_types_used):
            idx = picks[types == this_type]
            if len(idx) < 2 or (this_type == "grad" and len(idx) < 4):
                # prevent unnecessary warnings for e.g. EOG
                if this_type in _DATA_CH_TYPES_SPLIT:
                    logger.info(
                        "Need more than one channel to make "
                        "topography for %s. Disabling interactivity." % (this_type,)
                    )
                selectables[type_idx] = False

    if selectable:
        # Parameters for butterfly interactive plots
        params = dict(
            axes=axes,
            texts=texts,
            lines=lines,
            ch_names=info["ch_names"],
            idxs=idxs,
            need_draw=False,
            path_effects=path_effects,
        )
        fig.canvas.mpl_connect("pick_event", partial(_butterfly_onpick, params=params))
        fig.canvas.mpl_connect(
            "button_press_event", partial(_butterfly_on_button_press, params=params)
        )
    for ai, (ax, this_type) in enumerate(zip(axes, ch_types_used)):
        line_list = list()  # 'line_list' contains the lines for this axes
        if unit is False:
            this_scaling = 1.0
            ch_unit = "NA"  # no unit
        else:
            this_scaling = 1.0 if scalings is None else scalings[this_type]
            ch_unit = units[this_type]
        idx = list(picks[types == this_type])
        idxs.append(idx)

        if len(idx) > 0:
            # Set amplitude scaling
            D = this_scaling * data[idx, :]
            _check_if_nan(D)
            gfp_only = isinstance(gfp, str) and gfp == "only"
            if not gfp_only:
                chs = [info["chs"][i] for i in idx]
                locs3d = np.array([ch["loc"][:3] for ch in chs])
                if spatial_colors is True and not _check_ch_locs(chs):
                    warn("Channel locations not available. Disabling spatial colors.")
                    spatial_colors = selectable = False
                if spatial_colors is True and len(idx) != 1:
                    x, y, z = locs3d.T
                    colors = _rgb(x, y, z)
                    _handle_spatial_colors(
                        colors, info, idx, this_type, psd, ax, sphere
                    )
                else:
                    if isinstance(spatial_colors, (tuple, str)):
                        col = [spatial_colors]
                    else:
                        col = ["k"]
                    colors = col * len(idx)
                    for i in bad_ch_idx:
                        if i in idx:
                            colors[idx.index(i)] = "r"

                if zorder == "std":
                    # find the channels with the least activity
                    # to map them in front of the more active ones
                    z_ord = D.std(axis=1).argsort()
                elif zorder == "unsorted":
                    z_ord = list(range(D.shape[0]))
                elif not callable(zorder):
                    error = '`zorder` must be a function, "std" or "unsorted", not {0}.'
                    raise TypeError(error.format(type(zorder)))
                else:
                    z_ord = zorder(D)

                # plot channels
                for ch_idx, z in enumerate(z_ord):
                    line_list.append(
                        ax.plot(
                            times,
                            D[ch_idx],
                            picker=3.0,
                            zorder=z + 1 if spatial_colors is True else 1,
                            color=colors[ch_idx],
                            alpha=line_alpha,
                            linewidth=0.5,
                        )[0]
                    )

            if gfp:  # 'only' or boolean True
                gfp_color = 3 * (0.0,) if spatial_colors is True else (0.0, 1.0, 0.0)
                this_gfp = np.sqrt((D * D).mean(axis=0))
                this_ylim = (
                    ax.get_ylim()
                    if (ylim is None or this_type not in ylim.keys())
                    else ylim[this_type]
                )
                if gfp_only:
                    y_offset = 0.0
                else:
                    y_offset = this_ylim[0]
                this_gfp += y_offset
                ax.fill_between(
                    times,
                    y_offset,
                    this_gfp,
                    color="none",
                    facecolor=gfp_color,
                    zorder=1,
                    alpha=0.2,
                )
                line_list.append(
                    ax.plot(
                        times, this_gfp, color=gfp_color, zorder=3, alpha=line_alpha
                    )[0]
                )
                ax.text(
                    times[0] + 0.01 * (times[-1] - times[0]),
                    this_gfp[0] + 0.05 * np.diff(ax.get_ylim())[0],
                    "GFP",
                    zorder=4,
                    color=gfp_color,
                    path_effects=gfp_path_effects,
                )
            for ii, line in zip(idx, line_list):
                if ii in bad_ch_idx:
                    line.set_zorder(2)
                    if spatial_colors is True:
                        line.set_linestyle("--")
            ax.set_ylabel(ch_unit)
            # for old matplotlib, we actually need this to have a bounding
            # box (!), so we have to put some valid text here, change
            # alpha and path effects later
            texts.append(
                ax.text(
                    0,
                    0,
                    "blank",
                    zorder=3,
                    verticalalignment="baseline",
                    horizontalalignment="left",
                    fontweight="bold",
                    alpha=0,
                )
            )

            if xlim is not None:
                if xlim == "tight":
                    xlim = (times[0], times[-1])
                ax.set_xlim(xlim)
            if ylim is not None and this_type in ylim:
                ax.set_ylim(ylim[this_type])
            ax.set(
                title=r"%s (%d channel%s)" % (titles[this_type], len(D), _pl(len(D)))
            )
            if ai == 0:
                _add_nave(ax, nave)
            if hline is not None:
                for h in hline:
                    c = "grey" if spatial_colors is True else "r"
                    ax.axhline(h, linestyle="--", linewidth=2, color=c)
        lines.append(line_list)
    if selectable:
        for ax in np.array(axes)[selectables]:
            if len(ax.lines) == 1:
                continue
            text = ax.annotate(
                "Loading...",
                xy=(0.01, 0.1),
                xycoords="axes fraction",
                fontsize=20,
                color="green",
                zorder=3,
            )
            text.set_visible(False)
            callback_onselect = partial(
                _line_plot_onselect,
                ch_types=ch_types_used,
                info=info,
                data=data,
                times=times,
                text=text,
                psd=psd,
                time_unit=time_unit,
                sphere=sphere,
            )
            blit = False if plt.get_backend() == "MacOSX" else True
            minspan = 0 if len(times) < 2 else times[1] - times[0]
            ax._span_selector = SpanSelector(
                ax,
                callback_onselect,
                "horizontal",
                minspan=minspan,
                useblit=blit,
                rectprops=dict(alpha=0.5, facecolor="red"),
            )


# Traceback (ValueError)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/anaconda3/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
339                 pass
340             else:
--> 341                 return printer(obj)
342             # Finally look for special method names
343             method = get_real_method(obj, self.print_method)

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
242
243     if 'png' in formats:
--> 244         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
245     if 'retina' in formats or 'png2x' in formats:
246         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
126
127     bytes_io = BytesIO()
--> 128     fig.canvas.print_figure(bytes_io, **kw)
129     data = bytes_io.getvalue()
130     if fmt == 'svg':

~/anaconda3/lib/python3.7/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, **kwargs)
2080                     orientation=orientation,
2081                     bbox_inches_restore=_bbox_inches_restore,
-> 2082                     **kwargs)
2083             finally:
2084                 if bbox_inches and restore_bbox:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, metadata, pil_kwargs, *args, **kwargs)
525
526         else:
--> 527             FigureCanvasAgg.draw(self)
528             renderer = self.get_renderer()
529             with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in draw(self)
384         Draw the figure using the renderer.
385         """
--> 386         self.renderer = self.get_renderer(cleared=True)
387         with RendererAgg.lock:
388             self.figure.draw(self.renderer)

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in get_renderer(self, cleared)
397                           and getattr(self, "_lastKey", None) == key)
398         if not reuse_renderer:
--> 399             self.renderer = RendererAgg(w, h, self.figure.dpi)
400             self._lastKey = key
401         elif cleared:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in __init__(self, width, height, dpi)
84         self.width = width
85         self.height = height
---> 86         self._renderer = _RendererAgg(int(width), int(height), dpi)
87         self._filter_renderers = []
88

ValueError: Image size of 115104x291 pixels is too large. It must be less than 2^16 in each direction.

<Figure size 432x288 with 6 Axes>

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/anaconda3/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
339                 pass
340             else:
--> 341                 return printer(obj)
342             # Finally look for special method names
343             method = get_real_method(obj, self.print_method)

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
242
243     if 'png' in formats:
--> 244         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
245     if 'retina' in formats or 'png2x' in formats:
246         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/anaconda3/lib/python3.7/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
126
127     bytes_io = BytesIO()
--> 128     fig.canvas.print_figure(bytes_io, **kw)
129     data = bytes_io.getvalue()
130     if fmt == 'svg':

~/anaconda3/lib/python3.7/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, **kwargs)
2080                     orientation=orientation,
2081                     bbox_inches_restore=_bbox_inches_restore,
-> 2082                     **kwargs)
2083             finally:
2084                 if bbox_inches and restore_bbox:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, metadata, pil_kwargs, *args, **kwargs)
525
526         else:
--> 527             FigureCanvasAgg.draw(self)
528             renderer = self.get_renderer()
529             with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in draw(self)
384         Draw the figure using the renderer.
385         """
--> 386         self.renderer = self.get_renderer(cleared=True)
387         with RendererAgg.lock:
388             self.figure.draw(self.renderer)

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in get_renderer(self, cleared)
397                           and getattr(self, "_lastKey", None) == key)
398         if not reuse_renderer:
--> 399             self.renderer = RendererAgg(w, h, self.figure.dpi)
400             self._lastKey = key
401         elif cleared:

~/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in __init__(self, width, height, dpi)
84         self.width = width
85         self.height = height
---> 86         self._renderer = _RendererAgg(int(width), int(height), dpi)
87         self._filter_renderers = []
88

ValueError: Image size of 115104x291 pixels is too large. It must be less than 2^16 in each direction.

# Fixed code
def _plot_lines(
    data,
    info,
    picks,
    fig,
    axes,
    spatial_colors,
    unit,
    units,
    scalings,
    hline,
    gfp,
    types,
    zorder,
    xlim,
    ylim,
    times,
    bad_ch_idx,
    titles,
    ch_types_used,
    selectable,
    psd,
    line_alpha,
    nave,
    time_unit,
    sphere,
):
    """Plot data as butterfly plot."""
    from matplotlib import patheffects, pyplot as plt
    from matplotlib.widgets import SpanSelector

    assert len(axes) == len(ch_types_used)
    texts = list()
    idxs = list()
    lines = list()
    sphere = _check_sphere(sphere, info)
    path_effects = [patheffects.withStroke(linewidth=2, foreground="w", alpha=0.75)]
    gfp_path_effects = [patheffects.withStroke(linewidth=5, foreground="w", alpha=0.75)]
    if selectable:
        selectables = np.ones(len(ch_types_used), dtype=bool)
        for type_idx, this_type in enumerate(ch_types_used):
            idx = picks[types == this_type]
            if len(idx) < 2 or (this_type == "grad" and len(idx) < 4):
                # prevent unnecessary warnings for e.g. EOG
                if this_type in _DATA_CH_TYPES_SPLIT:
                    logger.info(
                        "Need more than one channel to make "
                        "topography for %s. Disabling interactivity." % (this_type,)
                    )
                selectables[type_idx] = False

    if selectable:
        # Parameters for butterfly interactive plots
        params = dict(
            axes=axes,
            texts=texts,
            lines=lines,
            ch_names=info["ch_names"],
            idxs=idxs,
            need_draw=False,
            path_effects=path_effects,
        )
        fig.canvas.mpl_connect("pick_event", partial(_butterfly_onpick, params=params))
        fig.canvas.mpl_connect(
            "button_press_event", partial(_butterfly_on_button_press, params=params)
        )
    for ai, (ax, this_type) in enumerate(zip(axes, ch_types_used)):
        line_list = list()  # 'line_list' contains the lines for this axes
        if unit is False:
            this_scaling = 1.0
            ch_unit = "NA"  # no unit
        else:
            this_scaling = 1.0 if scalings is None else scalings[this_type]
            ch_unit = units[this_type]
        idx = list(picks[types == this_type])
        idxs.append(idx)

        if len(idx) > 0:
            # Set amplitude scaling
            D = this_scaling * data[idx, :]
            _check_if_nan(D)
            gfp_only = isinstance(gfp, str) and gfp == "only"
            if not gfp_only:
                chs = [info["chs"][i] for i in idx]
                locs3d = np.array([ch["loc"][:3] for ch in chs])
                if spatial_colors is True and not _check_ch_locs(chs):
                    warn("Channel locations not available. Disabling spatial colors.")
                    spatial_colors = selectable = False
                if spatial_colors is True and len(idx) != 1:
                    x, y, z = locs3d.T
                    colors = _rgb(x, y, z)
                    _handle_spatial_colors(
                        colors, info, idx, this_type, psd, ax, sphere
                    )
                else:
                    if isinstance(spatial_colors, (tuple, str)):
                        col = [spatial_colors]
                    else:
                        col = ["k"]
                    colors = col * len(idx)
                    for i in bad_ch_idx:
                        if i in idx:
                            colors[idx.index(i)] = "r"

                if zorder == "std":
                    # find the channels with the least activity
                    # to map them in front of the more active ones
                    z_ord = D.std(axis=1).argsort()
                elif zorder == "unsorted":
                    z_ord = list(range(D.shape[0]))
                elif not callable(zorder):
                    error = '`zorder` must be a function, "std" or "unsorted", not {0}.'
                    raise TypeError(error.format(type(zorder)))
                else:
                    z_ord = zorder(D)

                # plot channels
                for ch_idx, z in enumerate(z_ord):
                    line_list.append(
                        ax.plot(
                            times,
                            D[ch_idx],
                            picker=3.0,
                            zorder=z + 1 if spatial_colors is True else 1,
                            color=colors[ch_idx],
                            alpha=line_alpha,
                            linewidth=0.5,
                        )[0]
                    )

            if gfp:  # 'only' or boolean True
                gfp_color = 3 * (0.0,) if spatial_colors is True else (0.0, 1.0, 0.0)
                this_gfp = np.sqrt((D * D).mean(axis=0))
                this_ylim = (
                    ax.get_ylim()
                    if (ylim is None or this_type not in ylim.keys())
                    else ylim[this_type]
                )
                if gfp_only:
                    y_offset = 0.0
                else:
                    y_offset = this_ylim[0]
                this_gfp += y_offset
                ax.fill_between(
                    times,
                    y_offset,
                    this_gfp,
                    color="none",
                    facecolor=gfp_color,
                    zorder=1,
                    alpha=0.2,
                )
                line_list.append(
                    ax.plot(
                        times, this_gfp, color=gfp_color, zorder=3, alpha=line_alpha
                    )[0]
                )
                ax.text(
                    times[0] + 0.01 * (times[-1] - times[0]),
                    this_gfp[0] + 0.05 * np.diff(ax.get_ylim())[0],
                    "GFP",
                    zorder=4,
                    color=gfp_color,
                    path_effects=gfp_path_effects,
                )
            for ii, line in zip(idx, line_list):
                if ii in bad_ch_idx:
                    line.set_zorder(2)
                    if spatial_colors is True:
                        line.set_linestyle("--")
            ax.set_ylabel(ch_unit)
            # for old matplotlib, we actually need this to have a bounding
            # box (!), so we have to put some valid text here, change
            # alpha and path effects later
            texts.append(
                ax.text(
                    0,
                    0,
                    "blank",
                    zorder=3,
                    verticalalignment="baseline",
                    horizontalalignment="left",
                    fontweight="bold",
                    alpha=0,
                    clip_on=True,
                )
            )

            if xlim is not None:
                if xlim == "tight":
                    xlim = (times[0], times[-1])
                ax.set_xlim(xlim)
            if ylim is not None and this_type in ylim:
                ax.set_ylim(ylim[this_type])
            ax.set(
                title=r"%s (%d channel%s)" % (titles[this_type], len(D), _pl(len(D)))
            )
            if ai == 0:
                _add_nave(ax, nave)
            if hline is not None:
                for h in hline:
                    c = "grey" if spatial_colors is True else "r"
                    ax.axhline(h, linestyle="--", linewidth=2, color=c)
        lines.append(line_list)
    if selectable:
        for ax in np.array(axes)[selectables]:
            if len(ax.lines) == 1:
                continue
            text = ax.annotate(
                "Loading...",
                xy=(0.01, 0.1),
                xycoords="axes fraction",
                fontsize=20,
                color="green",
                zorder=3,
            )
            text.set_visible(False)
            callback_onselect = partial(
                _line_plot_onselect,
                ch_types=ch_types_used,
                info=info,
                data=data,
                times=times,
                text=text,
                psd=psd,
                time_unit=time_unit,
                sphere=sphere,
            )
            blit = False if plt.get_backend() == "MacOSX" else True
            minspan = 0 if len(times) < 2 else times[1] - times[0]
            ax._span_selector = SpanSelector(
                ax,
                callback_onselect,
                "horizontal",
                minspan=minspan,
                useblit=blit,
                rectprops=dict(alpha=0.5, facecolor="red"),
            )