예제 #1
0
    def update(self, name = None):
        """
        Update all plots.  Note that when calling this function, we assume that you've updated the data returned by the
        callback.  When you call update multiple times without updating the data it can lead to incorrect results on
        plots with history (samples will be repeated)
        :param name: The name of the plot to update.  If not specified, updates all plots.
        """
        self._counter += 1
        if self._counter % self._update_every != 0:
            return

        data_dict = self._get_data_structure()  # dict : str -> IPlot

        if self._plots is None or set(data_dict.keys()) != self._plot_keys:
            # Note - this causes us to reset all plots (including ones with history
            # every time a new plot comes in, but that's ok for now).
            if self._fig is not None:
                self._fig.clf()
            else:
                self._fig = eplt.figure()
            self._plots = self._get_plots_from_first_data(data_dict)
            self._plot_keys = set(self._plots.keys())
            plot_data_dict(data_dict, plots = self._plots, hang = False, figure = self._fig)
        else:
            if name is None:  # Update all plots
                for k, v in data_dict.iteritems():
                    self._plots[k].update(v)
                    self._plots[k].plot()
            else:
                self._plots[name].update(data_dict[name])
                self._plots[name].plot()

        redraw_figure(self._fig)
예제 #2
0
def hold_dbplots(fig=None, draw_every=None):
    """
    Use this in a "with" statement to prevent plotting until the end.
    :param fig:
    :return:
    """
    if is_server_plotting_on():
        # For now, this does nothing.  Eventually, it should be made to send a "draw" command through the pipe
        yield
        return

    global _hold_plots
    _old_hold_state = _hold_plots
    _hold_plots = True
    yield
    _hold_plots = _old_hold_state

    if _old_hold_state:
        plot_now = False
    elif draw_every is not None:
        global _hold_plot_counter
        plot_now = _hold_plot_counter % draw_every == 0
        _hold_plot_counter += 1
    else:
        plot_now = True

    if plot_now and fig in _DBPLOT_FIGURES:
        redraw_figure(_DBPLOT_FIGURES[fig].figure)
예제 #3
0
def replot_and_redraw_figure(fig):

    for subplot in _DBPLOT_FIGURES[fig].subplots.values():
        plt.subplot(subplot.axis)
        subplot.plot_object.plot()

    redraw_figure(_DBPLOT_FIGURES[fig].figure)
예제 #4
0
    def update(self, name = None):
        """
        Update all plots.  Note that when calling this function, we assume that you've updated the data returned by the
        callback.  When you call update multiple times without updating the data it can lead to incorrect results on
        plots with history (samples will be repeated)
        :param name: The name of the plot to update.  If not specified, updates all plots.
        """
        self._counter += 1
        if self._counter % self._update_every != 0:
            return

        data_dict = self._get_data_structure()  # dict : str -> IPlot

        if self._plots is None or set(data_dict.keys()) != self._plot_keys:
            # Note - this causes us to reset all plots (including ones with history
            # every time a new plot comes in, but that's ok for now).
            if self._fig is not None:
                self._fig.clf()
            else:
                self._fig = plt.figure()
            self._plots = self._get_plots_from_first_data(data_dict)
            self._plot_keys = set(self._plots.keys())
            plot_data_dict(data_dict, plots = self._plots, hang = False, figure = self._fig)
        else:
            if name is None:  # Update all plots
                for k, v in data_dict.items():
                    self._plots[k].update(v)
                    self._plots[k].plot()
            else:
                self._plots[name].update(data_dict[name])
                self._plots[name].plot()

        redraw_figure(self._fig)
예제 #5
0
def replot_and_redraw_figure(fig):

    for subplot in _DBPLOT_FIGURES[fig].subplots.values():
        plt.subplot(subplot.axis)
        subplot.plot_object.plot()

    redraw_figure(_DBPLOT_FIGURES[fig].figure)
예제 #6
0
def display_figure(fig, hang):
    if hang is True:
        plt.figure(fig.number)
        plt.show()
    elif hang in (None, False):
        redraw_figure(fig)
    elif isinstance(hang, (int, float)):
        redraw_figure(fig)
        plt.pause(hang)
    else:
        raise TypeError("Can't interpret hang argument {}".format(hang))
예제 #7
0
def hold_dbplots(fig=None, plot_every=None):
    """
    Use this in a "with" statement to prevent plotting until the end.
    :param fig:
    :return:
    """
    global _hold_plots
    _hold_plots = True
    yield
    _hold_plots = False

    if plot_every is not None:
        global _hold_plot_counter
        plot_now = _hold_plot_counter % plot_every == 0
        _hold_plot_counter += 1
    else:
        plot_now = True

    if plot_now:
        redraw_figure(_DBPLOT_FIGURES[fig].figure)
예제 #8
0
def dbplot(data,
           name=None,
           plot_type=None,
           axis=None,
           plot_mode='live',
           draw_now=True,
           hang=False,
           title=None,
           fig=None,
           xlabel=None,
           ylabel=None,
           draw_every=None,
           layout=None,
           legend=None,
           grid=False,
           wait_for_display_sec=0,
           cornertext=None):
    """
    Plot arbitrary data and continue execution.  This program tries to figure out what type of plot to use.

    :param data: Any data.  Hopefully, we at dbplot will be able to figure out a plot for it.
    :param name: A name uniquely identifying this plot.
    :param plot_type: A specialized constructor to be used the first time when plotting.  You can also pass
        certain string to give hints as to what kind of plot you want (can resolve cases where the given data could be
        plotted in multiple ways):
        'line': Plots a line plot
        'img': An image plot
        'colour': A colour image plot
        'pic': A picture (no scale bars, axis labels, etc).
    :param axis: A string identifying which axis to plot on.  By default, it is the same as "name".  Only use this
        argument if you indend to make multiple dbplots share the same axis.
    :param plot_mode: Influences how the data should be used to choose the plot type:
        'live': Best for 'live' plots that you intend to update as new data arrives
        'static': Best for 'static' plots, that you do not intend to update
        'image': Try to represent the plot as an image
    :param draw_now: Draw the plot now (you may choose false if you're going to add another plot immediately after and
        don't want have to draw this one again.
    :param hang: Hang on the plot (wait for it to be closed before continuing)
    :param title: Title of the plot (will default to name if not included)
    :param fig: Name of the figure - use this when you want to create multiple figures.
    :param grid: Turn the grid on
    :param wait_for_display_sec: In server mode, you can choose to wait maximally wait_for_display_sec seconds before this
        call returns. In case plotting is finished earlier, the call returns earlier. Setting wait_for_display_sec to a negative number will cause the call to block until the plot has been displayed.
    """
    if is_server_plotting_on():
        # Redirect the function call to the plotting server.  The flag gets turned on in a configuration file.  It is
        # turned off when this file is run ON the plotting server, from the first line in plotting_server.py
        arg_locals = locals().copy()
        from artemis.remote.plotting.plotting_client import dbplot_remotely
        dbplot_remotely(arg_locals=arg_locals)
        return

    if isinstance(fig, plt.Figure):
        assert None not in _DBPLOT_FIGURES, "If you pass a figure, you can only do it on the first call to dbplot (for now)"
        _DBPLOT_FIGURES[None] = _PlotWindow(figure=fig,
                                            subplots=OrderedDict(),
                                            axes={})
        fig = None
    elif fig not in _DBPLOT_FIGURES or not plt.fignum_exists(
            _DBPLOT_FIGURES[fig].figure.number
    ):  # Second condition handles closed figures.
        _DBPLOT_FIGURES[fig] = _PlotWindow(figure=_make_dbplot_figure(),
                                           subplots=OrderedDict(),
                                           axes={})
        if fig is not None:
            _DBPLOT_FIGURES[fig].figure.canvas.set_window_title(fig)

    suplot_dict = _DBPLOT_FIGURES[fig].subplots

    if axis is None:
        axis = name

    if name not in suplot_dict:

        if isinstance(plot_type, str):
            plot = PLOT_CONSTRUCTORS[plot_type]()
        elif plot_type is None:
            plot = get_plot_from_data(data, mode=plot_mode)
        else:
            assert hasattr(plot_type, "__call__")
            plot = plot_type()

        if isinstance(axis, SubplotSpec):
            axis = plt.subplot(axis)
        if isinstance(axis, Axes):
            ax = axis
            ax_name = str(axis)
        elif isinstance(axis, string_types) or axis is None:
            ax = select_subplot(
                axis,
                fig=_DBPLOT_FIGURES[fig].figure,
                layout=_default_layout if layout is None else layout)
            ax_name = axis
            # ax.set_title(axis)
        else:
            raise Exception(
                "Axis specifier must be a string, an Axis object, or a SubplotSpec object.  Not {}"
                .format(axis))

        if ax_name not in _DBPLOT_FIGURES[fig].axes:
            ax.set_title(name)
            _DBPLOT_FIGURES[fig].subplots[name] = _Subplot(axis=ax,
                                                           plot_object=plot)
            _DBPLOT_FIGURES[fig].axes[ax_name] = ax

        _DBPLOT_FIGURES[fig].subplots[name] = _Subplot(
            axis=_DBPLOT_FIGURES[fig].axes[ax_name], plot_object=plot)
        plt.sca(_DBPLOT_FIGURES[fig].axes[ax_name])
        if xlabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_xlabel(xlabel)
        if ylabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_ylabel(ylabel)
        if draw_every is not None:
            _draw_counters[fig, name] = -1

        if grid:
            plt.grid()

    # Update the relevant data and plot it.  TODO: Add option for plotting update interval
    plot = _DBPLOT_FIGURES[fig].subplots[name].plot_object
    plot.update(data)
    plot.plot()

    if cornertext is not None:
        if not hasattr(_DBPLOT_FIGURES[fig].figure, '__cornertext'):
            _DBPLOT_FIGURES[fig].figure.__cornertext = next(
                iter(_DBPLOT_FIGURES[fig].subplots.values())).axis.annotate(
                    cornertext,
                    xy=(0, 0),
                    xytext=(0.01, 0.98),
                    textcoords='figure fraction')
        else:
            _DBPLOT_FIGURES[fig].figure.__cornertext.set_text(cornertext)
    if title is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.set_title(title)
    if legend is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.legend(legend,
                                                        loc='best',
                                                        framealpha=0.5)

    if draw_now and not _hold_plots:
        if draw_every is not None:
            _draw_counters[fig, name] += 1
            if _draw_counters[fig, name] % draw_every != 0:
                return _DBPLOT_FIGURES[fig].subplots[name].axis
        if hang:
            plt.figure(_DBPLOT_FIGURES[fig].figure.number)
            plt.show()
        else:
            redraw_figure(_DBPLOT_FIGURES[fig].figure)
    return _DBPLOT_FIGURES[fig].subplots[name].axis
예제 #9
0
def dbplot_hang(timeout=None):
    if timeout is None:
        plt.show()
    else:
        redraw_figure()
        plt.pause(timeout)
예제 #10
0
def dbplot(data,
           name=None,
           plot_type=None,
           axis=None,
           plot_mode='live',
           draw_now=True,
           hang=False,
           title=None,
           fig=None,
           xlabel=None,
           ylabel=None,
           draw_every=None,
           layout=None,
           legend=None,
           grid=False,
           wait_for_display_sec=0):
    """
    Plot arbitrary data.  This program tries to figure out what type of plot to use.

    :param data: Any data.  Hopefully, we at dbplot will be able to figure out a plot for it.
    :param name: A name uniquely identifying this plot.
    :param plot_type: A specialized constructor to be used the first time when plotting.  You can also pass
        certain string to give hints as to what kind of plot you want (can resolve cases where the given data could be
        plotted in multiple ways):
        'line': Plots a line plot
        'img': An image plot
        'colour': A colour image plot
        'pic': A picture (no scale bars, axis labels, etc).
    :param axis: A string identifying which axis to plot on.  By default, it is the same as "name".  Only use this
        argument if you indend to make multiple dbplots share the same axis.
    :param plot_mode: Influences how the data should be used to choose the plot type:
        'live': Best for 'live' plots that you intend to update as new data arrives
        'static': Best for 'static' plots, that you do not intend to update
        'image': Try to represent the plot as an image
    :param draw_now: Draw the plot now (you may choose false if you're going to add another plot immediately after and
        don't want have to draw this one again.
    :param hang: Hang on the plot (wait for it to be closed before continuing)
    :param title: Title of the plot (will default to name if not included)
    :param fig: Name of the figure - use this when you want to create multiple figures.
    :param grid: Turn the grid on
    :param wait_for_display_sec: In server mode, you can choose to wait maximally wait_for_display_sec seconds before this call returns. In case plotting
    is finished earlier, the call returns earlier. Setting wait_for_display_sec to a negative number will cause the call to block until the plot has been displayed.
    """
    if is_server_plotting_on():
        # Redirect the function call to the plotting server.  The flag gets turned on in a configuration file.  It is
        # turned off when this file is run ON the plotting server, from the first line in plotting_server.py
        arg_locals = locals().copy()
        from artemis.remote.plotting.plotting_client import dbplot_remotetly
        dbplot_remotetly(arg_locals=arg_locals)
        return

    if isinstance(fig, plt.Figure):
        assert None not in _DBPLOT_FIGURES, "If you pass a figure, you can only do it on the first call to dbplot (for now)"
        _DBPLOT_FIGURES[None] = fig
        fig = None
    elif fig not in _DBPLOT_FIGURES:
        _DBPLOT_FIGURES[fig] = _PlotWindow(figure=_make_dbplot_figure(),
                                           subplots=OrderedDict(),
                                           axes={})
        if fig is not None:
            _DBPLOT_FIGURES[fig].figure.canvas.set_window_title(fig)

    suplot_dict = _DBPLOT_FIGURES[fig].subplots

    if axis is None:
        axis = name

    if name not in suplot_dict:

        if isinstance(plot_type, str):
            plot = {
                'line':
                LinePlot,
                'thick-line':
                lambda: LinePlot(plot_kwargs={'linewidth': 3}),
                'pos_line':
                lambda: LinePlot(y_bounds=(0, None), y_bound_extend=(0, 0.05)),
                # 'pos_line': lambda: LinePlot(y_bounds=(0, None)),
                'bar':
                BarPlot,
                'img':
                ImagePlot,
                'colour':
                lambda: ImagePlot(is_colour_data=True),
                'equal_aspect':
                lambda: ImagePlot(aspect='equal'),
                'image_history':
                lambda: MovingImagePlot(),
                'fixed_line_history':
                lambda: MovingPointPlot(buffer_len=100),
                'pic':
                lambda: ImagePlot(show_clims=False, aspect='equal'),
                'notice':
                lambda: TextPlot(max_history=1,
                                 horizontal_alignment='center',
                                 vertical_alignment='center',
                                 size='x-large'),
                'cost':
                lambda: MovingPointPlot(y_bounds=(0, None),
                                        y_bound_extend=(0, 0.05)),
                'percent':
                lambda: MovingPointPlot(y_bounds=(0, 100)),
                'trajectory':
                lambda: Moving2DPointPlot(axes_update_mode='expand'),
                'trajectory+':
                lambda: Moving2DPointPlot(axes_update_mode='expand',
                                          x_bounds=(0, None),
                                          y_bounds=(0, None)),
                'histogram':
                lambda: HistogramPlot(edges=np.linspace(-5, 5, 20)),
                'cumhist':
                lambda: CumulativeLineHistogram(edges=np.linspace(-5, 5, 20)),
            }[plot_type]()
        elif plot_type is None:
            plot = get_plot_from_data(data, mode=plot_mode)
        else:
            assert hasattr(plot_type, "__call__")
            plot = plot_type()

        if isinstance(axis, SubplotSpec):
            axis = plt.subplot(axis)
        if isinstance(axis, Axes):
            ax = axis
            ax_name = str(axis)
        elif isinstance(axis, basestring) or axis is None:
            ax = select_subplot(
                axis,
                fig=_DBPLOT_FIGURES[fig].figure,
                layout=_default_layout if layout is None else layout)
            ax_name = axis
            # ax.set_title(axis)
        else:
            raise Exception(
                "Axis specifier must be a string, an Axis object, or a SubplotSpec object.  Not {}"
                .format(axis))

        if ax_name not in _DBPLOT_FIGURES[fig].axes:
            ax.set_title(name)
            _DBPLOT_FIGURES[fig].subplots[name] = _Subplot(axis=ax,
                                                           plot_object=plot)
            _DBPLOT_FIGURES[fig].axes[ax_name] = ax

        _DBPLOT_FIGURES[fig].subplots[name] = _Subplot(
            axis=_DBPLOT_FIGURES[fig].axes[ax_name], plot_object=plot)
        plt.sca(_DBPLOT_FIGURES[fig].axes[ax_name])
        if xlabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_xlabel(xlabel)
        if ylabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_ylabel(ylabel)
        if draw_every is not None:
            _draw_counters[fig, name] = -1

        if grid:
            plt.grid()

    # Update the relevant data and plot it.  TODO: Add option for plotting update interval
    plot = _DBPLOT_FIGURES[fig].subplots[name].plot_object
    plot.update(data)
    plot.plot()
    if title is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.set_title(title)
    if legend is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.legend(legend,
                                                        loc='best',
                                                        framealpha=0.5)

    if draw_now and not _hold_plots:
        if draw_every is not None:
            _draw_counters[fig, name] += 1
            if _draw_counters[fig, name] % draw_every != 0:
                return _DBPLOT_FIGURES[fig].subplots[name].axis
        if hang:
            plt.figure(_DBPLOT_FIGURES[fig].figure.number)
            plt.show()
        else:
            redraw_figure(_DBPLOT_FIGURES[fig].figure)
    return _DBPLOT_FIGURES[fig].subplots[name].axis
예제 #11
0
def dbplot(data, name = None, plot_type = None, axis=None, plot_mode = 'live', draw_now = True, hang = False, title=None,
           fig = None, xlabel = None, ylabel = None, draw_every = None, layout=None, legend=None, grid=False,
           wait_for_display_sec=0, cornertext = None, reset_color_cycle = False):
    """
    Plot arbitrary data and continue execution.  This program tries to figure out what type of plot to use.

    :param data: Any data.  Hopefully, we at dbplot will be able to figure out a plot for it.
    :param name: A name uniquely identifying this plot.
    :param plot_type: A specialized constructor to be used the first time when plotting.  You can also pass
        certain string to give hints as to what kind of plot you want (can resolve cases where the given data could be
        plotted in multiple ways):
        'line': Plots a line plot
        'img': An image plot
        'colour': A colour image plot
        'pic': A picture (no scale bars, axis labels, etc).
    :param axis: A string identifying which axis to plot on.  By default, it is the same as "name".  Only use this
        argument if you indend to make multiple dbplots share the same axis.
    :param plot_mode: Influences how the data should be used to choose the plot type:
        'live': Best for 'live' plots that you intend to update as new data arrives
        'static': Best for 'static' plots, that you do not intend to update
        'image': Try to represent the plot as an image
    :param draw_now: Draw the plot now (you may choose false if you're going to add another plot immediately after and
        don't want have to draw this one again.
    :param hang: Hang on the plot (wait for it to be closed before continuing)
    :param title: Title of the plot (will default to name if not included)
    :param fig: Name of the figure - use this when you want to create multiple figures.
    :param grid: Turn the grid on
    :param wait_for_display_sec: In server mode, you can choose to wait maximally wait_for_display_sec seconds before this
        call returns. In case plotting is finished earlier, the call returns earlier. Setting wait_for_display_sec to a negative number will cause the call to block until the plot has been displayed.
    """
    if is_server_plotting_on():
        # Redirect the function call to the plotting server.  The flag gets turned on in a configuration file.  It is
        # turned off when this file is run ON the plotting server, from the first line in plotting_server.py
        arg_locals = locals().copy()
        from artemis.remote.plotting.plotting_client import dbplot_remotely
        dbplot_remotely(arg_locals=arg_locals)
        return

    if isinstance(fig, plt.Figure):
        assert None not in _DBPLOT_FIGURES, "If you pass a figure, you can only do it on the first call to dbplot (for now)"
        _DBPLOT_FIGURES[None] = _PlotWindow(figure=fig, subplots=OrderedDict(), axes={})
        fig = None
    elif fig not in _DBPLOT_FIGURES or not plt.fignum_exists(_DBPLOT_FIGURES[fig].figure.number):  # Second condition handles closed figures.
        _DBPLOT_FIGURES[fig] = _PlotWindow(figure = _make_dbplot_figure(), subplots=OrderedDict(), axes = {})
        if fig is not None:
            _DBPLOT_FIGURES[fig].figure.canvas.set_window_title(fig)

    suplot_dict = _DBPLOT_FIGURES[fig].subplots

    if axis is None:
        axis=name

    if name not in suplot_dict:  # Initialize new axis

        if isinstance(plot_type, str):
            plot = PLOT_CONSTRUCTORS[plot_type]()
        elif isinstance(plot_type, tuple):
            assert len(plot_type)==2 and isinstance(plot_type[0], str) and isinstance(plot_type[1], dict), 'If you specify a tuple for plot_type, we expect (name, arg_dict).  Got: {}'.format(plot_type)
            plot_type_name, plot_type_args = plot_type
            plot = PLOT_CONSTRUCTORS[plot_type_name](**plot_type_args)
        elif plot_type is None:
            plot = get_plot_from_data(data, mode=plot_mode)
        else:
            assert hasattr(plot_type, "__call__")
            plot = plot_type()

        if isinstance(axis, SubplotSpec):
            axis = plt.subplot(axis)
        if isinstance(axis, Axes):
            ax = axis
            ax_name = str(axis)
        elif isinstance(axis, string_types) or axis is None:
            ax = select_subplot(axis, fig=_DBPLOT_FIGURES[fig].figure, layout=_default_layout if layout is None else layout)
            ax_name = axis
            # ax.set_title(axis)
        else:
            raise Exception("Axis specifier must be a string, an Axis object, or a SubplotSpec object.  Not {}".format(axis))

        if ax_name not in _DBPLOT_FIGURES[fig].axes:
            ax.set_title(name)
            _DBPLOT_FIGURES[fig].subplots[name] = _Subplot(axis=ax, plot_object=plot)
            _DBPLOT_FIGURES[fig].axes[ax_name] = ax

        _DBPLOT_FIGURES[fig].subplots[name] = _Subplot(axis=_DBPLOT_FIGURES[fig].axes[ax_name], plot_object=plot)
        plt.sca(_DBPLOT_FIGURES[fig].axes[ax_name])
        if xlabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_xlabel(xlabel)
        if ylabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_ylabel(ylabel)
        if draw_every is not None:
            _draw_counters[fig, name] = Checkpoints(draw_every)

        if grid:
            plt.grid()

    plot = _DBPLOT_FIGURES[fig].subplots[name].plot_object
    if reset_color_cycle:
        get_dbplot_axis(axis_name=axis, fig=fig).set_color_cycle(None)

    plot.update(data)

    # Update Labels...
    if cornertext is not None:
        if not hasattr(_DBPLOT_FIGURES[fig].figure, '__cornertext'):
            _DBPLOT_FIGURES[fig].figure.__cornertext = next(iter(_DBPLOT_FIGURES[fig].subplots.values())).axis.annotate(cornertext, xy=(0, 0), xytext=(0.01, 0.98), textcoords='figure fraction')
        else:
            _DBPLOT_FIGURES[fig].figure.__cornertext.set_text(cornertext)
    if title is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.set_title(title)
    if legend is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.legend(legend, loc='best', framealpha=0.5)

    if draw_now and not _hold_plots and (draw_every is None or ((fig, name) not in _draw_counters) or _draw_counters[fig, name]()):
        plot.plot()
        if hang:
            plt.figure(_DBPLOT_FIGURES[fig].figure.number)
            plt.show()
        else:
            redraw_figure(_DBPLOT_FIGURES[fig].figure)
    return _DBPLOT_FIGURES[fig].subplots[name].axis
예제 #12
0
def dbplot(data,
           name=None,
           plot_type=None,
           plot_mode='live',
           draw_now=True,
           hang=False,
           title=None,
           fig=None,
           xlabel=None,
           ylabel=None,
           draw_every=None,
           legend=None,
           plot_constructor=None):
    """
    Plot arbitrary data.  This program tries to figure out what type of plot to use.

    :param data: Any data.  Hopefully, we at dbplot will be able to figure out a plot for it.
    :param name: A name uniquely identifying this plot.
    :param plot_type: A specialized constructor to be used the first time when plotting.  You can also pass
        certain string to give hints as to what kind of plot you want (can resolve cases where the given data could be
        plotted in multiple ways):
        'line': Plots a line plot
        'img': An image plot
        'colour': A colour image plot
        'pic': A picture (no scale bars, axis labels, etc).
    :param plot_mode: Influences how the data should be used to choose the plot type:
        'live': Best for 'live' plots that you intend to update as new data arrives
        'static': Best for 'static' plots, that you do not intend to update
        'image': Try to represent the plot as an image
    :param draw_now: Draw the plot now (you may choose false if you're going to add another plot immediately after and
        don't want have to draw this one again.
    :param hang: Hang on the plot (wait for it to be closed before continuing)
    :param title: Title of the plot (will default to name if not included)
    :param fig: Name of the figure - use this when you want to create multiple figures.
    """

    if isinstance(fig, plt.Figure):
        assert None not in _DBPLOT_FIGURES, "If you pass a figure, you can only do it on the first call to dbplot (for now)"
        _DBPLOT_FIGURES[None] = fig
        fig = None
    elif fig not in _DBPLOT_FIGURES:
        _DBPLOT_FIGURES[fig] = _PlotWindow(figure=_make_dbplot_figure(),
                                           subplots=OrderedDict())
        if name is not None:
            _DBPLOT_FIGURES[fig].figure.canvas.set_window_title(fig)

    suplot_dict = _DBPLOT_FIGURES[fig].subplots

    if name not in suplot_dict:

        if plot_constructor is not None:
            print "Warning: The 'plot_constructor' argument to dbplot is deprecated.  Use plot_type instead"
            assert plot_type is None
            plot_type = plot_constructor

        if isinstance(plot_type, str):
            plot = {
                'line':
                LinePlot,
                'pos_line':
                lambda: LinePlot(y_bounds=(0, None), y_bound_extend=(0, 0.05)),
                # 'pos_line': lambda: LinePlot(y_bounds=(0, None)),
                'img':
                ImagePlot,
                'colour':
                lambda: ImagePlot(is_colour_data=True),
                'equal_aspect':
                lambda: ImagePlot(aspect='equal'),
                'image_history':
                lambda: MovingImagePlot(),
                'pic':
                lambda: ImagePlot(show_clims=False, aspect='equal'),
                'notice':
                lambda: TextPlot(max_history=1,
                                 horizontal_alignment='center',
                                 vertical_alignment='center',
                                 size='x-large'),
                'cost':
                lambda: MovingPointPlot(y_bounds=(0, None),
                                        y_bound_extend=(0, 0.05)),
                'percent':
                lambda: MovingPointPlot(y_bounds=(0, 100)),
                'trajectory':
                lambda: Moving2DPointPlot(),
                'histogram':
                lambda: HistogramPlot(edges=np.linspace(-5, 5, 20)),
                'cumhist':
                lambda: CumulativeLineHistogram(edges=np.linspace(-5, 5, 20)),
            }[plot_type]()
        elif plot_type is None:
            plot = get_plot_from_data(data, mode=plot_mode)
        else:
            assert hasattr(plot_type, "__call__")
            plot = plot_type()

        _extend_subplots(
            fig=fig, subplot_name=name,
            plot_object=plot)  # This guarantees that the new plot will exist
        if xlabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_xlabel(xlabel)
        if ylabel is not None:
            _DBPLOT_FIGURES[fig].subplots[name].axis.set_ylabel(ylabel)
        if draw_every is not None:
            _draw_counters[fig, name] = -1

    # Update the relevant data and plot it.  TODO: Add option for plotting update interval
    plot = _DBPLOT_FIGURES[fig].subplots[name].plot_object
    plot.update(data)
    plot.plot()
    if title is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.set_title(title)
    if legend is not None:
        _DBPLOT_FIGURES[fig].subplots[name].axis.legend(legend)

    if draw_now and not _hold_plots:
        if draw_every is not None:
            _draw_counters[fig, name] += 1
            if _draw_counters[fig, name] % draw_every != 0:
                return _DBPLOT_FIGURES[fig].subplots[name].axis
        if hang:
            plt.figure(_DBPLOT_FIGURES[fig].figure.number)
            plt.show()
        else:
            redraw_figure(_DBPLOT_FIGURES[fig].figure)
    return _DBPLOT_FIGURES[fig].subplots[name].axis