Example #1
0
    def __call__( self, *args, **kwargs ):
        """Log the data passed via *args, and send them to the plotting
        process, if available."""
        finished = False
        save_figure = ''
        x_values = None
        igs = nm.arange(self.n_gr)
        full = True
        if kwargs:
            if 'finished' in kwargs:
                finished = kwargs['finished']
            if 'save_figure' in kwargs:
                save_figure = kwargs['save_figure']
            if 'x' in kwargs:
                x_values = kwargs['x']

            if 'igs' in kwargs:
                igs = nm.array(kwargs['igs'])
                full = False
                
        if save_figure and (self.plot_pipe is not None):
            self.plot_pipe.send( ['save', save_figure] )
            ok = self.plot_pipe.recv()

        if finished:
            self.terminate()
            return

        ls = len( args ), self.n_arg
        if full and (ls[0] != ls[1]):
            if kwargs:
                return
            else:
                msg = 'log called with wrong number of arguments! (%d == %d)' \
                      % ls
                raise IndexError( msg )

        for ig in igs:
            if (x_values is not None) and (x_values[ig] is not None):
                self.x_values[ig].append(x_values[ig])
            else:
                if len(self.x_values[ig]):
                    ii = self.x_values[ig][-1] + 1
                else:
                    ii = 0
                self.x_values[ig].append(ii)

        for ig, ii, iseq, name in self.iter_names(igs):
            aux = args[iseq]
            if isinstance( aux, nm.ndarray ):
                aux = nm.array( aux, ndmin = 1 )
                if len( aux ) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, 'can log only scalars (%s)' % aux
            key = name_to_key( name, ii )
            self.data[key].append( aux )

            if self.output:
                self.output(('%%s: %%s: %s' % self.formats[key])
                            % (name, self.x_values[ig][-1], aux))

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register( self.terminate )

                self.__class__.count += 1

                self.plot_pipe, plotter_pipe = Pipe()
                self.plotter = ProcessPlotter( self.aggregate )
                self.plot_process = Process( target = self.plotter,
                                             args = (plotter_pipe,
                                                     self.get_log_name(),
                                                     self.data_names,
                                                     self.yscales,
                                                     self.xlabels,
                                                     self.ylabels) )
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data(igs)
            
        self.n_calls += 1
Example #2
0
class Log( Struct ):
    """Log data and (optionally) plot them in the second process via
    ProcessPlotter."""
    count = -1

    def from_conf( conf, data_names ):
        """
        Parameters
        ----------
        data_names : tuple of str
            The data names grouped by subplots: ([name1, name2, ...], [name3,
            name4, ...], ...), where name<n> are strings to display in
            (sub)plot legends.
        """
        if not isinstance( data_names, tuple ):
            data_names = (data_names,)

        obj = Log(data_names, **conf)

        return obj
    from_conf = staticmethod( from_conf )

    def __init__(self, data_names=None, yscales=None,
                 xlabels=None, ylabels=None, is_plot=True, aggregate=200,
                 formats=None, log_filename=None):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        try:
            import matplotlib as mpl
        except:
            mpl = None

        if (mpl is not None) and mpl.rcParams['backend'] == 'GTKAgg':
            can_live_plot = True
        else:
            can_live_plot = False

        Struct.__init__(self, data_names = {},
                        n_arg = 0, n_gr = 0,
                        data = {}, x_values = {}, n_calls = 0,
                        yscales = {}, xlabels = {}, ylabels = {},
                        plot_pipe = None, formats = {}, output = None)

        if data_names is not None:
            n_gr = len(data_names)
        else:
            n_gr = 0
            data_names = []

        yscales = get_default(yscales, ['linear'] * n_gr)
        xlabels = get_default(xlabels, ['iteration'] * n_gr)
        ylabels = get_default(ylabels, [''] * n_gr )

        if formats is None:
            formats = [None] * n_gr

        for ig, names in enumerate(data_names):
            self.add_group(names, yscales[ig], xlabels[ig], ylabels[ig],
                           formats[ig])

        self.is_plot = get_default( is_plot, True )
        self.aggregate = get_default( aggregate, 100 )

        self.can_plot = (can_live_plot and (mpl is not None)
                         and (Process is not None))

        if log_filename is not None:
            self.output = Output('', filename=log_filename)
            self.output('# started: %s' % time.asctime())
            self.output('# groups: %d' % n_gr)
            for ig, names in enumerate(data_names):
                self.output('#   %d' % ig)
                self.output('#     xlabel: "%s", ylabel: "%s", yscales: "%s"'
                            % (xlabels[ig], ylabels[ig], yscales[ig]))
                self.output('#     names: "%s"' % ', '.join(names))

        if self.is_plot and (not self.can_plot):
            output(_msg_no_live)

    def add_group(self, names, yscale=None, xlabel=None, ylabel=None,
                  formats=None):
        """Add a new data group. Notify the plotting process if it is
        already running."""
        ig = self.n_gr
        self.n_gr += 1

        self.x_values[ig] = []

        self.data_names[ig] = names
        self.yscales[ig] = yscale
        self.xlabels[ig] = xlabel
        self.ylabels[ig] = ylabel
        
        ii = self.n_arg
        for iseq, name in enumerate(names):
            key = name_to_key(name, ii)
            self.data[key] = []
            ii += 1

            if formats is not None:
                self.formats[key] = formats[iseq]
            else:
                self.formats[key] = '%.3e'

        self.n_arg = ii

        if self.plot_pipe is not None:
            send = self.plot_pipe.send
            send(['add_axis', ig, names, yscale, xlabel, ylabel])

    def iter_names(self, igs=None):
        if igs is None:
            igs = nm.arange(self.n_gr)

        ii = iseq = 0
        for ig, names in ordered_iteritems(self.data_names):
            for name in names:
                if ig in igs:
                    yield ig, ii, iseq, name
                    iseq += 1
                ii += 1

    def get_log_name(self):
        return os.path.join(sfepy_config_dir,
                            'plotter_%03d.log' % self.__class__.count)       


    def __call__( self, *args, **kwargs ):
        """Log the data passed via *args, and send them to the plotting
        process, if available."""
        finished = False
        save_figure = ''
        x_values = None
        igs = nm.arange(self.n_gr)
        full = True
        if kwargs:
            if 'finished' in kwargs:
                finished = kwargs['finished']
            if 'save_figure' in kwargs:
                save_figure = kwargs['save_figure']
            if 'x' in kwargs:
                x_values = kwargs['x']

            if 'igs' in kwargs:
                igs = nm.array(kwargs['igs'])
                full = False
                
        if save_figure and (self.plot_pipe is not None):
            self.plot_pipe.send( ['save', save_figure] )
            ok = self.plot_pipe.recv()

        if finished:
            self.terminate()
            return

        ls = len( args ), self.n_arg
        if full and (ls[0] != ls[1]):
            if kwargs:
                return
            else:
                msg = 'log called with wrong number of arguments! (%d == %d)' \
                      % ls
                raise IndexError( msg )

        for ig in igs:
            if (x_values is not None) and (x_values[ig] is not None):
                self.x_values[ig].append(x_values[ig])
            else:
                if len(self.x_values[ig]):
                    ii = self.x_values[ig][-1] + 1
                else:
                    ii = 0
                self.x_values[ig].append(ii)

        for ig, ii, iseq, name in self.iter_names(igs):
            aux = args[iseq]
            if isinstance( aux, nm.ndarray ):
                aux = nm.array( aux, ndmin = 1 )
                if len( aux ) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, 'can log only scalars (%s)' % aux
            key = name_to_key( name, ii )
            self.data[key].append( aux )

            if self.output:
                self.output(('%%s: %%s: %s' % self.formats[key])
                            % (name, self.x_values[ig][-1], aux))

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register( self.terminate )

                self.__class__.count += 1

                self.plot_pipe, plotter_pipe = Pipe()
                self.plotter = ProcessPlotter( self.aggregate )
                self.plot_process = Process( target = self.plotter,
                                             args = (plotter_pipe,
                                                     self.get_log_name(),
                                                     self.data_names,
                                                     self.yscales,
                                                     self.xlabels,
                                                     self.ylabels) )
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data(igs)
            
        self.n_calls += 1

    def terminate(self):
        if self.output is not None:
            self.output('# ended: %s' % time.asctime())
            self.output = None

        if self.is_plot and self.can_plot:
            self.plot_pipe.send(None)
            self.plot_process.join()
            self.n_calls = 0
            output('terminated')

    def plot_data(self, igs):
        send = self.plot_pipe.send

        ii = 0
        for ig, names in ordered_iteritems(self.data_names):
            if ig in igs:
                send(['ig', ig])
                send(['clear'])
                for name in names:
                    key = name_to_key(name, ii)
                    try:
                        send(['plot',
                              nm.array(self.x_values[ig]),
                              nm.array(self.data[key])])
                    except:
                        msg = "send failed! (%s, %s, %s)!" \
                              % (ii, name, self.data[key])
                        raise IOError(msg)
                    ii += 1

            else:
                ii += len(names)

        send(['legends'])
        send(['continue'])

    def plot_vlines(self, igs=None, **kwargs):
        """Plot vertical lines in axes given by igs at current x locations
        to mark some events."""
        if igs is None:
            igs = range(self.n_gr)

        if self.plot_pipe is not None:
            send = self.plot_pipe.send

            for ig in igs:
                x = self.x_values[ig]
                if len(x):
                    send(['ig', ig])
                    send(['vline', x[-1], kwargs])

            send(['continue'])

        if self.output:
            for ig in igs:
                for name in self.data_names[ig]:
                    self.output(name + ': -----')
Example #3
0
File: log.py Project: sdurve/sfepy
    def __call__(self, *args, **kwargs):
        """Log the data passed via *args, and send them to the plotting
        process, if available."""
        finished = False
        save_figure = ''
        x_values = None
        igs = nm.arange(self.n_gr)
        full = True
        if kwargs:
            if 'finished' in kwargs:
                finished = kwargs['finished']
            if 'save_figure' in kwargs:
                save_figure = kwargs['save_figure']
            if 'x' in kwargs:
                x_values = kwargs['x']

            if 'igs' in kwargs:
                igs = nm.array(kwargs['igs'])
                full = False

        if save_figure and (self.plot_pipe is not None):
            self.plot_pipe.send(['save', save_figure])
            ok = self.plot_pipe.recv()

        if finished:
            self.terminate()
            return

        ls = len(args), self.n_arg
        if full and (ls[0] != ls[1]):
            if kwargs:
                return
            else:
                msg = 'log called with wrong number of arguments! (%d == %d)' \
                      % ls
                raise IndexError(msg)

        for ig in igs:
            if (x_values is not None) and (x_values[ig] is not None):
                self.x_values[ig].append(x_values[ig])
            else:
                if len(self.x_values[ig]):
                    ii = self.x_values[ig][-1] + 1
                else:
                    ii = 0
                self.x_values[ig].append(ii)

        for ig, ii, iseq, name in self.iter_names(igs):
            aux = args[iseq]
            if isinstance(aux, nm.ndarray):
                aux = nm.array(aux, ndmin=1)
                if len(aux) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, 'can log only scalars (%s)' % aux
            key = name_to_key(name, ii)
            self.data[key].append(aux)

            if self.output:
                self.output(('%%s: %%s: %s' % self.formats[key]) %
                            (name, self.x_values[ig][-1], aux))

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register(self.terminate)

                self.__class__.count += 1

                self.plot_pipe, plotter_pipe = Pipe()
                self.plotter = ProcessPlotter(self.aggregate)
                self.plot_process = Process(
                    target=self.plotter,
                    args=(plotter_pipe, self.get_log_name(), self.data_names,
                          self.yscales, self.xlabels, self.ylabels))
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data(igs)

        self.n_calls += 1
Example #4
0
File: log.py Project: sdurve/sfepy
class Log(Struct):
    """Log data and (optionally) plot them in the second process via
    ProcessPlotter."""
    count = -1

    def from_conf(conf, data_names):
        """
        Parameters
        ----------
        data_names : tuple of str
            The data names grouped by subplots: ([name1, name2, ...], [name3,
            name4, ...], ...), where name<n> are strings to display in
            (sub)plot legends.
        """
        if not isinstance(data_names, tuple):
            data_names = (data_names, )

        obj = Log(data_names, **conf)

        return obj

    from_conf = staticmethod(from_conf)

    def __init__(self,
                 data_names=None,
                 yscales=None,
                 xlabels=None,
                 ylabels=None,
                 is_plot=True,
                 aggregate=200,
                 formats=None,
                 log_filename=None):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        try:
            import matplotlib as mpl
        except:
            mpl = None

        if (mpl is not None) and mpl.rcParams['backend'] == 'GTKAgg':
            can_live_plot = True
        else:
            can_live_plot = False

        Struct.__init__(self,
                        data_names={},
                        n_arg=0,
                        n_gr=0,
                        data={},
                        x_values={},
                        n_calls=0,
                        yscales={},
                        xlabels={},
                        ylabels={},
                        plot_pipe=None,
                        formats={},
                        output=None)

        if data_names is not None:
            n_gr = len(data_names)
        else:
            n_gr = 0
            data_names = []

        yscales = get_default(yscales, ['linear'] * n_gr)
        xlabels = get_default(xlabels, ['iteration'] * n_gr)
        ylabels = get_default(ylabels, [''] * n_gr)

        if formats is None:
            formats = [None] * n_gr

        for ig, names in enumerate(data_names):
            self.add_group(names, yscales[ig], xlabels[ig], ylabels[ig],
                           formats[ig])

        self.is_plot = get_default(is_plot, True)
        self.aggregate = get_default(aggregate, 100)

        self.can_plot = (can_live_plot and (mpl is not None)
                         and (Process is not None))

        if log_filename is not None:
            self.output = Output('', filename=log_filename)
            self.output('# started: %s' % time.asctime())
            self.output('# groups: %d' % n_gr)
            for ig, names in enumerate(data_names):
                self.output('#   %d' % ig)
                self.output('#     xlabel: "%s", ylabel: "%s", yscales: "%s"' %
                            (xlabels[ig], ylabels[ig], yscales[ig]))
                self.output('#     names: "%s"' % ', '.join(names))

        if self.is_plot and (not self.can_plot):
            output(_msg_no_live)

    def add_group(self,
                  names,
                  yscale=None,
                  xlabel=None,
                  ylabel=None,
                  formats=None):
        """Add a new data group. Notify the plotting process if it is
        already running."""
        ig = self.n_gr
        self.n_gr += 1

        self.x_values[ig] = []

        self.data_names[ig] = names
        self.yscales[ig] = yscale
        self.xlabels[ig] = xlabel
        self.ylabels[ig] = ylabel

        ii = self.n_arg
        for iseq, name in enumerate(names):
            key = name_to_key(name, ii)
            self.data[key] = []
            ii += 1

            if formats is not None:
                self.formats[key] = formats[iseq]
            else:
                self.formats[key] = '%.3e'

        self.n_arg = ii

        if self.plot_pipe is not None:
            send = self.plot_pipe.send
            send(['add_axis', ig, names, yscale, xlabel, ylabel])

    def iter_names(self, igs=None):
        if igs is None:
            igs = nm.arange(self.n_gr)

        ii = iseq = 0
        for ig, names in ordered_iteritems(self.data_names):
            for name in names:
                if ig in igs:
                    yield ig, ii, iseq, name
                    iseq += 1
                ii += 1

    def get_log_name(self):
        return os.path.join(sfepy_config_dir,
                            'plotter_%03d.log' % self.__class__.count)

    def __call__(self, *args, **kwargs):
        """Log the data passed via *args, and send them to the plotting
        process, if available."""
        finished = False
        save_figure = ''
        x_values = None
        igs = nm.arange(self.n_gr)
        full = True
        if kwargs:
            if 'finished' in kwargs:
                finished = kwargs['finished']
            if 'save_figure' in kwargs:
                save_figure = kwargs['save_figure']
            if 'x' in kwargs:
                x_values = kwargs['x']

            if 'igs' in kwargs:
                igs = nm.array(kwargs['igs'])
                full = False

        if save_figure and (self.plot_pipe is not None):
            self.plot_pipe.send(['save', save_figure])
            ok = self.plot_pipe.recv()

        if finished:
            self.terminate()
            return

        ls = len(args), self.n_arg
        if full and (ls[0] != ls[1]):
            if kwargs:
                return
            else:
                msg = 'log called with wrong number of arguments! (%d == %d)' \
                      % ls
                raise IndexError(msg)

        for ig in igs:
            if (x_values is not None) and (x_values[ig] is not None):
                self.x_values[ig].append(x_values[ig])
            else:
                if len(self.x_values[ig]):
                    ii = self.x_values[ig][-1] + 1
                else:
                    ii = 0
                self.x_values[ig].append(ii)

        for ig, ii, iseq, name in self.iter_names(igs):
            aux = args[iseq]
            if isinstance(aux, nm.ndarray):
                aux = nm.array(aux, ndmin=1)
                if len(aux) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, 'can log only scalars (%s)' % aux
            key = name_to_key(name, ii)
            self.data[key].append(aux)

            if self.output:
                self.output(('%%s: %%s: %s' % self.formats[key]) %
                            (name, self.x_values[ig][-1], aux))

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register(self.terminate)

                self.__class__.count += 1

                self.plot_pipe, plotter_pipe = Pipe()
                self.plotter = ProcessPlotter(self.aggregate)
                self.plot_process = Process(
                    target=self.plotter,
                    args=(plotter_pipe, self.get_log_name(), self.data_names,
                          self.yscales, self.xlabels, self.ylabels))
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data(igs)

        self.n_calls += 1

    def terminate(self):
        if self.output is not None:
            self.output('# ended: %s' % time.asctime())
            self.output = None

        if self.is_plot and self.can_plot:
            self.plot_pipe.send(None)
            self.plot_process.join()
            self.n_calls = 0
            output('terminated')

    def plot_data(self, igs):
        send = self.plot_pipe.send

        ii = 0
        for ig, names in ordered_iteritems(self.data_names):
            if ig in igs:
                send(['ig', ig])
                send(['clear'])
                for name in names:
                    key = name_to_key(name, ii)
                    try:
                        send([
                            'plot',
                            nm.array(self.x_values[ig]),
                            nm.array(self.data[key])
                        ])
                    except:
                        msg = "send failed! (%s, %s, %s)!" \
                              % (ii, name, self.data[key])
                        raise IOError(msg)
                    ii += 1

            else:
                ii += len(names)

        send(['legends'])
        send(['continue'])

    def plot_vlines(self, igs=None, **kwargs):
        """Plot vertical lines in axes given by igs at current x locations
        to mark some events."""
        if igs is None:
            igs = range(self.n_gr)

        if self.plot_pipe is not None:
            send = self.plot_pipe.send

            for ig in igs:
                x = self.x_values[ig]
                if len(x):
                    send(['ig', ig])
                    send(['vline', x[-1], kwargs])

            send(['continue'])

        if self.output:
            for ig in igs:
                for name in self.data_names[ig]:
                    self.output(name + ': -----')
Example #5
0
File: log.py Project: certik/sfepy
    def __call__(self, *args, **kwargs):
        finished = False
        save_figure = ""
        x_values = None
        if kwargs:
            if "finished" in kwargs:
                finished = kwargs["finished"]
            if "save_figure" in kwargs:
                save_figure = kwargs["save_figure"]
            if "x" in kwargs:
                x_values = kwargs["x"]

        if save_figure and (self.plot_queue is not None):
            self.plot_queue.put(["save", save_figure])

        if finished:
            self.terminate()
            return

        ls = len(args), self.n_arg
        if ls[0] != ls[1]:
            msg = "log called with wrong number of arguments! (%d == %d)" % ls
            raise IndexError(msg)

        for ii, name in enumerate(self.seq_data_names):
            aux = args[ii]
            if isinstance(aux, nm.ndarray):
                aux = nm.array(aux, ndmin=1)
                if len(aux) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, "can log only scalars (%s)" % aux
            key = name_to_key(name, ii)
            self.data[key].append(aux)

        for ig in range(self.n_gr):
            if (x_values is not None) and x_values[ig]:
                self.x_values[ig].append(x_values[ig])
            else:
                self.x_values[ig].append(self.n_calls)

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register(self.terminate)

                self.plot_queue = Queue()
                self.plotter = ProcessPlotter(self.aggregate)
                self.plot_process = Process(
                    target=self.plotter,
                    args=(
                        self.plot_queue,
                        self.data_names,
                        self.igs,
                        self.seq_data_names,
                        self.yscales,
                        self.xaxes,
                        self.yaxes,
                    ),
                )
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data()

        self.n_calls += 1
Example #6
0
File: log.py Project: certik/sfepy
class Log(Struct):
    """Log data and (optionally) plot them in the second process via
    ProcessPlotter."""

    def from_conf(conf, data_names):
        """`data_names` ... tuple of names grouped by subplots:
                            ([name1, name2, ...], [name3, name4, ...], ...)
        where name<n> are strings to display in (sub)plot legends."""
        if not isinstance(data_names, tuple):
            data_names = (data_names,)

        obj = Log(data_names=data_names, seq_data_names=[], igs=[], data={}, x_values={}, n_calls=0, plot_queue=None)

        ii = 0
        for ig, names in enumerate(obj.data_names):
            obj.x_values[ig] = []
            for name in names:
                key = name_to_key(name, ii)
                obj.data[key] = []
                obj.igs.append(ig)
                obj.seq_data_names.append(name)
                ii += 1
        obj.n_arg = len(obj.igs)

        obj.n_gr = len(obj.data_names)

        if isinstance(conf, dict):
            get = conf.get
        else:
            get = conf.get_default_attr

        obj.is_plot = get("is_plot", True)
        obj.yscales = get("yscales", ["linear"] * obj.n_arg)
        obj.xaxes = get("xaxes", ["iteration"] * obj.n_arg)
        obj.yaxes = get("yaxes", [""] * obj.n_arg)
        obj.aggregate = get("aggregate", 100)

        obj.can_plot = (pylab is not None) and (Process is not None)

        if obj.is_plot and (not obj.can_plot):
            output("warning: log plot is disabled, install pylab (GTKAgg)")
            output("         and multiprocessing")

        return obj

    from_conf = staticmethod(from_conf)

    def __call__(self, *args, **kwargs):
        finished = False
        save_figure = ""
        x_values = None
        if kwargs:
            if "finished" in kwargs:
                finished = kwargs["finished"]
            if "save_figure" in kwargs:
                save_figure = kwargs["save_figure"]
            if "x" in kwargs:
                x_values = kwargs["x"]

        if save_figure and (self.plot_queue is not None):
            self.plot_queue.put(["save", save_figure])

        if finished:
            self.terminate()
            return

        ls = len(args), self.n_arg
        if ls[0] != ls[1]:
            msg = "log called with wrong number of arguments! (%d == %d)" % ls
            raise IndexError(msg)

        for ii, name in enumerate(self.seq_data_names):
            aux = args[ii]
            if isinstance(aux, nm.ndarray):
                aux = nm.array(aux, ndmin=1)
                if len(aux) == 1:
                    aux = aux[0]
                else:
                    raise ValueError, "can log only scalars (%s)" % aux
            key = name_to_key(name, ii)
            self.data[key].append(aux)

        for ig in range(self.n_gr):
            if (x_values is not None) and x_values[ig]:
                self.x_values[ig].append(x_values[ig])
            else:
                self.x_values[ig].append(self.n_calls)

        if self.is_plot and self.can_plot:
            if self.n_calls == 0:
                atexit.register(self.terminate)

                self.plot_queue = Queue()
                self.plotter = ProcessPlotter(self.aggregate)
                self.plot_process = Process(
                    target=self.plotter,
                    args=(
                        self.plot_queue,
                        self.data_names,
                        self.igs,
                        self.seq_data_names,
                        self.yscales,
                        self.xaxes,
                        self.yaxes,
                    ),
                )
                self.plot_process.daemon = True
                self.plot_process.start()

            self.plot_data()

        self.n_calls += 1

    def terminate(self):
        if self.is_plot and self.can_plot:
            self.plot_queue.put(None)
            self.plot_process.join()
            self.n_calls = 0
            output("terminated")

    def plot_data(self):
        put = self.plot_queue.put

        put(["clear"])
        for ii, name in enumerate(self.seq_data_names):
            key = name_to_key(name, ii)
            try:
                put(["iseq", ii])
                put(["plot", nm.array(self.x_values[self.igs[ii]]), nm.array(self.data[key])])
            except:
                print ii, name, self.data[key]
                raise
        put(["legends"])
        put(["continue"])