Search code examples
enthoughtchaco

How to have 100% zoom factor withChaco


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.


Solution

  • 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()