Dynamically create plots in Chaco
Asked Answered
S

1

15

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.

Schechter answered 22/2, 2012 at 19:39 Comment(6)
Do you mean that you even don't want to see the plotting frame before you need the plot and to remove the plotting frame when it's time to be destroyed?Bitterweed
It's not so much that I don't want to see the frame, it's that the data controls the number of plots and this number can change over time, so I can't create the frames ahead of time. Any thoughts on how one might go about doing this?Schechter
i'm sorry, don't have time for a nice answer right now. But the tutorials on this page really don't help you? github.enthought.com/chaco/user_manual/tutorial.htmlBitterweed
@K.-Michael Aye : The link you provided is dead. Is this the right one : github.com/enthought/chaco/tree/master/examples/tutorials?Af
@K.-MichaelAye Today it is, 404.Ensue
docs.enthought.com/chaco/user_manual/…Bitterweed
Z
8

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.

Zohara answered 16/6, 2012 at 21:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.