Question

The Chaco plotting toolkit for Python includes examples that show how to dynamically update existing plots. However, my application requires that I dynamically create and destroy plots depending on the data. I am new to programming with Chaco and Traits, so a simple example that illustrates how to do this would be really helpful.

Was it helpful?

Solution

This is a bit late, but here's an example that creates and destroys Chaco plots. The main interface is PlotSelector, which defines some fake data and radio buttons to switch between two different plot styles (line and bar plots).

This example uses a Traits event to signal when to close a plot, and then handles that signal with PlotController. There may be a better way to close the window, but I couldn't find one.

Edit: Updated imports for newer versions of Traits, Chaco, and Enable (ETS 4 instead of 3).

import numpy as np

import traits.api as traits
import traitsui.api as ui
import chaco.api as chaco
from enable.api import ComponentEditor


class PlotController(ui.Controller):
    view = ui.View(ui.Item('plot', editor=ComponentEditor(), show_label=False),
                   height=300, width=300, resizable=True)

    def object_close_signal_changed(self, info):
        info.ui.dispose()


class BasicPlot(traits.HasTraits):
    close_signal = traits.Event()
    plot = traits.Instance(chaco.Plot)


class LinePlot(BasicPlot):

    def __init__(self, plotdata):
        self.plot = chaco.Plot(plotdata)
        self.plot.plot(('x', 'y'))


class BarPlot(BasicPlot):

    def __init__(self, plotdata):
        self.plot = chaco.Plot(plotdata)
        self.plot.candle_plot(('x', 'ymin', 'ymax'))


available_plot_types = dict(line=LinePlot, bar=BarPlot)

class PlotSelector(traits.HasTraits):

    plot_type = traits.Enum(['line', 'bar'])
    traits_view = ui.View('plot_type', style='custom')

    def __init__(self, x, y):
        ymin = y - 1
        ymax = y + 1
        self.plotdata = chaco.ArrayPlotData(x=x, y=y, ymin=ymin, ymax=ymax)
        self.figure = None

    def _plot_type_changed(self):
        plot_class = available_plot_types[self.plot_type]
        if self.figure is not None:
            self.figure.close_signal = True
        self.figure = plot_class(self.plotdata)
        controller = PlotController(model=self.figure)
        controller.edit_traits()


N = 20
x = np.arange(N)
y = x + np.random.normal(size=N)
plot_selector = PlotSelector(x, y)
plot_selector.configure_traits()

Note that the main interface (PlotSelector) calls configure_traits (starts application), while the plots are viewed with edit_traits (called from within application). Also, note that this example calls edit_traits from PlotController instead of calling it from the model. You could instead move the view from PlotController to BasicPlot and set the handler method of that view to PlotController.

Finally, if you don't need to totally destroy the plot window, then you may want to look at the Plot object's delplot method, which destroys the *sub*plot (here the line plot or bar plot).

I hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top