Chaco zoom_plot example

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Chaco zoom_plot example

Neil Hodgson

Hi

I am playing around with the zoom_plot demo. 

I wanted to add multiple datasets to the plots, which I thought would be straight forward.
After adding an extra dataset z to the ArrayPlotData instance, I thought a second call to plotter.plot should be ok (see below).

def _plot_default(self):
plotter = Plot(data=self.data)
main_plot = plotter.plot(['x','y'])[0]
self.configure_plot(main_plot, xlabel='')

    # this line added to also plot z data
    plotter.plot(['x','z'])

I see that a line_plot is correctly added to plotter.plots, but the data is not shown on the plot. 

Anyone looked at this before?  Any tips?

Thanks,
Neil


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Robert Kern
On Sun, Feb 24, 2013 at 8:24 PM, Neil Hodgson <[hidden email]> wrote:

>
> Hi
>
> I am playing around with the zoom_plot demo.
>
> I wanted to add multiple datasets to the plots, which I thought would be
> straight forward.
> After adding an extra dataset z to the ArrayPlotData instance, I thought a
> second call to plotter.plot should be ok (see below).
>
> def _plot_default(self):
> plotter = Plot(data=self.data)
> main_plot = plotter.plot(['x','y'])[0]
> self.configure_plot(main_plot, xlabel='')
>
>     # this line added to also plot z data
>     plotter.plot(['x','z'])
>
> I see that a line_plot is correctly added to plotter.plots, but the data is
> not shown on the plot.
>
> Anyone looked at this before?  Any tips?

Can you post the complete code that fails to work? Thanks.

--
Robert Kern
Enthought
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Neil Hodgson
From: Robert Kern <[hidden email]>
To: Neil Hodgson <[hidden email]>; [hidden email]
Sent: Sunday, 24 February 2013, 21:30
Subject: Re: [Enthought-Dev] Chaco zoom_plot example

On Sun, Feb 24, 2013 at 8:24 PM, Neil Hodgson <[hidden email]> wrote:

>
> Hi
>
> I am playing around with the zoom_plot demo.
>
> I wanted to add multiple datasets to the plots, which I thought would be
> straight forward.
> After adding an extra dataset z to the ArrayPlotData instance, I thought a
> second call to plotter.plot should be ok (see below).
>
> def _plot_default(self):
> plotter = Plot(data=self.data)
> main_plot = plotter.plot(['x','y'])[0]
> self.configure_plot(main_plot, xlabel='')
>
>    # this line added to also plot z data
>    plotter.plot(['x','z'])
>
> I see that a line_plot is correctly added to plotter.plots, but the data is
> not shown on the plot.
>
> Anyone looked at this before?  Any tips?

Can you post the complete code that fails to work? Thanks.

--
Robert Kern
Enthought


Robert,

The code is 99% zoom_plot.py from the Chaco demos directory.

I created an extra data source in _data_default method and then as explained in the OP added one line in the _plot_default method to try and add the extra data to the plot.

Thanks,
Neil

"""
The main executable file for the zoom_plot demo.

Right-click and drag on the upper plot to select a region to view in detail
in the lower plot. The selected region can be moved around by dragging,
or resized by clicking on one of its edges and dragging. The ZoomPlot class
encapsulates the creation of a zoom plot and exposes some of the attributes and
methods necessary for deep interaction with the plot.
"""
# Standard library imports
import os
os.environ['ETS_TOOLKIT'] = 'qt4'

# Major library imports
from numpy import sin, pi, linspace

# Enthought imports
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance
from traitsui.api import Item, Group, View
from traits.util.resource import find_resource

# Chaco imports
from chaco.api import VPlotContainer, ArrayPlotData, Plot, PlotGrid, PlotAxis
from chaco.tools.api import RangeSelection

# Relative imports
from zoom_overlay import ZoomOverlay

sample_path = os.path.join('examples','data','sample.wav')
alt_path = os.path.join('..','data','sample.wav')
fname = find_resource('Chaco', sample_path, alt_path=alt_path,
return_path=True)
numpts = 3000

def read_music_data():
from wav_to_numeric import wav_to_numeric
index, data = wav_to_numeric(fname)
return index[:numpts], data[:numpts]


class ZoomPlot(HasTraits):
'''Encapsulation of the zoom plot concept.

This class organzies the data, plot container and ZoomOverlay required for
a zoom plot. ZoomPlot represents the first step towards a reusable and
extensible generalization of the zoom plot.

'''

data = Instance(ArrayPlotData)

plot = Instance(Component)
def update_data(self, x, y):
'''Update the data in the plot windows'''
# FIXME: This isn't forcing the update, so the crufty code below is used.
#self.plot.data['x'] = x
#self.plot.data['y'] = y
self.plot.components[0].index.set_data(x)
self.plot.components[0].value.set_data(y)
self.plot.components[1].index.set_data(x)
self.plot.components[1].value.set_data(y)

def _data_default(self):
x = linspace(0, 4*pi, 1201)
y = sin(x**2)
z = -1. * y
data = ArrayPlotData(x=x, y=y, z=z)
return data

def _plot_default(self):
plotter = Plot(data=self.data)
main_plot = plotter.plot(['x','y'])[0]
main_plot2 = plotter.plot(['x','z'])[0]
self.configure_plot(main_plot, xlabel='')
plotter2 = Plot(data=self.data)
zoom_plot = plotter2.plot(['x','y'])[0]
self.configure_plot(zoom_plot)
outer_container = VPlotContainer(padding=20,
fill_padding=True,
spacing=0,
stack_order='top_to_bottom',
bgcolor='lightgray',
use_backbuffer=True)

outer_container.add(main_plot)
outer_container.add(zoom_plot)

# FIXME: This is set to the windows bg color. Should get from the system.
#outer_container.bgcolor = (236/255., 233/255., 216/255., 1.0)

main_plot.controller = RangeSelection(main_plot)
zoom_overlay = ZoomOverlay(source=main_plot, destination=zoom_plot)
outer_container.overlays.append(zoom_overlay)

return outer_container

@staticmethod
def configure_plot(plot, xlabel='Time (s)'):
""" Set up colors, grids, etc. on plot objects.
"""
plot.bgcolor = 'white'
plot.border_visible = True
plot.padding = [40, 15, 15, 20]
plot.color = 'darkred'
plot.line_width = 1.1
vertical_grid = PlotGrid(component=plot,
mapper=plot.index_mapper,
orientation='vertical',
line_color="gray",
line_style='dot',
use_draw_order = True)

horizontal_grid = PlotGrid(component=plot,
mapper=plot.value_mapper,
orientation='horizontal',
line_color="gray",
line_style='dot',
use_draw_order = True)

vertical_axis = PlotAxis(orientation='left',
mapper=plot.value_mapper,
use_draw_order = True)
horizontal_axis = PlotAxis(orientation='bottom',
title=xlabel,
mapper=plot.index_mapper,
use_draw_order = True)

plot.underlays.append(vertical_grid)
plot.underlays.append(horizontal_grid)

# Have to add axes to overlays because we are backbuffering the main plot,
# and only overlays get to render in addition to the backbuffer.
plot.overlays.append(vertical_axis)
plot.overlays.append(horizontal_axis)
#===============================================================================
# Attributes to use for the plot view.
size = (800, 600)
title = fname

#===============================================================================
# # Demo class that is used by the demo.py application.
#===============================================================================
class ZoomPlotView(HasTraits):

zoom_plot = Instance(ZoomPlot, ())
traits_view = View(
Group(
Item('object.zoom_plot.plot', editor=ComponentEditor(size=size),
show_label=False),
orientation = "vertical"),
resizable=True, title='Zoom Plot',
width=size[0], height=size[1]
)

demo = ZoomPlotView()
# Configure the zoom plot by giving it data
try:
x,y = read_music_data()
demo.zoom_plot.update_data(x, y)
except:
# Use the defaults
pass

if __name__ == "__main__":
demo.configure_traits()

#--EOF---





_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Robert Kern
Your code had its indentation stripped out. Can you resend it as an
attachment? Or post it in pastebin or a Github gist?

https://gist.github.com/

Thanks!

On Sun, Feb 24, 2013 at 8:51 PM, Neil Hodgson <[hidden email]> wrote:

> From: Robert Kern <[hidden email]>
> To: Neil Hodgson <[hidden email]>; [hidden email]
> Sent: Sunday, 24 February 2013, 21:30
> Subject: Re: [Enthought-Dev] Chaco zoom_plot example
>
> On Sun, Feb 24, 2013 at 8:24 PM, Neil Hodgson <[hidden email]>
> wrote:
>>
>> Hi
>>
>> I am playing around with the zoom_plot demo.
>>
>> I wanted to add multiple datasets to the plots, which I thought would be
>> straight forward.
>> After adding an extra dataset z to the ArrayPlotData instance, I thought a
>> second call to plotter.plot should be ok (see below).
>>
>> def _plot_default(self):
>> plotter = Plot(data=self.data)
>> main_plot = plotter.plot(['x','y'])[0]
>> self.configure_plot(main_plot, xlabel='')
>>
>>    # this line added to also plot z data
>>    plotter.plot(['x','z'])
>>
>> I see that a line_plot is correctly added to plotter.plots, but the data
>> is
>> not shown on the plot.
>>
>> Anyone looked at this before?  Any tips?
>
> Can you post the complete code that fails to work? Thanks.
>
> --
> Robert Kern
> Enthought
>
>
> Robert,
>
> The code is 99% zoom_plot.py from the Chaco demos directory.
>
> I created an extra data source in _data_default method and then as explained
> in the OP added one line in the _plot_default method to try and add the
> extra data to the plot.
>
> Thanks,
> Neil
>
> """
> The main executable file for the zoom_plot demo.
>
> Right-click and drag on the upper plot to select a region to view in detail
> in the lower plot. The selected region can be moved around by dragging,
> or resized by clicking on one of its edges and dragging. The ZoomPlot class
> encapsulates the creation of a zoom plot and exposes some of the attributes
> and
> methods necessary for deep interaction with the plot.
> """
> # Standard library imports
> import os
> os.environ['ETS_TOOLKIT'] = 'qt4'
>
> # Major library imports
> from numpy import sin, pi, linspace
>
> # Enthought imports
> from enable.api import Component, ComponentEditor
> from traits.api import HasTraits, Instance
> from traitsui.api import Item, Group, View
> from traits.util.resource import find_resource
>
> # Chaco imports
> from chaco.api import VPlotContainer, ArrayPlotData, Plot, PlotGrid,
> PlotAxis
> from chaco.tools.api import RangeSelection
>
> # Relative imports
> from zoom_overlay import ZoomOverlay
>
> sample_path = os.path.join('examples','data','sample.wav')
> alt_path = os.path.join('..','data','sample.wav')
> fname = find_resource('Chaco', sample_path, alt_path=alt_path,
> return_path=True)
> numpts = 3000
>
> def read_music_data():
> from wav_to_numeric import wav_to_numeric
> index, data = wav_to_numeric(fname)
> return index[:numpts], data[:numpts]
>
>
> class ZoomPlot(HasTraits):
> '''Encapsulation of the zoom plot concept.
>
> This class organzies the data, plot container and ZoomOverlay required for
> a zoom plot. ZoomPlot represents the first step towards a reusable and
> extensible generalization of the zoom plot.
>
> '''
>
> data = Instance(ArrayPlotData)
>
> plot = Instance(Component)
> def update_data(self, x, y):
> '''Update the data in the plot windows'''
> # FIXME: This isn't forcing the update, so the crufty code below is used.
> #self.plot.data['x'] = x
> #self.plot.data['y'] = y
> self.plot.components[0].index.set_data(x)
> self.plot.components[0].value.set_data(y)
> self.plot.components[1].index.set_data(x)
> self.plot.components[1].value.set_data(y)
>
> def _data_default(self):
> x = linspace(0, 4*pi, 1201)
> y = sin(x**2)
> z = -1. * y
> data = ArrayPlotData(x=x, y=y, z=z)
> return data
>
> def _plot_default(self):
> plotter = Plot(data=self.data)
> main_plot = plotter.plot(['x','y'])[0]
> main_plot2 = plotter.plot(['x','z'])[0]
> self.configure_plot(main_plot, xlabel='')
> plotter2 = Plot(data=self.data)
> zoom_plot = plotter2.plot(['x','y'])[0]
> self.configure_plot(zoom_plot)
> outer_container = VPlotContainer(padding=20,
> fill_padding=True,
> spacing=0,
> stack_order='top_to_bottom',
> bgcolor='lightgray',
> use_backbuffer=True)
>
> outer_container.add(main_plot)
> outer_container.add(zoom_plot)
>
> # FIXME: This is set to the windows bg color. Should get from the system.
> #outer_container.bgcolor = (236/255., 233/255., 216/255., 1.0)
>
> main_plot.controller = RangeSelection(main_plot)
> zoom_overlay = ZoomOverlay(source=main_plot, destination=zoom_plot)
> outer_container.overlays.append(zoom_overlay)
>
> return outer_container
>
> @staticmethod
> def configure_plot(plot, xlabel='Time (s)'):
> """ Set up colors, grids, etc. on plot objects.
> """
> plot.bgcolor = 'white'
> plot.border_visible = True
> plot.padding = [40, 15, 15, 20]
> plot.color = 'darkred'
> plot.line_width = 1.1
> vertical_grid = PlotGrid(component=plot,
> mapper=plot.index_mapper,
> orientation='vertical',
> line_color="gray",
> line_style='dot',
> use_draw_order = True)
>
> horizontal_grid = PlotGrid(component=plot,
> mapper=plot.value_mapper,
> orientation='horizontal',
> line_color="gray",
> line_style='dot',
> use_draw_order = True)
>
> vertical_axis = PlotAxis(orientation='left',
> mapper=plot.value_mapper,
> use_draw_order = True)
> horizontal_axis = PlotAxis(orientation='bottom',
> title=xlabel,
> mapper=plot.index_mapper,
> use_draw_order = True)
>
> plot.underlays.append(vertical_grid)
> plot.underlays.append(horizontal_grid)
>
> # Have to add axes to overlays because we are backbuffering the main plot,
> # and only overlays get to render in addition to the backbuffer.
> plot.overlays.append(vertical_axis)
> plot.overlays.append(horizontal_axis)
> #===============================================================================
> # Attributes to use for the plot view.
> size = (800, 600)
> title = fname
>
> #===============================================================================
> # # Demo class that is used by the demo.py application.
> #===============================================================================
> class ZoomPlotView(HasTraits):
>
> zoom_plot = Instance(ZoomPlot, ())
> traits_view = View(
> Group(
> Item('object.zoom_plot.plot', editor=ComponentEditor(size=size),
> show_label=False),
> orientation = "vertical"),
> resizable=True, title='Zoom Plot',
> width=size[0], height=size[1]
> )
>
> demo = ZoomPlotView()
> # Configure the zoom plot by giving it data
> try:
> x,y = read_music_data()
> demo.zoom_plot.update_data(x, y)
> except:
> # Use the defaults
> pass
>
> if __name__ == "__main__":
> demo.configure_traits()
>
> #--EOF---
>
>
> ________________________________
>



--
Robert Kern
Enthought
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Neil Hodgson
ok third time lucky :).

https://gist.github.com/anonymous/5047740

The question basically is - how do I add multple datasets to the zoom_plot example?  Has anyone done this before?

As I understood the common way of having multiple plots is described here:

http://docs.enthought.com/chaco/user_manual/chaco_tutorial.html#multiple-plots
 

The zoom_plot example seems more complex than that, in ways I don't quite get.  What I've tried and some comments are in the gist.

Thanks, Neil
 

From: Robert Kern <[hidden email]>
To: Neil Hodgson <[hidden email]>
Cc: "[hidden email]" <[hidden email]>
Sent: Wednesday, 27 February 2013, 11:46
Subject: Re: [Enthought-Dev] Chaco zoom_plot example

Your code had its indentation stripped out. Can you resend it as an
attachment? Or post it in pastebin or a Github gist?

https://gist.github.com/

Thanks!

On Sun, Feb 24, 2013 at 8:51 PM, Neil Hodgson <[hidden email]> wrote:

> From: Robert Kern <[hidden email]>
> To: Neil Hodgson <[hidden email]>; [hidden email]
> Sent: Sunday, 24 February 2013, 21:30
> Subject: Re: [Enthought-Dev] Chaco zoom_plot example
>
> On Sun, Feb 24, 2013 at 8:24 PM, Neil Hodgson <[hidden email]>
> wrote:
>>
>> Hi
>>
>> I am playing around with the zoom_plot demo.
>>
>> I wanted to add multiple datasets to the plots, which I thought would be
>> straight forward.
>> After adding an extra dataset z to the ArrayPlotData instance, I thought a
>> second call to plotter.plot should be ok (see below).
>>
>> def _plot_default(self):
>> plotter = Plot(data=self.data)
>> main_plot = plotter.plot(['x','y'])[0]
>> self.configure_plot(main_plot, xlabel='')
>>
>>    # this line added to also plot z data
>>    plotter.plot(['x','z'])
>>
>> I see that a line_plot is correctly added to plotter.plots, but the data
>> is
>> not shown on the plot.
>>
>> Anyone looked at this before?  Any tips?
>
> Can you post the complete code that fails to work? Thanks.
>
> --
> Robert Kern
> Enthought
>
>
> Robert,
>
> The code is 99% zoom_plot.py from the Chaco demos directory.
>
> I created an extra data source in _data_default method and then as explained
> in the OP added one line in the _plot_default method to try and add the
> extra data to the plot.
>


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Robert Kern
On Wed, Feb 27, 2013 at 1:10 PM, Neil Hodgson <[hidden email]> wrote:
> ok third time lucky :).
>
> https://gist.github.com/anonymous/5047740

Okay, yes. Note that the Plots themselves are not actually put into
the VPlotContainer. Just the individual LinePlots themselves. That's
why you don't see your added plot. The Plot class was really just
being used as a convenient way to instantiate the LinePlots with a
minimum of fuss. The ZoomOverlay does not appear to work on Plots,
unfortunately. Sorry. It needs a BaseXYPlot (like a LinePlot) as its
source, and it expects to be in the same container as its destination.
Plot is essentially an OverlayPlotContainer. ZoomOverlay would need to
be rewritten to handle that case.

--
Robert Kern
Enthought
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Neil Hodgson
Understood. I should have followed main_plot one level deeper.

I'll see what I can do with ZoomPlotOverlay with my limited time/knowledge of Chaco.  If you or anyone else has tips on how this should be done that would be great.

I took a quick look - one work around I thought of was to hand Plot instances to the VPlotContainer but hand the individial BaseXYPlot instances (main_plot and zoom_plot) to ZoomPlotOverlay.  My hackish thinking was that these main_plot and zoom_plot could be empty plots with there axes kept in sync with the the two Plot instances.

This actually works for the zoom control, but screws up the appearance of the zoom_overlay polygon.

Will look into it somemore when I get a chance, thanks
Neil


From: Robert Kern <[hidden email]>
To: Neil Hodgson <[hidden email]>
Cc: "[hidden email]" <[hidden email]>
Sent: Wednesday, 27 February 2013, 14:51
Subject: Re: [Enthought-Dev] Chaco zoom_plot example

On Wed, Feb 27, 2013 at 1:10 PM, Neil Hodgson <[hidden email]> wrote:
> ok third time lucky :).
>
> https://gist.github.com/anonymous/5047740

Okay, yes. Note that the Plots themselves are not actually put into
the VPlotContainer. Just the individual LinePlots themselves. That's
why you don't see your added plot. The Plot class was really just
being used as a convenient way to instantiate the LinePlots with a
minimum of fuss. The ZoomOverlay does not appear to work on Plots,
unfortunately. Sorry. It needs a BaseXYPlot (like a LinePlot) as its
source, and it expects to be in the same container as its destination.
Plot is essentially an OverlayPlotContainer. ZoomOverlay would need to
be rewritten to handle that case.

--
Robert Kern
Enthought



_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: Chaco zoom_plot example

Robert Kern
On Wed, Feb 27, 2013 at 4:34 PM, Neil Hodgson <[hidden email]> wrote:

> Understood. I should have followed main_plot one level deeper.
>
> I'll see what I can do with ZoomPlotOverlay with my limited time/knowledge
> of Chaco.  If you or anyone else has tips on how this should be done that
> would be great.
>
> I took a quick look - one work around I thought of was to hand Plot
> instances to the VPlotContainer but hand the individial BaseXYPlot instances
> (main_plot and zoom_plot) to ZoomPlotOverlay.  My hackish thinking was that
> these main_plot and zoom_plot could be empty plots with there axes kept in
> sync with the the two Plot instances.
>
> This actually works for the zoom control, but screws up the appearance of
> the zoom_overlay polygon.
Right. ZoomOverlay is looking at the source BaseXYPlot's mapper to
determine where to draw the trapezoid and selection region. The mapper
returns screen coordinates relative to its proximate container. That's
why it relies on both plots being immediate children of the same
Container.

With a little bit of work, you can convert between the two coordinate
spaces. It's still not ideal. I haven't been able to use regular Plots
with it yet, but an OverlayPlotContainer will do the job.

--
Robert Kern
Enthought

_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev

gistfile1.py (10K) Download Attachment
zoom_overlay.py (7K) Download Attachment