As an example, in chaco/examples/demo/basic/image_inspector.py, how to set the zoom factor such that 1 array point corresponds to 1 screen pixel (100% zoom). It seems that the ZoomTool methods (zoom_in, zoom_out, ...) only deal with zoom factor changes, not with absolute factor setting.
2 Answers
I would try something with plot.range2d.low
, plot.range2d.high
and plot.outer_bounds
. The first two relate to data space, while the latter relates to the size of the picture area. By setting the limits of the data space using the picture area, you can map 1 pixel to 1 data unit. Here's an example, the interesting bit is in the _zoom_100_percent
method:
import numpy as np
from chaco.api import Plot, ArrayPlotData
from chaco.tools.api import PanTool, ZoomTool
from enable.api import ComponentEditor
from traits.api import Button, HasTraits, Instance, on_trait_change
from traitsui.api import Item, View
class HundredPercentZoom(HasTraits):
plot = Instance(Plot)
zoom_button = Button('100% Zoom')
traits_view = View(
Item('plot', editor=ComponentEditor(), show_label=False),
'zoom_button',
width=800,
height=600,
)
def _plot_default(self):
t = np.linspace(0, 1000, 200)
y = 400 * (np.sin(t) + 0.1 * np.sin(t * 100))
plot = Plot(ArrayPlotData(t=t, y=y))
plot.plot(('t', 'y'))
plot.tools.append(PanTool(plot))
plot.tools.append(ZoomTool(plot))
return plot
@on_trait_change('zoom_button')
def _zoom_100_percent(self):
low = self.plot.range2d.low
bounds = self.plot.outer_bounds
print(bounds)
self.plot.range2d.high = (low[0] + bounds[0], low[1] + bounds[1])
if __name__ == "__main__":
hpz = HundredPercentZoom()
hpz.configure_traits()
I added a print
statement in there so you can see that the plot area is different than the window area, which is 800x600. I also added a PanTool and ZoomTool, so you can pan around once zoomed in. You can go back to the orignal zoom state using the Escape key, as long as your plot has a ZoomTool.

- 802
- 6
- 7
The solution I have arrived to, starting from the original example image_inspector.py . A button allows to have a 100 % zoom factor around a point chosen as the zoom center.
All is in the _btn_fired method in class Demo.
There may still be a problem of 1 not being subtracted or added to some bounds or limits, as the button operation is not strictly involutive (a second press should not do anything) as it should.
Anything simpler?
#!/usr/bin/env python
"""
Demonstrates the ImageInspectorTool and overlay on a colormapped image
plot. The underlying plot is similar to the one in cmap_image_plot.py.
- Left-drag pans the plot.
- Mousewheel up and down zooms the plot in and out.
- Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular
region to zoom. If you use a sequence of zoom boxes, pressing alt-left-arrow
and alt-right-arrow moves you forwards and backwards through the "zoom
history".
- Pressing "p" will toggle the display of the image inspector overlay.
"""
# Major library imports
from numpy import linspace, meshgrid, pi, sin, divide, multiply
# Enthought library imports
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance, Button, Float
from traitsui.api import Item, Group, View, HGroup
# Chaco imports
from chaco.api import ArrayPlotData, jet, Plot
from chaco.tools.api import PanTool, ZoomTool
from chaco.tools.image_inspector_tool import ImageInspectorTool, \
ImageInspectorOverlay
#===============================================================================
# # Create the Chaco plot.
#===============================================================================
def _create_plot_component():# Create a scalar field to colormap
xbounds = (-2*pi, 2*pi, 600)
ybounds = (-1.5*pi, 1.5*pi, 300)
xs = linspace(*xbounds)
ys = linspace(*ybounds)
x, y = meshgrid(xs,ys)
z = sin(x)*y
# Create a plot data obect and give it this data
pd = ArrayPlotData()
pd.set_data("imagedata", z)
# Create the plot
plot = Plot(pd)
img_plot = plot.img_plot("imagedata",
xbounds = xbounds[:2],
ybounds = ybounds[:2],
colormap=jet)[0]
# Tweak some of the plot properties
plot.title = "My First Image Plot"
plot.padding = 50
# Attach some tools to the plot
plot.tools.append(PanTool(plot))
zoom = ZoomTool(component=plot, tool_mode="box", always_on=False)
plot.overlays.append(zoom)
imgtool = ImageInspectorTool(img_plot)
img_plot.tools.append(imgtool)
overlay = ImageInspectorOverlay(component=img_plot, image_inspector=imgtool,
bgcolor="white", border_visible=True)
img_plot.overlays.append(overlay)
return plot
#===============================================================================
# Attributes to use for the plot view.
size = (800, 600)
title="Inspecting a Colormapped Image Plot"
#===============================================================================
# # Demo class that is used by the demo.py application.
#===============================================================================
class Demo(HasTraits):
plot = Instance(Component)
center_x = Float
center_y = Float
btn = Button('100 %')
def _btn_fired(self):
img_plot, = self.plot.plots['plot0']
zoom_center = (self.center_x, self.center_y)
# Size of plot in screen pixels
plot_size = img_plot.bounds
# Zoom center in screen space
zoom_center_screen, = img_plot.map_screen(zoom_center)
# Get actual bounds in data space
low, high = (img_plot.index_mapper.range.low,
img_plot.index_mapper.range.high)
# Get data space x and y units in terms of x and y array indices
sizes = [item.get_size() for item in img_plot.index.get_data()]
(min_x, min_y), (max_x, max_y) = img_plot.index.get_bounds()
unit = divide((max_x - min_x, max_y - min_y), sizes)
# Calculate new bounds
new_low = zoom_center - multiply(zoom_center_screen, unit)
new_high = new_low + multiply(plot_size, unit)
# Set new bounds
img_plot.index_mapper.range.set_bounds(new_low,new_high)
traits_view = View(
Group(
Item('plot', editor=ComponentEditor(size=size),
show_label=False),
HGroup('center_x', 'center_y', 'btn'),
orientation = "vertical"
),
resizable=True, title=title
)
def _plot_default(self):
return _create_plot_component()
demo = Demo()
if __name__ == "__main__":
demo.configure_traits()

- 193
- 1
- 10