chaco-4.1.0/0000755000175100001440000000000011674464663013573 5ustar ischnellusers00000000000000chaco-4.1.0/LICENSE.txt0000644000175100001440000000312011674464170015403 0ustar ischnellusers00000000000000This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. Copyright (c) 2006, Enthought, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Enthought, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. chaco-4.1.0/README.rst0000644000175100001440000000352111674464170015254 0ustar ischnellusers00000000000000========================================= chaco: interactive 2-dimensional plotting ========================================= http://github.enthought.com/chaco Chaco is a Python plotting application toolkit that facilitates writing plotting applications at all levels of complexity, from simple scripts with hard-coded data to large plotting programs with complex data interrelationships and a multitude of interactive tools. While Chaco generates attractive static plots for publication and presentation, it also works well for interactive data visualization and exploration. Features -------- - **Flexible drawing and layout**: Plots consist of graphical components which can be placed inside nestable containers for layout, positioning, and event dispatch. Every component has a configurable rendering loop with distinct layers and backbuffering. Containers can draw cooperatively so that layers span across the containment hierarchy. - **Modular and extensible architecture**: Chaco is object-oriented from the ground up for ease of extension and customization. There are clear interfaces and abstract classes defining extension points for writing your own custom behaviors, from custom tools, plot types, layouts, etc. Most classes are also "subclass-friendly", so that subclasses can override one or two methods and everything else just works. - **Data model for ease of extension and embedding**: Chaco separates the data from any transformations of the data that are needed for displaying it. This separation makes it easier to extend Chaco, or embed it in applications. Prerequisites ------------- You must have the following libraries installed before building or installing Chaco: * `Numpy `_ * `distribute `_ * `enable `_ chaco-4.1.0/setup.py0000644000175100001440000000425511674464170015304 0ustar ischnellusers00000000000000# Copyright (c) 2008-2011 by Enthought, Inc. # All rights reserved. from os.path import join from numpy import get_include from setuptools import setup, Extension, find_packages info = {} execfile(join('chaco', '__init__.py'), info) # Register Python extensions contour = Extension( 'chaco.contour.contour', sources=['chaco/contour/cntr.c'], include_dirs=[get_include()], define_macros=[('NUMPY', None)] ) # Commenting this out for now, until we get the module fully tested and working #speedups = Extension( # 'chaco._speedups', # sources = ['chaco/_speedups.cpp'], # include_dirs = [get_include()], # define_macros=[('NUMPY', None)] # ) setup( name = 'chaco', version = info['__version__'], author = 'Peter Wang, et. al.', author_email = 'pwang@enthought.com', maintainer = 'ETS Developers', maintainer_email = 'enthought-dev@enthought.com', url = 'http://code.enthought.com/projects/chaco', classifiers = [c.strip() for c in """\ Development Status :: 5 - Production/Stable Intended Audience :: Developers Intended Audience :: Science/Research License :: OSI Approved :: BSD License Operating System :: MacOS Operating System :: Microsoft :: Windows Operating System :: OS Independent Operating System :: POSIX Operating System :: Unix Programming Language :: C Programming Language :: Python Topic :: Scientific/Engineering Topic :: Software Development Topic :: Software Development :: Libraries """.splitlines() if len(c.strip()) > 0], package_data={'chaco': ['tools/toolbars/images/*.png', 'layers/data/*.svg']}, description = 'interactive 2-dimensional plotting', long_description = open('README.rst').read(), download_url = ('http://www.enthought.com/repo/ets/chaco-%s.tar.gz' % info['__version__']), ext_modules = [contour], include_package_data = True, install_requires = info['__requires__'], license = 'BSD', packages = find_packages(), platforms = ["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"], zip_safe = False, ) chaco-4.1.0/examples/0000755000175100001440000000000011674464170015402 5ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/0000755000175100001440000000000011674464170016326 5ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/canvas/0000755000175100001440000000000011674464170017601 5ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/canvas/cliptest.py0000644000175100001440000000557011674464170022011 0ustar ischnellusers00000000000000#!/usr/bin/env python """ The main app for the PlotCanvas application """ # Enthought library imports from traits.api import Float from enable.api import Window, Container, Component, Pointer from enable.tools.api import MoveTool from enable.example_support import DemoFrame, demo_main class Box(Component): """ The box moves wherever the user clicks and drags. """ normal_pointer = Pointer("arrow") moving_pointer = Pointer("hand") offset_x = Float offset_y = Float fill_color = (0.8, 0.0, 0.1, 1.0) moving_color = (0.0, 0.8, 0.1, 1.0) resizable = "" def __init__(self, *args, **kw): Component.__init__(self, *args, **kw) def _draw_mainlayer(self, gc, view_bounds=None, mode="default"): with gc: gc.set_fill_color(self.fill_color) dx, dy = self.bounds x, y = self.position gc.clip_to_rect(x, y, dx, dy) gc.rect(x, y, dx, dy) gc.fill_path() ## draw line around outer box #gc.set_stroke_color((0,0,0,1)) #gc.rect(self.outer_x, self.outer_y, self.outer_width, self.outer_height) #gc.stroke_path() return def normal_left_down(self, event): self.event_state = "moving" event.window.set_pointer(self.moving_pointer) event.window.set_mouse_owner(self, event.net_transform()) self.offset_x = event.x - self.x self.offset_y = event.y - self.y event.handled = True return def moving_mouse_move(self, event): self.position = [event.x-self.offset_x, event.y-self.offset_y] event.handled = True self.request_redraw() return def moving_left_up(self, event): self.event_state = "normal" event.window.set_pointer(self.normal_pointer) event.window.set_mouse_owner(None) event.handled = True self.request_redraw() return def moving_mouse_leave(self, event): self.moving_left_up(event) event.handled = True return class MainFrame(DemoFrame): def _create_window(self): a = Box(bounds=[75, 75], position=[50,50], fill_color=(1, 0, 0, 1)) b = Box(bounds=[75, 75], position=[200,50], fill_color=(0, 1, 0, 1)) c = Box(bounds=[75, 75], position=[50,200], fill_color=(0, 0, 1, 1)) cont = Container(a, b, c, bounds=[400,400], border_visible=True, bgcolor="lightgray") #cont.unified_draw = True #cont.draw_layer = "background" cont2 = Container(bounds=[300,300], border_visible=True, bgcolor="cyan") cont.tools.append(MoveTool(cont, drag_button="left")) cont2.tools.append(MoveTool(cont2, drag_button="left")) outer = Container(cont, cont2, fit_window=True) return Window(self, -1, component=outer) if __name__ == "__main__": demo_main(MainFrame, size=(800,800), title="ClipTest") chaco-4.1.0/examples/demo/canvas/mp_move_tool.py0000644000175100001440000000064111674464170022653 0ustar ischnellusers00000000000000 from traits.api import Int from enable.tools.api import MoveTool class MPMoveTool(MoveTool): cur_bid = Int(-1) def normal_blob_down(self, event): if self.cur_bid == -1: self.cur_bid = event.bid self.normal_left_down(event) def dragging_blob_up(self, event): if event.bid == self.cur_bid: self.cur_bid = -1 self.normal_left_up(event) chaco-4.1.0/examples/demo/canvas/data_source_button.py0000644000175100001440000001555211674464170024047 0ustar ischnellusers00000000000000 from random import choice from traits.api import Any, Enum, HasTraits, Instance, Int, List, Str from chaco.example_support import COLOR_PALETTE from chaco.api import Plot from chaco.plot_canvas_toolbar import PlotToolbarButton DEBUG = False class ButtonController(HasTraits): """ Tells buttons what to do Buttons defer to this when they are activated. """ modifier = Enum("control", "shift", "alt") # The list of buttons that are currently "down" active_buttons = List # A reference to the Plot object that displays scatterplots of multiple # dataseries plot = Instance(Plot) # The transient plot overlay housing self.plot plot_overlay = Any # The name of the scatter plot in the Plot _scatterplot_name = "ButtonControllerPlot" def notify(self, button, type, event): """ Informs the controller that the particular **button** just got an event. **Type** is either "up" or "down". Event is the actual mouse event. """ #control_down = getattr(event, self.modifier + "_down", False) control_down = True if DEBUG: print "[notify]", button.plotname, type, "control:", control_down if type == "down": if control_down and button in self.active_buttons: self.button_deselected(button) else: if not control_down: # Deselect all current buttons and select the new one [self.button_deselected(b) for b in self.active_buttons \ if b is not button] self.button_selected(button) else: # type == "up" #if not control_down: if 1: self.button_deselected(button) return def button_selected(self, button): if DEBUG: print "active:", [b.plotname for b in self.active_buttons] print "new button selected:", button.plotname if button in self.active_buttons: return numbuttons = len(self.active_buttons) if numbuttons == 0: self.active_buttons.append(button) button.show_overlay() elif numbuttons == 1: self.active_buttons[0].hide_overlay() self.active_buttons.append(button) self.show_scatterplot(*self.active_buttons) elif numbuttons == 2: # Replace the last active button with the new one self.active_buttons[1].button_state = "up" self.active_buttons[1] = button self.hide_scatterplot() self.show_scatterplot(*self.active_buttons) else: return button.button_state = "down" return def button_deselected(self, button): if DEBUG: print "active:", [b.plotname for b in self.active_buttons] print "new button deselected:", button.plotname if button not in self.active_buttons: button.button_state = "up" return numbuttons = len(self.active_buttons) if numbuttons == 1: if button in self.active_buttons: self.active_buttons.remove(button) button.hide_overlay() elif numbuttons == 2: if button in self.active_buttons: self.active_buttons.remove(button) self.hide_scatterplot() remaining_button = self.active_buttons[0] remaining_button.show_overlay() else: return button.button_state = "up" return def show_scatterplot(self, b1, b2): if len(self.plot.plots) > 0: self.plot.delplot(*self.plot.plots.keys()) cur_plot = self.plot.plot((b1.plotname+"_y", b2.plotname+"_y"), name=self._scatterplot_name, type="scatter", marker="square", color=tuple(choice(COLOR_PALETTE)), marker_size=8, ) self.plot.index_axis.title = b1.plotname #self.plot.value_axis.title = b2.plotname self.plot.title = b1.plotname + " vs. " + b2.plotname self.plot_overlay.visible = True self.plot.request_redraw() def hide_scatterplot(self): if self._scatterplot_name in self.plot.plots: self.plot.delplot(self._scatterplot_name) self.plot.index_range.set_bounds("auto", "auto") self.plot.value_range.set_bounds("auto", "auto") self.plot_overlay.visible = False class DataSourceButton(PlotToolbarButton): # A TransientPlotOverlay containing the timeseries plot of this datasource plot_overlay = Any plotname = Str canvas = Any #overlay_bounds = List() # Can't call this "controller" because it conflicts with old tool dispatch button_controller = Instance(ButtonController) # Override inherited trait label_color = (0,0,0,1) resizable = "" cur_bid = Int(-1) # The overlay to display when the user holds the mouse down over us. #_overlay = Instance(AbstractOverlay) def normal_left_down(self, event): self.button_state = "down" self.button_controller.notify(self, "down", event) event.handled = True self.request_redraw() def normal_left_up(self, event): self.button_state = "up" self.button_controller.notify(self, "up", event) event.handled = True self.request_redraw() def normal_blob_down(self, event): if self.cur_bid == -1: self.cur_bid = event.bid self.normal_left_down(event) if hasattr(event, "bid"): event.window.capture_blob(self, event.bid, event.net_transform()) def normal_blob_up(self, event): if event.bid == self.cur_bid: if hasattr(event, "bid"): event.window.release_blob(event.bid) self.cur_bid = -1 self.normal_left_up(event) def normal_mouse_leave(self, event): if event.left_down: return self.normal_left_up(event) def normal_mouse_enter(self, event): if event.left_down: return self.normal_left_down(event) def show_overlay(self): if self.plot_overlay is not None: self._do_layout() self.plot_overlay.visible = True self.request_redraw() return def hide_overlay(self): if self.plot_overlay is not None: self.plot_overlay.visible = False self.request_redraw() return def _do_layout(self): if self.canvas is not None: boff = self.canvas.bounds_offset self.plot_overlay.offset = (boff[0], boff[1] + self.y - self.container.y + self.height/2) self.plot_overlay.do_layout() chaco-4.1.0/examples/demo/canvas/mp_viewport_pan_tool.py0000644000175100001440000000277711674464170024436 0ustar ischnellusers00000000000000 from traits.api import Int, Tuple from enable.tools.api import ViewportPanTool class MPViewportPanTool(ViewportPanTool): cur_bid = Int(-1) _last_blob_pos = Tuple def normal_blob_down(self, event): if self.cur_bid == -1 and self.is_draggable(event.x, event.y): self.cur_bid = event.bid self.drag_start(event) def dragging_blob_up(self, event): if event.bid == self.cur_bid: self.cur_bid = -1 self.drag_end(event) def dragging_blob_move(self, event): if event.bid == self.cur_bid: self._last_blob_pos = (event.x, event.y) self.dragging(event) def drag_start(self, event): if self.component: self.original_padding = self.component.padding if hasattr(event, "bid"): event.window.capture_blob(self, event.bid, event.net_transform()) else: event.window.set_mouse_owner(self, event.net_transform()) self._last_blob_pos = (event.x, event.y) self.mouse_down_position = (event.x,event.y) self.event_state = "dragging" event.handled = True ViewportPanTool.drag_start(self, event) return def drag_end(self, event): event.x, event.y = self._last_blob_pos if hasattr(event, "bid"): event.window.release_blob(event.bid) self.event_state = "normal" ViewportPanTool.drag_end(self, event) chaco-4.1.0/examples/demo/canvas/mptools.py0000644000175100001440000003060211674464170021651 0ustar ischnellusers00000000000000""" A collection of Chaco tools that respond to a multi-pointer interface """ from numpy import asarray, dot, sqrt # Enthought library imports from traits.api import Delegate, Dict, Enum, Instance, Int, Property, Trait, Tuple, CArray # Chaco imports from chaco.api import BaseTool from chaco.tools.api import PanTool, DragZoom, LegendTool, RangeSelection BOGUS_BLOB_ID = -1 def l2norm(v): return sqrt(dot(v,v)) class MPPanTool(PanTool): cur_bid = Int(BOGUS_BLOB_ID) def normal_blob_down(self, event): if self.cur_bid == BOGUS_BLOB_ID: self.cur_bid = event.bid self._start_pan(event, capture_mouse=False) event.window.capture_blob(self, event.bid, event.net_transform()) def panning_blob_up(self, event): if event.bid == self.cur_bid: self.cur_bid = BOGUS_BLOB_ID self._end_pan(event) def panning_blob_move(self, event): if event.bid == self.cur_bid: self._dispatch_stateful_event(event, "mouse_move") def panning_mouse_leave(self, event): """ Handles the mouse leaving the plot when the tool is in the 'panning' state. Don't end panning. """ return def _end_pan(self, event): if hasattr(event, "bid"): event.window.release_blob(event.bid) PanTool._end_pan(self, event) class MPDragZoom(DragZoom): speed = 1.0 # The original dataspace points where blobs 1 and 2 went down _orig_low = CArray #Trait(None, None, Tuple) _orig_high = CArray #Trait(None, None, Tuple) # Dataspace center of the zoom action _center_pt = Trait(None, None, Tuple) # Maps blob ID numbers to the (x,y) coordinates that came in. _blobs = Dict() # Maps blob ID numbers to the (x0,y0) coordinates from blob_move events. _moves = Dict() # Properties to convert the dictionaries to map from blob ID numbers to # a single coordinate appropriate for the axis the range selects on. _axis_blobs = Property(Dict) _axis_moves = Property(Dict) def _convert_to_axis(self, d): """ Convert a mapping of ID to (x,y) tuple to a mapping of ID to just the coordinate appropriate for the selected axis. """ if self.axis == 'index': idx = self.axis_index else: idx = 1-self.axis_index d2 = {} for id, coords in d.items(): d2[id] = coords[idx] return d2 def _get__axis_blobs(self): return self._convert_to_axis(self._blobs) def _get__axis_moves(self): return self._convert_to_axis(self._moves) def drag_start(self, event, capture_mouse=False): bid1, bid2 = sorted(self._moves) xy01, xy02 = self._moves[bid1], self._moves[bid2] self._orig_low, self._orig_high = map(asarray, self._map_coordinate_box(xy01, xy02)) self.orig_center = (self._orig_high + self._orig_low) / 2.0 self.orig_diag = l2norm(self._orig_high - self._orig_low) #DragZoom.drag_start(self, event, capture_mouse) self._original_xy = xy02 c = self.component self._orig_screen_bounds = ((c.x,c.y), (c.x2,c.y2)) self._original_data = (c.x_mapper.map_data(xy02[0]), c.y_mapper.map_data(xy02[1])) self._prev_y = xy02[1] if capture_mouse: event.window.set_pointer(self.drag_pointer) def normal_blob_down(self, event): if len(self._blobs) < 2: self._blobs[event.bid] = (event.x, event.y) event.window.capture_blob(self, event.bid, transform=event.net_transform()) event.handled = True def normal_blob_up(self, event): self._handle_blob_leave(event) def normal_blob_move(self, event): self._handle_blob_move(event) def normal_blob_frame_end(self, event): if len(self._moves) == 2: self.event_state = "dragging" self.drag_start(event, capture_mouse=False) def dragging_blob_move(self, event): self._handle_blob_move(event) def dragging_blob_frame_end(self, event): # Get dataspace coordinates of the previous and new coordinates bid1, bid2 = sorted(self._moves) p1, p2 = self._blobs[bid1], self._blobs[bid2] low, high = map(asarray, self._map_coordinate_box(p1, p2)) # Compute the amount of translation center = (high + low) / 2.0 translation = center - self.orig_center # Computing the zoom factor. We have the coordinates of the original # blob_down events, and we have a new box as well. For now, just use # the relative sizes of the diagonals. diag = l2norm(high - low) zoom = self.speed * self.orig_diag / diag # The original screen bounds are used to test if we've reached max_zoom orig_screen_low, orig_screen_high = \ map(asarray, self._map_coordinate_box(*self._orig_screen_bounds)) new_low = center - zoom * (center - orig_screen_low) - translation new_high = center + zoom * (orig_screen_high - center) - translation for ndx in (0,1): if self._zoom_limit_reached(orig_screen_low[ndx], orig_screen_high[ndx], new_low[ndx], new_high[ndx]): return c = self.component c.x_mapper.range.set_bounds(new_low[0], new_high[0]) c.y_mapper.range.set_bounds(new_low[1], new_high[1]) self.component.request_redraw() def dragging_blob_up(self, event): self._handle_blob_leave(event) def _handle_blob_move(self, event): if event.bid not in self._blobs: return self._blobs[event.bid] = event.x, event.y self._moves[event.bid] = event.x0, event.y0 event.handled = True def _handle_blob_leave(self, event): if event.bid in self._blobs: del self._blobs[event.bid] self._moves.pop(event.bid, None) event.window.release_blob(event.bid) if len(self._blobs) < 2: self.event_state = "normal" class MPPanZoom(BaseTool): """ This tool wraps a pan and a zoom tool, and automatically switches behavior back and forth depending on how many blobs are tracked on screen. """ pan = Instance(MPPanTool) zoom = Instance(MPDragZoom) event_state = Enum("normal", "pan", "zoom") _blobs = Delegate('zoom') _moves = Delegate('zoom') def _dispatch_stateful_event(self, event, suffix): self.zoom.dispatch(event, suffix) event.handled = False self.pan.dispatch(event, suffix) if len(self._blobs) == 2: self.event_state = 'zoom' elif len(self._blobs) == 1: self.event_state = 'pan' elif len(self._blobs) == 0: self.event_state = 'normal' else: assert len(self._blobs) <= 2 if suffix == 'blob_up': event.window.release_blob(event.bid) elif suffix == 'blob_down': event.window.release_blob(event.bid) event.window.capture_blob(self, event.bid, event.net_transform()) event.handled = True def _component_changed(self, old, new): self.pan.component = new self.zoom.component = new def _pan_default(self): return MPPanTool(self.component) def _zoom_default(self): return MPDragZoom(self.component) class MPLegendTool(LegendTool): event_state = Enum("normal", "dragging") cur_bid = Int(-1) def normal_blob_down(self, event): if self.cur_bid == -1 and self.is_draggable(event.x, event.y): self.cur_bid = event.bid self.drag_start(event) def dragging_blob_up(self, event): if event.bid == self.cur_bid: self.cur_bid = -1 self.drag_end(event) def dragging_blob_move(self, event): if event.bid == self.cur_bid: self.dragging(event) def drag_start(self, event): if self.component: self.original_padding = self.component.padding if hasattr(event, "bid"): event.window.capture_blob(self, event.bid, event.net_transform()) else: event.window.set_mouse_owner(self, event.net_transform()) self.mouse_down_position = (event.x,event.y) self.event_state = "dragging" event.handled = True return def drag_end(self, event): if hasattr(event, "bid"): event.window.release_blob(event.bid) self.event_state = "normal" LegendTool.drag_end(self, event) class MPRangeSelection(RangeSelection): # Maps blob ID numbers to the (x,y) coordinates that came in. _blobs = Dict() # Maps blob ID numbers to the (x0,y0) coordinates from blob_move events. _moves = Dict() # Properties to convert the dictionaries to map from blob ID numbers to # a single coordinate appropriate for the axis the range selects on. _axis_blobs = Property(Dict) _axis_moves = Property(Dict) def _convert_to_axis(self, d): """ Convert a mapping of ID to (x,y) tuple to a mapping of ID to just the coordinate appropriate for the selected axis. """ if self.axis == 'index': idx = self.axis_index else: idx = 1-self.axis_index d2 = {} for id, coords in d.items(): d2[id] = coords[idx] return d2 def _get__axis_blobs(self): return self._convert_to_axis(self._blobs) def _get__axis_moves(self): return self._convert_to_axis(self._moves) def normal_blob_down(self, event): if len(self._blobs) < 2: self._blobs[event.bid] = (event.x, event.y) event.window.capture_blob(self, event.bid, transform=event.net_transform()) event.handled = True def normal_blob_up(self, event): self._handle_blob_leave(event) def normal_blob_frame_end(self, event): if len(self._blobs) == 2: self.event_state = "selecting" #self.drag_start(event, capture_mouse=False) #self.selecting_mouse_move(event) self._set_sizing_cursor(event) self.selection = sorted(self._axis_blobs.values()) def selecting_blob_move(self, event): if event.bid in self._blobs: self._blobs[event.bid] = event.x, event.y self._moves[event.bid] = event.x0, event.y0 def selecting_blob_up(self, event): self._handle_blob_leave(event) def selecting_blob_frame_end(self, event): if self.selection is None: return elif len(self._blobs) == 2: axis_index = self.axis_index low = self.plot.position[axis_index] high = low + self.plot.bounds[axis_index] - 1 p1, p2 = self._axis_blobs.values() # XXX: what if p1 or p2 is out of bounds? m1 = self.mapper.map_data(p1) m2 = self.mapper.map_data(p2) low_val = min(m1, m2) high_val = max(m1, m2) self.selection = (low_val, high_val) self.component.request_redraw() elif len(self._moves) == 1: id, p0 = self._axis_moves.items()[0] m0 = self.mapper.map_data(p0) low, high = self.selection if low <= m0 <= high: m1 = self.mapper.map_data(self._axis_blobs[id]) dm = m1 - m0 self.selection = (low+dm, high+dm) def selected_blob_down(self, event): if len(self._blobs) < 2: self._blobs[event.bid] = (event.x, event.y) event.window.capture_blob(self, event.bid, transform=event.net_transform()) event.handled = True def selected_blob_move(self, event): if event.bid in self._blobs: self._blobs[event.bid] = event.x, event.y self._moves[event.bid] = event.x0, event.y0 def selected_blob_frame_end(self, event): self.selecting_blob_frame_end(event) def selected_blob_up(self, event): self._handle_blob_leave(event) def _handle_blob_leave(self, event): self._moves.pop(event.bid, None) if event.bid in self._blobs: del self._blobs[event.bid] event.window.release_blob(event.bid) # Treat the blob leave as a selecting_mouse_up event self.selecting_right_up(event) if len(self._blobs) < 2: self.event_state = "selected" chaco-4.1.0/examples/demo/canvas/canvas.py0000644000175100001440000002763211674464170021440 0ustar ischnellusers00000000000000#!/usr/bin/env python """ The main app for the PlotCanvas application """ # FIXME - this is broken MULTITOUCH = False DEBUG = False # Major library imports from copy import copy from numpy import arange, fabs, linspace, pi, sin from numpy import random from scipy.special import jn # Enthought library imports from enable.api import Viewport, Window from enable.tools.api import MoveTool, ResizeTool, ViewportPanTool from enable.example_support import DemoFrame, demo_main from traits.api import Any, Bool, Enum, Float, HasTraits, Instance, \ List, Str # Chaco imports from chaco.api import AbstractOverlay, ArrayPlotData, \ Plot, jet, ScatterPlot, LinePlot, LinearMapper from chaco.tools.api import PanTool, ZoomTool , LegendTool # Canvas imports from chaco.plot_canvas import PlotCanvas from chaco.plot_canvas_toolbar import PlotCanvasToolbar, PlotToolbarButton from transient_plot_overlay import TransientPlotOverlay from axis_tool import AxisTool, RangeController, MPAxisTool from plot_clone_tool import PlotCloneTool, MPPlotCloneTool from data_source_button import ButtonController, DataSourceButton from mp_move_tool import MPMoveTool from mp_viewport_pan_tool import MPViewportPanTool #from canvas_grid import CanvasGrid # Multitouch imports if MULTITOUCH: from mptools import MPPanTool, MPDragZoom, MPLegendTool, \ MPPanZoom, MPRangeSelection #AxisTool = MPAxisTool PlotCloneTool = MPPlotCloneTool NUMPOINTS = 250 DATA = { "GOOG": random.uniform(-2.0, 10.0, NUMPOINTS), "MSFT": random.uniform(-2.0, 10.0, NUMPOINTS), "AAPL": random.uniform(-2.0, 10.0, NUMPOINTS), "YHOO": random.uniform(-2.0, 10.0, NUMPOINTS), "CSCO": random.uniform(-2.0, 10.0, NUMPOINTS), "INTC": random.uniform(-2.0, 10.0, NUMPOINTS), "ORCL": random.uniform(-2.0, 10.0, NUMPOINTS), "HPQ": random.uniform(-2.0, 10.0, NUMPOINTS), "DELL": random.uniform(-2.0, 10.0, NUMPOINTS), } def add_basic_tools(plot): plot.tools.append(PanTool(plot)) plot.tools.append(MoveTool(plot, drag_button="right")) zoom = ZoomTool(component=plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) def do_plot(name, pd): xname = name + "_x" yname = name + "_y" pd.set_data(xname, range(len(DATA[name]))) pd.set_data(yname, DATA[name]) plot = Plot(pd, padding = 30, unified_draw = True, border_visible = True, ) plot.x_axis.visible = False plot.title = name plot.plot((xname, yname), name=name, type="line", color="blue",) return plot def clone_renderer(r): """ Returns a clone of plot renderer r """ basic_traits = ["orientation", "line_width", "color", "outline_color", "bgcolor", "border_visible", "border_color", "visible", "fill_padding", "resizable", "aspect_ratio", "draw_layer", "draw_order", "border_width", "resizable", "index", "value",] scatter_traits = ["custom_symbol", "marker", "marker_size", "selection_marker", "selection_marker_size", "selection_line_width", "selection_color"] line_traits = ["selected_color", "selected_line_style", "metadata_name", "render_style"] if isinstance(r, ScatterPlot): return r.clone_traits(basic_traits + scatter_traits) elif isinstance(r, LinePlot): return r.clone_traits(basic_traits + line_traits) def clone_plot(clonetool, drop_position): # A little sketchy... canvas = clonetool.component.container.component.component # Create a new Plot object oldplot = clonetool.component newplot = Plot(oldplot.data) basic_traits = ["orientation", "default_origin", "bgcolor", "border_color", "border_width", "border_visible", "draw_layer", "unified_draw", "fit_components", "fill_padding", "visible", "aspect_ratio", "title"] for attr in basic_traits: setattr(newplot, attr, getattr(oldplot, attr)) # copy the ranges dst = newplot.range2d src = oldplot.range2d #for attr in ('_low_setting', '_low_value', '_high_setting', '_high_value'): # setattr(dst, attr, getattr(src, attr)) dst._xrange.sources = copy(src._xrange.sources) dst._yrange.sources = copy(src._yrange.sources) newplot.padding = oldplot.padding newplot.bounds = oldplot.bounds[:] newplot.resizable = "" newplot.position = drop_position newplot.datasources = copy(oldplot.datasources) for name, renderers in oldplot.plots.items(): newrenderers = [] for renderer in renderers: new_r = clone_renderer(renderer) new_r.index_mapper = LinearMapper(range=newplot.index_range) new_r.value_mapper = LinearMapper(range=newplot.value_range) new_r._layout_needed = True new_r.invalidate_draw() new_r.resizable = "hv" newrenderers.append(new_r) newplot.plots[name] = newrenderers #newplot.plots = copy(oldplot.plots) for name, renderers in newplot.plots.items(): newplot.add(*renderers) newplot.index_axis.title = oldplot.index_axis.title newplot.index_axis.unified_draw = True newplot.value_axis.title = oldplot.value_axis.title newplot.value_axis.unified_draw = True # Add new tools to the new plot newplot.tools.append(AxisTool(component=newplot, range_controller=canvas.range_controller)) # Add tools to the new plot pan_traits = ["drag_button", "constrain", "constrain_key", "constrain_direction", "speed"] zoom_traits = ["tool_mode", "always_on", "axis", "enable_wheel", "drag_button", "wheel_zoom_step", "enter_zoom_key", "exit_zoom_key", "pointer", "color", "alpha", "border_color", "border_size", "disable_on_complete", "minimum_screen_delta", "max_zoom_in_factor", "max_zoom_out_factor"] move_traits = ["drag_button", "end_drag_on_leave", "cancel_keys", "capture_mouse", "modifier_key"] if not MULTITOUCH: for tool in oldplot.tools: if isinstance(tool, PanTool): newtool = tool.clone_traits(pan_traits) newtool.component = newplot break else: newtool = PanTool(newplot) # Reconfigure the pan tool to always use the left mouse, because we will # put plot move on the right mouse button newtool.drag_button = "left" newplot.tools.append(newtool) for tool in oldplot.tools: if isinstance(tool, MoveTool): newtool = tool.clone_traits(move_traits) newtool.component = newplot break else: newtool = MoveTool(newplot, drag_button="right") newplot.tools.append(newtool) for tool in oldplot.tools: if isinstance(tool, ZoomTool): newtool = tool.clone_traits(zoom_traits) newtool.component = newplot break else: newtool = ZoomTool(newplot) newplot.tools.append(newtool) else: pz = MPPanZoom(newplot) #pz.pan.constrain = True #pz.pan.constrain_direction = "x" #pz.zoom.mode = "range" #pz.zoom.axis = "index" newplot.tools.append(MPPanZoom(newplot)) #newplot.tools.append(MTMoveTool( newplot._layout_needed = True clonetool.dest.add(newplot) newplot.invalidate_draw() newplot.request_redraw() canvas.request_redraw() return def make_toolbar(canvas): # Create the toolbar toolbar = PlotCanvasToolbar(bounds=[70, 200], position=[50,350], fill_padding=True, bgcolor="lightgrey", padding = 5, align = "left", ) # Create the scatterplot pd = ArrayPlotData() scatterplot = Plot(pd, padding=15, bgcolor="white", unified_draw=True, border_visible=True) if not MULTITOUCH: scatterplot.tools.append(PanTool(scatterplot, drag_button="right")) scatterplot.tools.append(ZoomTool(scatterplot)) else: scatterplot.tools.append(MPPanZoom(scatterplot)) scatterplot.overlays.append(PlotCloneTool(scatterplot, dest=canvas, plot_cloner=clone_plot)) # Create the overlay overlay = TransientPlotOverlay(component=toolbar, overlay_component=scatterplot, bounds=[350,350], border_visible=True, visible = False, # initially invisible ) scatterplot.container = overlay # Create buttons controller = ButtonController() for name in DATA.keys(): plot = do_plot(name, pd) if MULTITOUCH: plot.tools.append(MPPanZoom(plot)) else: plot.tools.append(PanTool(plot, drag_button="right", constrain=True, constrain_direction="x")) plot.tools.append(ZoomTool(plot, tool_mode="range", axis="index", always_on=False)) plot.overlays.append(PlotCloneTool(plot, dest=canvas, plot_cloner=clone_plot)) plot_overlay = TransientPlotOverlay(component=toolbar, overlay_component=plot, border_visible=True, visible=False, ) plot.container = plot_overlay button = DataSourceButton(label=name, bounds=[80,46], padding = 5, button_controller = controller, #canvas = canvas, plot_overlay = plot_overlay, plotname = name) toolbar.add(button) canvas.overlays.append(plot_overlay) controller.plot = scatterplot controller.plot_overlay = overlay canvas.overlays.append(overlay) return toolbar class PlotFrame(DemoFrame): def _create_viewport(self): # Create a container and add our plots canvas = PlotCanvas() canvas.range_controller = RangeController(cavas = canvas) toolbar = make_toolbar(canvas) toolbar.component = canvas canvas.overlays.append(toolbar) viewport = Viewport(component=canvas) if MULTITOUCH: viewport.tools.append(MPViewportPanTool(viewport)) else: viewport.tools.append(ViewportPanTool(viewport, drag_button="right")) return viewport def _create_window_mt(self): viewport = self._create_viewport() from enactable.configuration import arg_parser, get_global_config from enactable.enable.enable_blob_listener import BlobWindow from enactable.enable.blobprovider import NetworkBlobProvider parser = arg_parser() args = parser.parse_args() cfg = get_global_config() tconf = cfg.tconf tconf.from_arguments(args) provider = NetworkBlobProvider(host=tconf.Server.host, port=tconf.Server.port) provider.start() return BlobWindow(self, -1, component=viewport, blob_provider=provider) def _create_window_simple(self): viewport = self._create_viewport() return Window(self, -1, component=viewport) def _create_window(self): if MULTITOUCH: return self._create_window_mt() else: return self._create_window_simple() if __name__ == "__main__": demo_main(PlotFrame, size=(1000,700), title="PlotCanvas") # EOF chaco-4.1.0/examples/demo/canvas/transient_plot_overlay.py0000644000175100001440000000545011674464170024765 0ustar ischnellusers00000000000000 from __future__ import with_statement from enable.api import Component from traits.api import Enum, Float, Instance, Trait, Tuple from chaco.api import AbstractOverlay, BasePlotContainer class TransientPlotOverlay(BasePlotContainer, AbstractOverlay): """ Allows an arbitrary plot component to be overlaid on top of another one. """ # The PlotComponent to draw as an overlay overlay_component = Instance(Component) # Where this overlay should draw relative to our .component align = Enum("right", "left", "top", "bottom") # The amount of space between the overlaying component and the underlying # one. This is either horizontal or vertical (depending on the value of # self.align), but is not both. margin = Float(10) # An offset to apply in X and Y offset = Trait(None, None, Tuple) # Override default values of some inherited traits unified_draw = True resizable = "" def _bounds_default(self): return [450, 250] def _clear_bounds(self, gc, view_bounds): if view_bounds is None: view_bounds = (0,0, self.width, self.height) gc.clip_to_rect(*view_bounds) gc.set_fill_color((1.0,1.0,1.0,1.0)) gc.begin_path() gc.rect(*view_bounds) gc.fill_path() def overlay(self, component, gc, view_bounds=None, mode="normal"): self._do_layout() with gc: self._clear_bounds(gc, view_bounds) self.overlay_component._draw(gc, view_bounds, mode) # TODO: Implement this more intelligently than the one in BasePlotContainer #def get_preferred_size(self): # pass def _do_layout(self): component = self.component bounds = self.outer_bounds if self.align in ("right", "left"): y = component.outer_y -(bounds[1] - component.outer_height) / 2 if self.align == "right": x = component.outer_x2 + self.margin else: x = component.outer_x - bounds[0] - self.margin else: # "top", "bottom" x = component.outer_x -(bounds[0] - component.outer_width) / 2 if self.align == "top": y = component.outer_y2 + self.margin else: y = component.outer_y - bounds[1] - self.margin if self.offset is not None: x += self.offset[0] y += self.offset[1] overlay_component = self.overlay_component overlay_component.outer_bounds = self.outer_bounds overlay_component.outer_position = [x, y] overlay_component._layout_needed = True overlay_component.do_layout() def dispatch(self, event, suffix): if self.visible and self.overlay_component.is_in(event.x, event.y): return self.overlay_component.dispatch(event, suffix) chaco-4.1.0/examples/demo/canvas/plot_clone_tool.py0000644000175100001440000001133611674464170023352 0ustar ischnellusers00000000000000""" Makes a copy of the plot in the overlay and adds it to the canvas. """ from __future__ import with_statement # Enthought library imports from traits.api import Bool, Callable, Enum, Float, Instance, Int, Trait, Tuple from enable.api import Container # Chaco imports from chaco.api import AbstractOverlay from enable.tools.api import DragTool class PlotCloneTool(AbstractOverlay, DragTool): """ On a drag operation, draws an overlay of self.component underneath the cursor. On drag_end, a copy of the plot is dropped onto the self.dest container. """ # The container to add the cloned plot to dest = Instance(Container) # A function that gets called on drag_end. It gets passed this tool # and the position at which to place the new cloned plot. plot_cloner = Callable # The amount to fade the plot when we draw as overlay alpha = Float(0.5) # The possible event states for this tool. event_state = Enum("normal", "dragging") capture_mouse = True # The (x,y) position of the "last" mouse position we received _offset = Trait(None, None, Tuple) # The relative position of the mouse_down_position to the origin # of the plot's coordinate system _offset_from_plot = Tuple # This is set to True before we attempt to move the plot, so that # we do not get called again, in case we are an overlay on the plot # we are drawing. _recursion_check = Bool(False) def overlay(self, component, gc, view_bounds=None, mode="normal"): if self._recursion_check: return else: if self._offset is not None and (self._offset[0] > 10 or self._offset[1] > 10): with gc: gc.clear_clip_path() gc.translate_ctm(*self._offset) gc.set_alpha(self.alpha) self._recursion_check = True self.component._draw(gc, view_bounds, mode) self._recursion_check = False def drag_start(self, event): """ Called when the drag operation starts. Implements DragTool. """ self._offset = (event.x - self.mouse_down_position[0], event.y - self.mouse_down_position[1]) self._offset_from_plot = (self.mouse_down_position[0] - self.component.x, self.mouse_down_position[1] - self.component.y) self.visible = True event.handled = True def dragging(self, event): self._offset = (event.x - self.mouse_down_position[0], event.y - self.mouse_down_position[1]) self.component.request_redraw() def drag_end(self, event): if self.plot_cloner is not None: # Recreate the event transform history and figure out the coordinates # of the event in the Canvas's coordinate system offset = self._offset_from_plot drop_position = (event.x - offset[0], event.y - offset[1]) self.plot_cloner(self, drop_position) self._offset = None self.visible = False self.component.request_redraw() class MPPlotCloneTool(PlotCloneTool): cur_bid = Int(-1) _last_blob_pos = Tuple def normal_blob_down(self, event): if self.cur_bid == -1 and self.is_draggable(event.x, event.y): self.cur_bid = event.bid self.drag_start(event) def dragging_blob_up(self, event): if event.bid == self.cur_bid: self.cur_bid = -1 self.drag_end(event) def dragging_blob_move(self, event): if event.bid == self.cur_bid: self.dragging(event) self._last_blob_pos = (event.x, event.y) def drag_start(self, event): if self.component: self.original_padding = self.component.padding if hasattr(event, "bid"): event.window.capture_blob(self, event.bid, event.net_transform()) else: event.window.set_mouse_owner(self, event.net_transform()) self.mouse_down_position = (event.x,event.y) self.event_state = "dragging" event.handled = True PlotCloneTool.drag_start(self, event) return def drag_end(self, event): if hasattr(event, "bid"): event.window.release_blob(event.bid) self.event_state = "normal" if self.plot_cloner is not None: offset = self._offset_from_plot drop_position = self._last_blob_pos if len(drop_position) == 2: self.plot_cloner(self, (drop_position[0] - offset[0], drop_position[1] - offset[1])) self._offset = None chaco-4.1.0/examples/demo/canvas/axis_tool.py0000644000175100001440000001167511674464170022166 0ustar ischnellusers00000000000000 from enable.api import BaseTool, ColorTrait from traits.api import Any, Bool, Dict, Enum, HasTraits, Int, List, Trait, Tuple class RangeController(HasTraits): canvas = Any # The list of active plots and which of their ranges was set plots_ranges = List # Stores the old ranges _ranges = Dict def notify(self, axistool, rangename, type, event): plot = axistool.component range = getattr(plot, rangename) if (type == "down") and ((plot, rangename) not in self.plots_ranges): if len(self.plots_ranges) > 0: src_plot, src_rangename = self.plots_ranges[0] src_range = getattr(src_plot, src_rangename) self.link(src_range, plot, rangename) self.plots_ranges.append((plot, rangename)) else: if (plot, rangename) in self.plots_ranges: if len(self.plots_ranges) > 1: self.unlink(plot, rangename) self.plots_ranges.remove((plot, rangename)) return True def link(self, src_range, dst_plot, dst_rangename): self._ranges[(dst_plot, dst_rangename)] = getattr(dst_plot, dst_rangename) setattr(dst_plot, dst_rangename, src_range) dst_plot.request_redraw() def unlink(self, plot, rangename): setattr(plot, rangename, self._ranges.pop((plot, rangename))) plot.request_redraw() class AxisTool(BaseTool): # The object to notify when we've been clicked # We notify by calling its .notify method, which should have the # signature: # should_handle_event = notify(axis_tool, axis, down_or_up, event) # # It should return a bool indicating whether or not we should process the # event. range_controller = Any down_tick_color = ColorTrait("red") down_axis_line_color = ColorTrait("red") down_tick_label_color = ColorTrait("red") down_bgcolor = ColorTrait("lightgray") down_border_visible = Bool(True) down_border_color = Trait(None, None, ColorTrait) _cached_tick_color = ColorTrait _cached_axis_line_color = ColorTrait _cached_tick_labl_color = ColorTrait _cached_bgcolor = ColorTrait _cached_border_visible = Bool(True) _cached_border_color = ColorTrait attr_list = ("tick_color", "axis_line_color", "tick_label_color", "bgcolor", "border_visible", "border_color") def normal_left_down(self, event): if self.component is None: return plot = self.component if plot.index_axis.is_in(event.x, event.y): axis = plot.index_axis rangename = "index_range" elif plot.value_axis.is_in(event.x, event.y): axis = plot.value_axis rangename = "value_range" else: return # If we have a controller, we let it decide whether # or not we get to handle the event. if self.range_controller is not None: should_handle = self.range_controller.notify(self, rangename, "down", event) if not should_handle: return for attr in self.attr_list: cached = "_cached_" + attr down = "down_" + attr setattr(self, cached, getattr(axis, attr)) if getattr(self, down) is not None: setattr(axis, attr, getattr(self, down)) axis.request_redraw() plot._debug = True event.handled = True return def normal_left_up(self, event): if self.component is None: return plot = self.component if plot.index_axis.is_in(event.x, event.y): axis = plot.index_axis rangename = "index_range" elif plot.value_axis.is_in(event.x, event.y): axis = plot.value_axis rangename = "value_range" else: return if self.range_controller is not None: should_handle = self.range_controller.notify(self, rangename, "up", event) if not should_handle: return for attr in self.attr_list: cached = "_cached_" + attr setattr(axis, attr, getattr(self, cached)) axis.request_redraw() event.handled = True return class MPAxisTool(AxisTool): cur_bid = Int(-1) _last_blob_pos = Tuple def normal_blob_down(self, event): if self.cur_bid == -1: self.cur_bid = event.bid if hasattr(event, "bid"): event.window.capture_blob(self, event.bid, event.net_transform()) self.normal_left_down(event) self._last_blob_pos = (event.x, event.y) def normal_blob_up(self, event): print "Axis blob up" if event.bid == self.cur_bid: if hasattr(event, "bid"): event.window.release_blob(event.bid) self.cur_bid = -1 event.x, event.y = self._last_blob_pos self.normal_left_up(event) chaco-4.1.0/examples/demo/noninteractive.py0000644000175100001440000000574611674464170021744 0ustar ischnellusers00000000000000#!/usr/bin/env python """ This demonstrates how to create a plot offscreen and save it to an image file on disk. """ # Standard library imports import os, sys # Major library imports from numpy import fabs, linspace, pi, sin from scipy.special import jn # Enthought library imports from traits.api import false from traits.etsconfig.api import ETSConfig # Chaco imports from chaco.api import ArrayPlotData, Plot, PlotGraphicsContext from chaco.example_support import COLOR_PALETTE DPI = 72.0 # This is a bit of a hack, to work around the fact that line widths don't scale # with the GraphicsContext's CTM. dpi_scale = DPI / 72.0 def create_plot(): numpoints = 100 low = -5 high = 15.0 x = linspace(low, high, numpoints) pd = ArrayPlotData(index=x) p = Plot(pd, bgcolor="oldlace", padding=50, border_visible=True) for i in range(10): pd.set_data("y" + str(i), jn(i,x)) p.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]), width = 2.0 * dpi_scale) p.x_grid.visible = True p.x_grid.line_width *= dpi_scale p.y_grid.visible = True p.y_grid.line_width *= dpi_scale p.legend.visible = True return p def draw_plot(filename, size=(800,600)): container = create_plot() container.outer_bounds = list(size) container.do_layout(force=True) gc = PlotGraphicsContext(size, dpi=DPI) gc.render_component(container) gc.save(filename) return def draw_svg(filename, size=(800,600)): from chaco.svg_graphics_context import SVGGraphicsContext container = create_plot() container.bounds = list(size) container.do_layout(force=True) gc = SVGGraphicsContext(size) gc.render_component(container) gc.save(filename) def draw_pdf(filename, size=(800,600)): from chaco.pdf_graphics_context import PdfPlotGraphicsContext container = create_plot() container.bounds = list(size) container.do_layout(force=True) gc = PdfPlotGraphicsContext(filename=filename, dest_box = (0.5, 0.5, 5.0, 5.0)) gc.render_component(container) gc.save() def get_directory(filename): print 'Please enter a path in which to place generated plots.' print 'Press to generate in the current directory.' path = raw_input('Path: ').strip() if len(path) > 0 and not os.path.exists(path): print 'The given path does not exist.' sys.exit() if not os.path.isabs(path): print 'Creating image: ' + os.path.join(os.getcwd(), path, filename) else: print 'Creating image: ' + os.path.join(path, filename) return os.path.join(path, filename) if __name__ == "__main__": if ETSConfig.kiva_backend == 'svg': # Render the plot as a SVG draw_svg(get_directory('noninteractive.svg'), size=(800,600)) elif ETSConfig.kiva_backend == 'pdf': # Render the plot as a PDF, requires on ReportLab draw_pdf(get_directory('noninteractive.pdf')) else: draw_plot(get_directory('noninteractive.png'), size=(800, 600)) # EOF chaco-4.1.0/examples/demo/simple_polar.py0000644000175100001440000000344011674464170021367 0ustar ischnellusers00000000000000""" Draws a static polar plot. """ # Major library imports from numpy import arange, pi, cos # Enthought library imports from enable.api import Component, ComponentEditor from traits.api import HasTraits, Instance from traitsui.api import Item, Group, View # Chaco imports from chaco.api import create_polar_plot #=============================================================================== # # Create the Chaco plot. #=============================================================================== def _create_plot_component(): # Create theta data numpoints = 5000 low = 0 high = 2*pi theta = arange(low, high, (high-low) / numpoints) # Create the radius data radius = cos(3*theta) # Create a new polar plot with radius and theta data plot = create_polar_plot((radius,theta),color=(0.0,0.0,1.0,1), width=4.0) return plot #=============================================================================== # Attributes to use for the plot view. size=(600,600) title="Simple Polar Plot" #=============================================================================== # # Demo class that is used by the demo.py application. #=============================================================================== class Demo(HasTraits): plot = Instance(Component) traits_view = View( Group( Item('plot', editor=ComponentEditor(size=size), show_label=False), orientation = "vertical"), resizable=True, title=title, width=size[0], height=size[1] ) def _plot_default(self): return _create_plot_component() demo = Demo() if __name__ == "__main__": demo.configure_traits() # EOF####################### chaco-4.1.0/examples/demo/world_map.py0000644000175100001440000001104111674464170020661 0ustar ischnellusers00000000000000#!/usr/bin/env python """ Displays a world map with locations plotted on top. Locations are expected to be tuples of latitude, longitude where West and South are expressed as negative values. - 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". """ # Standard library imports import os.path import urllib # Major library imports import numpy # ETS imports from chaco.api import Plot, ArrayPlotData, ImageData from chaco.tools.api import ZoomTool from enable.component_editor import ComponentEditor from traits.api import HasTraits, Instance, Str from traitsui.api import Item, View class WorldMapPlot(HasTraits): ### Public Traits ########################################################## # The plot which will be displayed plot = Instance(Plot) # The URL which points to the world map image to be downloaded image_url = Str("http://eoimages.gsfc.nasa.gov/ve//2433/land_shallow_topo_2048.jpg") ### Private Traits ######################################################### # The path to where the image exists on the filesystem image_path = Str() # The view traits_view = View(Item('plot', editor=ComponentEditor(), width=800, height=400, show_label=False), resizable=True) #--------------------------------------------------------------------------- # Public interface #--------------------------------------------------------------------------- def __init__(self, **kw): super(WorldMapPlot, self).__init__(**kw) self._download_map_image() image = ImageData.fromfile(self.image_path) # For now, the locations are hardcoded, though this can be changed # eassily to take command line args, read from a file, or by other # means austin_loc = (30.16, -97.44) locations_x = numpy.array([austin_loc[1]]) locations_y = numpy.array([austin_loc[0]]) # transform each of the locations to the image data space, including # moving the origin from bottom left to top left locations_x = (locations_x + 180) * image.data.shape[1]/360 locations_y = (locations_y*-1 + 90) * image.data.shape[0]/180 # Create the plott data, adding the image and the locations plot_data = ArrayPlotData() plot_data.set_data("imagedata", image._data) plot_data.set_data("locations_x", locations_x) plot_data.set_data("locations_y", locations_y) # Create the plot with the origin as top left, which matches # how the image data is aligned self.plot = Plot(plot_data, default_origin="top left") self.plot.img_plot('imagedata') # Plot the locations as a scatter plot to be overlayed on top # of the map loc_plot = self.plot.plot(('locations_x', 'locations_y'), type='scatter', size=3, color='yellow', marker='dot')[0] loc_plot.x_mapper.range.high = image.data.shape[1] loc_plot.x_mapper.range.low = 0 loc_plot.y_mapper.range.high = image.data.shape[0] loc_plot.y_mapper.range.low = -0 # set up any tools, in this case just the zoom tool zoom = ZoomTool(component=self.plot, tool_mode="box", always_on=False) self.plot.overlays.append(zoom) #--------------------------------------------------------------------------- # Protected interface #--------------------------------------------------------------------------- def _download_map_image(self): """ Downloads a map from the image_url attribute. This is done primarily to keep the redistributable Chaco package as small as possible """ example_dir = os.path.dirname(__file__) self.image_path = os.path.join(example_dir, 'data', os.path.split(self.image_url)[1]) if not os.path.exists(self.image_path): print "Downloading map image" urllib.urlretrieve(self.image_url, self.image_path) #=============================================================================== # demo object that is used by the demo.py application. #=============================================================================== demo = WorldMapPlot() if __name__ == "__main__": demo.configure_traits() chaco-4.1.0/examples/demo/vtk/0000755000175100001440000000000011674464170017132 5ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/vtk/vtk_example.py0000644000175100001440000000375211674464170022032 0ustar ischnellusers00000000000000 from numpy import linspace from scipy.special import jn from tvtk.api import tvtk from mayavi import mlab from enable.vtk_backend.vtk_window import EnableVTKWindow from chaco.api import ArrayPlotData, Plot, OverlayPlotContainer from chaco.tools.api import PanTool, ZoomTool, MoveTool def main(): # Create some x-y data series to plot x = linspace(-2.0, 10.0, 100) pd = ArrayPlotData(index = x) for i in range(5): pd.set_data("y" + str(i), jn(i,x)) # Create some line plots of some of the data plot = Plot(pd, bgcolor="none", padding=30, border_visible=True, overlay_border=True, use_backbuffer=False) plot.legend.visible = True plot.plot(("index", "y0", "y1", "y2"), name="j_n, n<3", color="auto") plot.plot(("index", "y3"), name="j_3", color="auto") plot.tools.append(PanTool(plot)) zoom = ZoomTool(component=plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Create the mlab test mesh and get references to various parts of the # VTK pipeline f = mlab.figure(size=(600,500)) m = mlab.test_mesh() scene = mlab.gcf().scene render_window = scene.render_window renderer = scene.renderer rwi = scene.interactor plot.resizable = "" plot.bounds = [200,200] plot.padding = 25 plot.bgcolor = "lightgray" plot.outer_position = [30,30] plot.tools.append(MoveTool(component=plot,drag_button="right")) container = OverlayPlotContainer(bgcolor = "transparent", fit_window = True) container.add(plot) # Create the Enable Window window = EnableVTKWindow(rwi, renderer, component=container, #istyle_class = tvtk.InteractorStyleSwitch, #istyle_class = tvtk.InteractorStyle, istyle_class = tvtk.InteractorStyleTrackballCamera, bgcolor = "transparent", event_passthrough = True, ) mlab.show() return window, render_window if __name__=="__main__": main() chaco-4.1.0/examples/demo/vtk/cmap_scatter.py0000644000175100001440000001055411674464170022156 0ustar ischnellusers00000000000000#!/usr/bin/env python """ Draws a colormapped scatterplot of some random data. Interactions are the same as simple_line, and additionally, range selection is available on the colorbar. Right-click-drag will select a range of colors on the colormap. This range can be dragged around, and the main plot will respond accordingly. Left-click anywhere on the colorbar to cancel the range selection. """ # Major library imports from numpy import exp, sort from numpy.random import random # VTK-related stuff from tvtk.api import tvtk from mayavi import mlab from enable.vtk_backend.vtk_window import EnableVTKWindow # Chaco imports from chaco.api import ArrayPlotData, ColorBar, \ ColormappedSelectionOverlay, OverlayPlotContainer, \ jet, LinearMapper, Plot from chaco.tools.api import PanTool, ZoomTool, RangeSelection, \ RangeSelectionOverlay, MoveTool #=============================================================================== # # Create the Chaco plot. #=============================================================================== def create_plot(): # Create some data numpts = 200 x = sort(random(numpts)) y = random(numpts) color = exp(-(x**2 + y**2)) # Create a plot data obect and give it this data pd = ArrayPlotData() pd.set_data("index", x) pd.set_data("value", y) pd.set_data("color", color) # Create the plot plot = Plot(pd) plot.plot(("index", "value", "color"), type="cmap_scatter", name="my_plot", color_mapper=jet, marker = "square", fill_alpha = 0.5, marker_size = 6, outline_color = "black", border_visible = True, bgcolor = "white") # Tweak some of the plot properties plot.title = "Colormapped Scatter Plot" plot.padding = 50 plot.x_grid.visible = False plot.y_grid.visible = False plot.x_axis.font = "modern 16" plot.y_axis.font = "modern 16" # Set colors #plot.title_color = "white" #for axis in plot.x_axis, plot.y_axis: # axis.set(title_color="white", tick_label_color="white") # Right now, some of the tools are a little invasive, and we need the # actual ColomappedScatterPlot object to give to them cmap_renderer = plot.plots["my_plot"][0] # Attach some tools to the plot plot.tools.append(PanTool(plot, constrain_key="shift")) zoom = ZoomTool(component=plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) selection = ColormappedSelectionOverlay(cmap_renderer, fade_alpha=0.35, selection_type="mask") cmap_renderer.overlays.append(selection) plot.tools.append(MoveTool(plot, drag_button="right")) return plot def create_colorbar(colormap): colorbar = ColorBar(index_mapper=LinearMapper(range=colormap.range), color_mapper=colormap, orientation='v', resizable='', height=400, width=30, padding=20) colorbar.tools.append(RangeSelection(component=colorbar)) colorbar.overlays.append(RangeSelectionOverlay(component=colorbar, border_color="white", alpha=0.8, fill_color="lightgray")) colorbar.tools.append(MoveTool(colorbar, drag_button="left")) return colorbar def start_vtk(component): f = mlab.figure(size=(700,500)) m = mlab.test_mesh() scene = mlab.gcf().scene render_window = scene.render_window renderer = scene.renderer rwi = scene.interactor window = EnableVTKWindow(rwi, renderer, component = component, istyle_class = tvtk.InteractorStyleTrackballCamera, bgcolor = "transparent", event_passthrough = True, ) mlab.show() def main(): plot = create_plot() plot.bounds = [400,300] plot.outer_position = [30,30] plot.resizable = "" cmap_renderer = plot.plots["my_plot"][0] # Create the colorbar, handing in the appropriate range and colormap colorbar = create_colorbar(plot.color_mapper) colorbar.outer_position = [450,30] colorbar.plot = cmap_renderer colorbar.padding_top = plot.padding_top colorbar.padding_bottom = plot.padding_bottom container = OverlayPlotContainer(bgcolor = "transparent", fit_window = True) container.add(plot) container.add(colorbar) start_vtk(container) if __name__ == "__main__": main() chaco-4.1.0/examples/demo/vtk/spectrum.py0000644000175100001440000001324611674464170021354 0ustar ischnellusers00000000000000#!/usr/bin/env python """ This plot displays the audio spectrum from the microphone. Based on updating_plot.py """ # Major library imports import pyaudio from numpy import zeros, linspace, short, fromstring, hstack, transpose from scipy import fft # Enthought library imports from chaco.default_colormaps import jet from traits.api import HasTraits, Instance, Any # Chaco imports from chaco.api import Plot, ArrayPlotData, HPlotContainer, \ OverlayPlotContainer from chaco.tools.api import MoveTool, PanTool, ZoomTool NUM_SAMPLES = 1024 SAMPLING_RATE = 11025 SPECTROGRAM_LENGTH = 100 def create_plot_component(obj): # Setup the spectrum plot frequencies = linspace(0., float(SAMPLING_RATE)/2, num=NUM_SAMPLES/2) obj.spectrum_data = ArrayPlotData(frequency=frequencies) empty_amplitude = zeros(NUM_SAMPLES/2) obj.spectrum_data.set_data('amplitude', empty_amplitude) obj.spectrum_plot = Plot(obj.spectrum_data) obj.spectrum_plot.plot(("frequency", "amplitude"), name="Spectrum", color="red") obj.spectrum_plot.padding = 50 obj.spectrum_plot.title = "Spectrum" spec_range = obj.spectrum_plot.plots.values()[0][0].value_mapper.range spec_range.low = 0.0 spec_range.high = 5.0 obj.spectrum_plot.index_axis.title = 'Frequency (hz)' obj.spectrum_plot.value_axis.title = 'Amplitude' # Time Series plot times = linspace(0., float(NUM_SAMPLES)/SAMPLING_RATE, num=NUM_SAMPLES) obj.time_data = ArrayPlotData(time=times) empty_amplitude = zeros(NUM_SAMPLES) obj.time_data.set_data('amplitude', empty_amplitude) obj.time_plot = Plot(obj.time_data) obj.time_plot.plot(("time", "amplitude"), name="Time", color="blue") obj.time_plot.padding = 50 obj.time_plot.title = "Time" obj.time_plot.index_axis.title = 'Time (seconds)' obj.time_plot.value_axis.title = 'Amplitude' time_range = obj.time_plot.plots.values()[0][0].value_mapper.range time_range.low = -0.2 time_range.high = 0.2 # Spectrogram plot spectrogram_data = zeros(( NUM_SAMPLES/2, SPECTROGRAM_LENGTH)) obj.spectrogram_plotdata = ArrayPlotData() obj.spectrogram_plotdata.set_data('imagedata', spectrogram_data) spectrogram_plot = Plot(obj.spectrogram_plotdata) spectrogram_time = linspace( 0.0, float(SPECTROGRAM_LENGTH*NUM_SAMPLES)/float(SAMPLING_RATE), num=SPECTROGRAM_LENGTH) spectrogram_freq = linspace(0.0, float(SAMPLING_RATE/2), num=NUM_SAMPLES/2) spectrogram_plot.img_plot('imagedata', name='Spectrogram', xbounds=spectrogram_time, ybounds=spectrogram_freq, colormap=jet, ) range_obj = spectrogram_plot.plots['Spectrogram'][0].value_mapper.range range_obj.high = 5 range_obj.low = 0.0 spectrogram_plot.title = 'Spectrogram' obj.spectrogram_plot = spectrogram_plot return obj.spectrum_plot, obj.time_plot, obj.spectrogram_plot _stream = None def get_audio_data(): global _stream if _stream is None: # The audio stream is opened the first time this function gets called. # The stream is always closed (if it was opened) in a try finally # block at the end of this file, pa = pyaudio.PyAudio() _stream = pa.open(format=pyaudio.paInt16, channels=1, rate=SAMPLING_RATE, input=True, frames_per_buffer=NUM_SAMPLES) audio_data = fromstring(_stream.read(NUM_SAMPLES), dtype=short) normalized_data = audio_data / 32768.0 return (abs(fft(normalized_data))[:NUM_SAMPLES/2], normalized_data) class TimerController(HasTraits): interactor = Any() timer_id = Any() def on_timer(self, vtk_obj=None, eventname=""): try: spectrum, time = get_audio_data() except IOError: return self.spectrum_data.set_data('amplitude', spectrum) self.time_data.set_data('amplitude', time) spectrogram_data = self.spectrogram_plotdata.get_data('imagedata') spectrogram_data = hstack((spectrogram_data[:,1:], transpose([spectrum]))) self.spectrogram_plotdata.set_data('imagedata', spectrogram_data) self.spectrum_plot.request_redraw() return def main(): from tvtk.api import tvtk from mayavi import mlab from enable.vtk_backend.vtk_window import EnableVTKWindow f = mlab.figure(size=(900,850)) m = mlab.test_mesh() scene = mlab.gcf().scene render_window = scene.render_window renderer = scene.renderer rwi = scene.interactor # Create the plot timer_controller = TimerController() plots = create_plot_component(timer_controller) specplot, timeplot, spectrogram = plots for i, p in enumerate(plots): p.set(resizable = "", bounds = [200,200], outer_x = 0, bgcolor = "transparent", ) p.outer_y = i*250 p.tools.append(MoveTool(p, drag_button="right")) p.tools.append(PanTool(p)) p.tools.append(ZoomTool(p)) spectrogram.tools[-1].set(tool_mode="range", axis="value") spectrogram.tools[-2].set(constrain=True, constrain_direction="y") container = OverlayPlotContainer(bgcolor = "transparent", fit_window = True) container.add(*plots) container.timer_callback = timer_controller.on_timer window = EnableVTKWindow(rwi, renderer, component = container, istyle_class = tvtk.InteractorStyleTrackballCamera, bgcolor = "transparent", event_passthrough = True, ) mlab.show() if __name__ == "__main__": main() chaco-4.1.0/examples/demo/aspect_ratio.py0000644000175100001440000000664511674464170021370 0ustar ischnellusers00000000000000""" Controlling aspect ratio Demonstrates various ways that Chaco can control aspect ratios in plots. Left-drag pans the plot. Mousewheel up and down zooms the plot in and out. """ # Major library imports from itertools import chain from numpy import sort, isfinite from numpy.random import random # Enthought library imports from enable.api import ComponentEditor from traits.api import Any, Bool, BaseFloat, HasTraits from traitsui.api import Item, HGroup, VGroup, View # Chaco imports from chaco.api import ArrayPlotData, Plot from chaco.tools.api import PanTool, ZoomTool class AspectRatio(BaseFloat): "A new Trait for defining aspect ratios" default_value = 1.0 info_text = "a nonzero floating point number" def validate(self, object, name, value): value = super(AspectRatio, self).validate(object, name, value) if value != 0.0 and isfinite(value): return value else: self.error(object, name, value) class MyPlot(HasTraits): plot = Any() screen_enabled = Bool(False) screen_aspect = AspectRatio() fixed_x = Bool(False) fixed_y = Bool(False) traits_view = View( VGroup( HGroup( Item("screen_enabled", label="Screen"), Item("screen_aspect", label="aspect ratio (w/h)") ), HGroup( Item("fixed_x", label="Data X fixed"), Item("fixed_y", label="Data Y fixed") ), Item("plot", editor=ComponentEditor(size=(100,100)), show_label=False) ), width=600, height=600, resizable=True, title="Aspect Ratio Example") def __init__(self, *args, **kw): HasTraits.__init__(self, *args, **kw) numpoints = 200 plotdata = ArrayPlotData(x=sort(random(numpoints)), y=random(numpoints)) plot = Plot(plotdata) plot.plot(("x", "y"), type="scatter") plot.tools.append(PanTool(plot)) plot.overlays.append(ZoomTool(plot)) self.plot = plot def _screen_enabled_changed(self): if self.screen_enabled: self.plot.aspect_ratio = self.screen_aspect else: self.plot.aspect_ratio = None self.plot.request_redraw() def _screen_aspect_changed(self): if self.screen_enabled: self.plot.aspect_ratio = self.screen_aspect self.plot.request_redraw() def _fixed_x_changed(self): self.plot.x_mapper.stretch_data = not self.fixed_x # Also have to change all the renderers' mappers for renderer in chain(*self.plot.plots.values()): renderer.index_mapper.stretch_data = not self.fixed_x self.plot.request_redraw() def _fixed_y_changed(self): self.plot.y_mapper.stretch_data = not self.fixed_y for renderer in chain(*self.plot.plots.values()): renderer.value_mapper.stretch_data = not self.fixed_y self.plot.request_redraw() #=============================================================================== # # Create the demo object to be used by the demo.py application. #=============================================================================== demo = myplot = MyPlot() if __name__ == "__main__": myplot.configure_traits()chaco-4.1.0/examples/demo/zoomed_plot/0000755000175100001440000000000011674464170020661 5ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/zoomed_plot/grid_plot_factory.py0000644000175100001440000001320311674464170024744 0ustar ischnellusers00000000000000 # Local relative imports from chaco.api import ArrayDataSource, DataRange1D, LinearMapper, LinePlot, \ ScatterPlot, PlotAxis, PlotGrid def create_gridded_line_plot(x, y, orientation="h", color="red", width=1.0, dash="solid", value_mapper_class=LinearMapper, padding=30): assert len(x) == len(y) # If you know it is monotonically increasing, sort_order can # be set to 'ascending' index = ArrayDataSource(x,sort_order='none') value = ArrayDataSource(y, sort_order="none") index_range = DataRange1D(tight_bounds = False) index_range.add(index) index_mapper = LinearMapper(range=index_range) value_range = DataRange1D(tight_bounds = False) value_range.add(value) value_mapper = value_mapper_class(range=value_range) plot = LinePlot(index=index, value=value, index_mapper = index_mapper, value_mapper = value_mapper, orientation = orientation, color = color, line_width = width, line_style = dash, padding = [40, 15, 15, 20], # left, right, top, bottom border_visible = True, border_width = 1, bgcolor = "white", use_backbuffer = True, backbuffer_padding = False, unified_draw = True, draw_layer = "plot", overlay_border = True) vertical_grid = PlotGrid(component = plot, mapper=index_mapper, orientation='vertical', line_color="gray", line_style='dot', use_draw_order = True) horizontal_grid = PlotGrid(component = plot, mapper=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='Time (s)', 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) return plot def create_gridded_scatter_plot(x, y, orientation="h", color="red", width=1.0, fill_color="red", marker="square", marker_size=2, value_mapper_class=LinearMapper, padding=30): assert len(x) == len(y) # If you know it is monotonically increasing, sort_order can # be set to 'ascending' index = ArrayDataSource(x,sort_order='none') value = ArrayDataSource(y, sort_order="none") index_range = DataRange1D(tight_bounds = False) index_range.add(index) index_mapper = LinearMapper(range=index_range) value_range = DataRange1D(tight_bounds = False) value_range.add(value) value_mapper = value_mapper_class(range=value_range) plot = ScatterPlot(index=index, value=value, index_mapper = index_mapper, value_mapper = value_mapper, orientation = orientation, color = color, fill_color=fill_color, marker=marker, marker_size=marker_size, padding = [40, 15, 15, 20], # left, right, top, bottom border_visible = True, border_width = 1, bgcolor = "white", use_backbuffer = True, backbuffer_padding = False, unified_draw = True, draw_layer = "plot", overlay_border = True) vertical_grid = PlotGrid(component = plot, mapper=index_mapper, orientation='vertical', line_color="gray", line_style='dot', use_draw_order = True) horizontal_grid = PlotGrid(component = plot, mapper=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='Time (s)', 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) return plot chaco-4.1.0/examples/demo/zoomed_plot/zoom_overlay.py0000644000175100001440000000772411674464170023772 0ustar ischnellusers00000000000000 from __future__ import with_statement from numpy import array, amax, amin from enable.api import ColorTrait, Component from traits.api import Float, Instance, Int from chaco.api import AbstractOverlay, BaseXYPlot class ZoomOverlay(AbstractOverlay): """ Draws a trapezoidal selection overlay from the source plot to the destination plot. Assumes that the source plot lies above the destination plot. """ source = Instance(BaseXYPlot) destination = Instance(Component) border_color = ColorTrait((0, 0, 0.7, 1)) border_width = Int(1) fill_color = ColorTrait("dodgerblue") alpha = Float(0.3) def calculate_points(self, component): """ Calculate the overlay polygon based on the selection and the location of the source and destination plots. """ # find selection range on source plot x_start, x_end = self._get_selection_screencoords() if x_start > x_end: x_start, x_end = x_end, x_start y_end = self.source.y y_start = self.source.y2 left_top = array([x_start, y_start]) left_mid = array([x_start, y_end]) right_top = array([x_end, y_start]) right_mid = array([x_end, y_end]) # Offset y because we want to avoid overlapping the trapezoid with the topmost # pixels of the destination plot. y = self.destination.y2 + 1 left_end = array([self.destination.x, y]) right_end = array([self.destination.x2, y]) polygon = array((left_top, left_mid, left_end, right_end,right_mid, right_top)) left_line = array((left_top, left_mid, left_end)) right_line = array((right_end,right_mid, right_top)) return left_line, right_line, polygon def overlay(self, component, gc, view_bounds=None, mode="normal"): """ Draws this overlay onto 'component', rendering onto 'gc'. """ tmp = self._get_selection_screencoords() if tmp is None: return left_line, right_line, polygon = self.calculate_points(component) with gc: gc.translate_ctm(*component.position) gc.set_alpha(self.alpha) gc.set_fill_color(self.fill_color_) gc.set_line_width(self.border_width) gc.set_stroke_color(self.border_color_) gc.begin_path() gc.lines(polygon) gc.fill_path() gc.begin_path() gc.lines(left_line) gc.lines(right_line) gc.stroke_path() return def _get_selection_screencoords(self): """ Returns a tuple of (x1, x2) screen space coordinates of the start and end selection points. If there is no current selection, then returns None. """ selection = self.source.index.metadata["selections"] if selection is not None and len(selection) == 2: mapper = self.source.index_mapper return mapper.map_screen(array(selection)) else: return None #------------------------------------------------------------------------ # Trait event handlers #------------------------------------------------------------------------ def _source_changed(self, old, new): if old is not None and old.controller is not None: old.controller.on_trait_change(self._selection_update_handler, "selection", remove=True) if new is not None and new.controller is not None: new.controller.on_trait_change(self._selection_update_handler, "selection") return def _selection_update_handler(self, value): if value is not None and self.destination is not None: r = self.destination.index_mapper.range start, end = amin(value), amax(value) r.low = start r.high = end self.source.request_redraw() self.destination.request_redraw() return chaco-4.1.0/examples/demo/zoomed_plot/wav_to_numeric.py0000644000175100001440000000212711674464170024256 0ustar ischnellusers00000000000000#! /bin/env python # Standard library imports import os.path import wave import numpy # Enthought library imports from traits.util.resource import find_resource def wav_to_numeric( fname, max_frames=-1 ): f = wave.open( fname, 'rb' ) sampleRate = f.getframerate() channels = f.getnchannels() if max_frames < 0: max_frames = f.getnframes() frames = f.readframes(max_frames) if f.getsampwidth() == 2: data = numpy.fromstring(frames, numpy.uint16).astype(numpy.float64) - (2**15 - 0.5) else: data = numpy.fromstring(frames, numpy.uint8).astype(numpy.float64) - 127.5 if channels == 2: left = data[0::2] right = data[1::2] data = left index = numpy.arange(len(data)) * 1.0/sampleRate return index, data def test(): 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) index, data = wav_to_numeric(fname) print data[:100] return index, data if __name__== '__main__': test() chaco-4.1.0/examples/demo/zoomed_plot/zoom_plot.py0000644000175100001440000001372511674464170023265 0ustar ischnellusers00000000000000""" 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 # 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) data = ArrayPlotData(x=x, y=y) return data def _plot_default(self): plotter = Plot(data=self.data) main_plot = plotter.plot(['x','y'])[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--- chaco-4.1.0/examples/demo/zoomed_plot/__init__.py0000644000175100001440000000000011674464170022760 0ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/scales_test.py0000644000175100001440000001475511674464170021225 0ustar ischnellusers00000000000000#!/usr/bin/env python """ Draws several overlapping line plots. 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". Right-click and dragging on the legend allows you to reposition the legend. Double-clicking on line or scatter plots brings up a traits editor for the plot. """ # Major library imports from numpy import linspace from scipy.special import jn from time import time from chaco.example_support import COLOR_PALETTE # Enthought library imports from enable.api import Component, ComponentEditor from traits.api import HasTraits, Instance from traitsui.api import Item, Group, View # Chaco imports from chaco.api import create_line_plot, OverlayPlotContainer, PlotLabel, \ create_scatter_plot, Legend, PlotGrid from chaco.tools.api import PanTool, ZoomTool, \ LegendTool, TraitsTool from chaco.scales.api import CalendarScaleSystem from chaco.scales_tick_generator import ScalesTickGenerator from chaco.axis import PlotAxis #=============================================================================== # # Create the Chaco plot. #=============================================================================== def add_default_axes(plot, orientation="normal", vtitle="",htitle=""): """ Creates left and bottom axes for a plot. Assumes that the index is horizontal and value is vertical by default; set orientation to something other than "normal" if they are flipped. """ if orientation in ("normal", "h"): v_mapper = plot.value_mapper h_mapper = plot.index_mapper else: v_mapper = plot.index_mapper h_mapper = plot.value_mapper left = PlotAxis(orientation='left', title= vtitle, mapper=v_mapper, component=plot) bottom = PlotAxis(orientation='bottom', title= htitle, mapper=h_mapper, component=plot) plot.underlays.append(left) plot.underlays.append(bottom) return left, bottom def add_default_grids(plot, orientation="normal", tick_gen=None): """ Creates horizontal and vertical gridlines for a plot. Assumes that the index is horizontal and value is vertical by default; set orientation to something other than "normal" if they are flipped. """ if orientation in ("normal", "h"): v_mapper = plot.index_mapper h_mapper = plot.value_mapper else: v_mapper = plot.value_mapper h_mapper = plot.index_mapper vgrid = PlotGrid(mapper=v_mapper, orientation='vertical', component=plot, line_color="lightgray", line_style="dot", tick_generator = tick_gen) hgrid = PlotGrid(mapper=h_mapper, orientation='horizontal', component=plot, line_color="lightgray", line_style="dot", tick_generator = ScalesTickGenerator()) plot.underlays.append(vgrid) plot.underlays.append(hgrid) return hgrid, vgrid def _create_plot_component(): container = OverlayPlotContainer(padding = 50, fill_padding = True, bgcolor = "lightgray", use_backbuffer=True) # Create the initial X-series of data numpoints = 100 low = -5 high = 15.0 x = linspace(low, high, numpoints) now = time() timex = linspace(now, now+7*24*3600, numpoints) # Plot some bessel functions value_mapper = None index_mapper = None plots = {} for i in range(10): y = jn(i, x) if i%2 == 1: plot = create_line_plot((timex,y), color=tuple(COLOR_PALETTE[i]), width=2.0) plot.index.sort_order = "ascending" else: plot = create_scatter_plot((timex,y), color=tuple(COLOR_PALETTE[i])) plot.bgcolor = "white" plot.border_visible = True if i == 0: value_mapper = plot.value_mapper index_mapper = plot.index_mapper left, bottom = add_default_axes(plot) left.tick_generator = ScalesTickGenerator() bottom.tick_generator = ScalesTickGenerator(scale=CalendarScaleSystem()) add_default_grids(plot, tick_gen=bottom.tick_generator) else: plot.value_mapper = value_mapper value_mapper.range.add(plot.value) plot.index_mapper = index_mapper index_mapper.range.add(plot.index) if i==0: plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Add a legend in the upper right corner, and make it relocatable legend = Legend(component=plot, padding=10, align="ur") legend.tools.append(LegendTool(legend, drag_button="right")) plot.overlays.append(legend) container.add(plot) plots["Bessel j_%d"%i] = plot # Set the list of plots on the legend legend.plots = plots # Add the title at the top container.overlays.append(PlotLabel("Bessel functions", component=container, font = "swiss 16", overlay_position="top")) # Add the traits inspector tool to the container container.tools.append(TraitsTool(container)) return container #=============================================================================== # Attributes to use for the plot view. size=(800,700) title="Simple line plot" #=============================================================================== # # Demo class that is used by the demo.py application. #=============================================================================== class Demo(HasTraits): plot = Instance(Component) traits_view = View( Group( Item('plot', editor=ComponentEditor(size=size), show_label=False), orientation = "vertical"), resizable=True, title=title, width=size[0], height=size[1] ) def _plot_default(self): return _create_plot_component() demo = Demo() if __name__ == "__main__": demo.configure_traits() #--EOF--- chaco-4.1.0/examples/demo/multiaxis_using_Plot.py0000644000175100001440000000614111674464170023124 0ustar ischnellusers00000000000000#!/usr/bin/env python """ Draws some x-y line and scatter plots. On the left hand plot: - 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". """ # Major library imports from numpy import linspace from scipy.special import jn from chaco.example_support import COLOR_PALETTE # Enthought library imports from enable.api import Component, ComponentEditor from traits.api import HasTraits, Instance from traitsui.api import Item, Group, View # Chaco imports from chaco.api import ArrayPlotData, Plot from chaco.tools.api import BroadcasterTool, PanTool, ZoomTool from chaco.api import create_line_plot, add_default_axes #=============================================================================== # # Create the Chaco plot. #=============================================================================== def _create_plot_component(): # Create some x-y data series to plot x = linspace(-2.0, 10.0, 100) pd = ArrayPlotData(index = x) for i in range(5): pd.set_data("y" + str(i), jn(i,x)) # Create some line plots of some of the data plot1 = Plot(pd) plot1.plot(("index", "y0", "y1", "y2"), name="j_n, n<3", color="red") # Tweak some of the plot properties plot1.title = "My First Line Plot" plot1.padding = 50 plot1.padding_top = 75 plot1.legend.visible = True x = linspace(-5, 15.0, 100) y = jn(5, x) foreign_plot = create_line_plot((x,y), color=tuple(COLOR_PALETTE[0]), width=2.0) left, bottom = add_default_axes(foreign_plot) left.orientation = "right" bottom.orientation = "top" plot1.add(foreign_plot) # Attach some tools to the plot broadcaster = BroadcasterTool() broadcaster.tools.append(PanTool(plot1)) broadcaster.tools.append(PanTool(foreign_plot)) for c in (plot1, foreign_plot): zoom = ZoomTool(component=c, tool_mode="box", always_on=False) broadcaster.tools.append(zoom) plot1.tools.append(broadcaster) return plot1 #=============================================================================== # Attributes to use for the plot view. size=(900,500) title="Multi-Y plot" #=============================================================================== # # Demo class that is used by the demo.py application. #=============================================================================== class Demo(HasTraits): plot = Instance(Component) traits_view = View( Group( Item('plot', editor=ComponentEditor(size=size), show_label=False), orientation = "vertical"), resizable=True, title=title, width=size[0], height=size[1] ) def _plot_default(self): return _create_plot_component() demo = Demo() if __name__ == "__main__": demo.configure_traits() #--EOF--- chaco-4.1.0/examples/demo/logo.py0000644000175100001440000000621211674464170017641 0ustar ischnellusers00000000000000""" LOGO overlay """ from __future__ import with_statement from numpy import array, cos, invert, isnan, nan, pi, sin, vstack from traits.api import Array, Enum, Float, Range from traitsui.api import Group, Item, View from enable.api import ColorTrait from chaco.api import arg_find_runs, AbstractOverlay class Turtle(AbstractOverlay): x = Float y = Float angle = Range(0.0, 360.0, value=90.0) # degrees, clockwise color = ColorTrait("blue") line_color = ColorTrait("green") size = Float(10.0) path = Array _pen = Enum("down", "up") view = View(Group("x", "y", "angle", Item("color", style="custom"), Item("line_color", style="custom"), "size", orientation="vertical")) def __init__(self, component=None, **traits): super(Turtle, self).__init__(component=component, **traits) if 'path' not in traits: self.path = array([self.x, self.y], ndmin=2) def overlay(self, other_component, gc, view_bounds=None, mode="normal"): self.render(gc, other_component) def render_turtle(self, gc, component): with gc: x, y = component.map_screen(array([self.x, self.y], ndmin=2))[0] gc.translate_ctm(x, y) angle = self.angle * pi / 180.0 gc.rotate_ctm(angle) gc.set_stroke_color(self.color_) gc.set_fill_color(self.color_) gc.begin_path() gc.lines([[-0.707*self.size, 0.707*self.size], [-0.707*self.size, -0.707*self.size], [self.size, 0.0]]) gc.fill_path() def render(self, gc, component): # Uses the component to map our path into screen space nan_mask = invert(isnan(self.path[:,0])).astype(int) blocks = [b for b in arg_find_runs(nan_mask, "flat") if nan_mask[b[0]] != 0] screen_pts = component.map_screen(self.path) with gc: gc.clip_to_rect(component.x, component.y, component.width, component.height) gc.set_stroke_color(self.line_color_) for start, end in blocks: gc.begin_path() gc.lines(screen_pts[start:end]) gc.stroke_path() self.render_turtle(gc, component) def pendown(self): self._pen = "down" self.path = vstack((self.path, [self.x, self.y])) def penup(self): self.path = vstack((self.path, [nan,nan])) self._pen = "up" def forward(self, amt): angle = self.angle * pi / 180.0 self.x += amt * cos(angle) self.y += amt * sin(angle) if self._pen == "down": self.path = vstack((self.path, [self.x, self.y])) def back(self, amt): self.forward(-amt) def left(self, angle): self.angle = (self.angle + angle) % 360 def right(self, angle): self.angle = ((self.angle - angle) + 360) % 360 def clear(self): self.path = array([self.x, self.y], ndmin=2) def reset(self): self.x = self.y = 0.0 self.angle = 90.0 self.clear() def _anytrait_changed(self, trait, val): self.component.request_redraw() chaco-4.1.0/examples/demo/multi_line_plot_demo.py0000644000175100001440000001127611674464170023112 0ustar ischnellusers00000000000000import numpy as np from traits.api import Instance, HasTraits, Range, Array from traitsui.api import View, Item, HGroup, VGroup, Group from enable.api import ComponentEditor from chaco.api import LinearMapper, Plot, ArrayDataSource, DataRange1D, PlotAxis from chaco.multi_array_data_source import MultiArrayDataSource from chaco.multi_line_plot import MultiLinePlot class DataModel(HasTraits): """This is the data to be plotted in the demo.""" # The x values of the data (1D numpy array). x_index = Array() # The channel numbers (1D numpy array). y_index = Array() # The data. The shape of this 2D array must be (y_index.size, x_index.size) data = Array() class MultiLinePlotDemo(HasTraits): """Demonstrates the MultiLinePlot. This demo assumes that 'model', an instance of DataModel containing the 2D data to be plotted, will be given to the constructor, and will not change later. """ model = Instance(DataModel) plot = Instance(Plot) multi_line_plot_renderer = Instance(MultiLinePlot) # Drives multi_line_plot_renderer.normalized_amplitude amplitude = Range(-1.5, 1.5, value=-0.5) # Drives multi_line_plot_renderer.offset offset = Range(-1.0, 1.0, value=0) traits_view = \ View( VGroup( Group( Item('plot', editor=ComponentEditor(), show_label=False), ), HGroup( Item('amplitude', springy=True), Item('offset', springy=True), springy=True, ), HGroup( Item('object.multi_line_plot_renderer.color', springy=True), Item('object.multi_line_plot_renderer.line_style', springy=True), springy=True, ), ), width=800, height=500, resizable=True, ) #----------------------------------------------------------------------- # Trait defaults #----------------------------------------------------------------------- def _multi_line_plot_renderer_default(self): """Create the default MultiLinePlot instance.""" xs = ArrayDataSource(self.model.x_index, sort_order='ascending') xrange = DataRange1D() xrange.add(xs) ys = ArrayDataSource(self.model.y_index, sort_order='ascending') yrange = DataRange1D() yrange.add(ys) # The data source for the MultiLinePlot. ds = MultiArrayDataSource(data=self.model.data) multi_line_plot_renderer = \ MultiLinePlot( index = xs, yindex = ys, index_mapper = LinearMapper(range=xrange), value_mapper = LinearMapper(range=yrange), value=ds, global_max = self.model.data.max(), global_min = self.model.data.min()) return multi_line_plot_renderer def _plot_default(self): """Create the Plot instance.""" plot = Plot(title="MultiLinePlot Demo") plot.add(self.multi_line_plot_renderer) x_axis = PlotAxis(component=plot, mapper=self.multi_line_plot_renderer.index_mapper, orientation='bottom', title='t (seconds)') y_axis = PlotAxis(component=plot, mapper=self.multi_line_plot_renderer.value_mapper, orientation='left', title='channel') plot.overlays.extend([x_axis, y_axis]) return plot #----------------------------------------------------------------------- # Trait change handlers #----------------------------------------------------------------------- def _amplitude_changed(self, amp): self.multi_line_plot_renderer.normalized_amplitude = amp def _offset_changed(self, off): self.multi_line_plot_renderer.offset = off # FIXME: The change does not trigger a redraw. Force a redraw by # faking an amplitude change. self.multi_line_plot_renderer._amplitude_changed() if __name__ == "__main__": # Sample rate. fs = 500 # Total time. T = 5.0 num_samples = fs * T t = np.arange(num_samples) / fs channels = np.arange(12) # Frequencies of the sine functions in each channel. freqs = 3*(channels[:,None] + 1) y = np.sin(freqs * t) # Create an instance of DataModel. This is the data to # be plotted with a MultiLinePlot. data = DataModel(x_index=t, y_index=channels, data=y) # Create the demo class, and show it. demo = MultiLinePlotDemo(model=data) demo.configure_traits() chaco-4.1.0/examples/demo/toolbar_plot.py0000644000175100001440000000272511674464170021406 0ustar ischnellusers00000000000000"""Toolbar Plot A toolbar plot is the same as a regular Plot, but also provides a usually hidden drop-down toolbar with configurable buttons. The toolbar appears when the mouse hovers over the top of the plot area. This toolbar provides buttons for X log scale, Y log scale, Save as, Copy image, Copy data, and Zoom reset. """ import numpy from chaco.plot import Plot, ArrayPlotData from chaco.api import ToolbarPlot from enable.api import ComponentEditor from traits.api import Instance, HasTraits from traitsui.api import View, Item class ExamplePlotApp(HasTraits): plot = Instance(Plot) traits_view = View(Item('plot', editor=ComponentEditor(), width = 600, height = 600, show_label=False), resizable=True) def __init__(self, index, series1, series2, **kw): super(ExamplePlotApp, self).__init__(**kw) plot_data = ArrayPlotData(index=index) plot_data.set_data('series1', series1) plot_data.set_data('series2', series2) self.plot = ToolbarPlot(plot_data) self.plot.plot(('index', 'series1'), color='auto') self.plot.plot(('index', 'series2'), color='auto') index = numpy.arange(1.0, 10., 0.01) series1 = (100.0 + index) / (100.0 - 20*index**2 + 5.0*index**4) series2 = (100.0 + index) / (100.0 - 20*index**2 + 5.0*index**3) demo = ExamplePlotApp(index, series1, series2) if __name__== '__main__': demo.configure_traits() chaco-4.1.0/examples/demo/advanced/0000755000175100001440000000000011674464170020073 5ustar ischnellusers00000000000000chaco-4.1.0/examples/demo/advanced/scalar_image_function_inspector_old.py0000644000175100001440000004322211674464170027710 0ustar ischnellusers00000000000000""" Renders a colormapped image of a scalar value field, and a cross section chosen by a line interactor. """ # Standard library imports from optparse import OptionParser import sys # Major library imports from numpy import array, linspace, meshgrid, nanmin, nanmax, pi, zeros # Enthought library imports from chaco.api import ArrayDataSource, ArrayPlotData, ColorBar, ContourLinePlot, \ ColormappedScatterPlot, CMapImagePlot, \ ContourPolyPlot, DataRange1D, VPlotContainer, \ DataRange2D, GridMapper, GridDataSource, \ HPlotContainer, ImageData, LinearMapper, \ LinePlot, OverlayPlotContainer, Plot, PlotAxis from chaco.default_colormaps import * from enable.component_editor import ComponentEditor from chaco.tools.api import LineInspector, PanTool, RangeSelection, \ RangeSelectionOverlay, ZoomTool from enable.api import Window from traits.api import Any, Array, Callable, CFloat, CInt, Enum, Event, Float, HasTraits, \ Int, Instance, Str, Trait, on_trait_change from traitsui.api import Group, Handler, HGroup, Item, View from traitsui.menu import Action, CloseAction, Menu, \ MenuBar, NoButtons, Separator class Model(HasTraits): #Traits view definitions: traits_view = View( Group(Item('function'), HGroup(Item('npts_x', label="Number X Points"), Item('npts_y', label="Number Y Points")), HGroup(Item('min_x', label="Min X value"), Item('max_x', label="Max X value")), HGroup(Item('min_y', label="Min Y value"), Item('max_y', label="Max Y value"))), buttons=["OK", "Cancel"]) function = Str("tanh(x**2+y)*cos(y)*jn(0,x+y*2)") npts_x = CInt(400) npts_y = CInt(200) min_x = CFloat(-2*pi) max_x = CFloat(2*pi) min_y = CFloat(-1.5*pi) max_y = CFloat(1.5*pi) xs = Array ys = Array zs = Array minz = Float maxz = Float model_changed = Event def __init__(self, *args, **kwargs): super(Model, self).__init__(*args, **kwargs) self.compute_model() def compute_model(self): # The xs and ys used for the image plot range need to be the # edges of the cells. self.xs = linspace(self.min_x, self.max_x, self.npts_x+1) self.ys = linspace(self.min_y, self.max_y, self.npts_y+1) # The grid of points at which we will evaluate the 2D function # is located at cell centers, so use halfsteps from the # min/max values (which are edges) xstep = (self.max_x - self.min_x) / self.npts_x ystep = (self.max_y - self.min_y) / self.npts_y gridx = linspace(self.min_x+xstep/2, self.max_x-xstep/2, self.npts_x) gridy = linspace(self.min_y+xstep/2, self.max_y-xstep/2, self.npts_y) x, y = meshgrid(gridx, gridy) try: d = dict(x=x, y=y) exec "from scipy import *" in d exec "from scipy.special import *" in d self.zs = eval(self.function, d) self.minz = nanmin(self.zs) self.maxz = nanmax(self.zs) self.model_changed = True self._function = self.function except: self.set(function = self._function, trait_change_notify=False) def _anytrait_changed(self, name, value): if name in ['function', 'npts_x', 'npts_y', 'min_x', 'max_x', 'min_y', 'max_y']: self.compute_model() class PlotUI(HasTraits): #Traits view definitions: traits_view = View( Group(Item('container', editor=ComponentEditor(size=(800,600)), show_label=False)), buttons=NoButtons, resizable=True) plot_edit_view = View( Group(Item('num_levels'), Item('colormap')), buttons=["OK","Cancel"]) num_levels = Int(15) colormap = Enum(color_map_name_dict.keys()) #--------------------------------------------------------------------------- # Private Traits #--------------------------------------------------------------------------- _image_index = Instance(GridDataSource) _image_value = Instance(ImageData) _cmap = Trait(jet, Callable) #--------------------------------------------------------------------------- # Public View interface #--------------------------------------------------------------------------- def __init__(self, *args, **kwargs): super(PlotUI, self).__init__(*args, **kwargs) self.create_plot() def create_plot(self): # Create the mapper, etc self._image_index = GridDataSource(array([]), array([]), sort_order=("ascending","ascending")) image_index_range = DataRange2D(self._image_index) self._image_index.on_trait_change(self._metadata_changed, "metadata_changed") self._image_value = ImageData(data=array([]), value_depth=1) image_value_range = DataRange1D(self._image_value) # Create the contour plots self.polyplot = ContourPolyPlot(index=self._image_index, value=self._image_value, index_mapper=GridMapper(range= image_index_range), color_mapper=\ self._cmap(image_value_range), levels=self.num_levels) self.lineplot = ContourLinePlot(index=self._image_index, value=self._image_value, index_mapper=GridMapper(range= self.polyplot.index_mapper.range), levels=self.num_levels) # Add a left axis to the plot left = PlotAxis(orientation='left', title= "y", mapper=self.polyplot.index_mapper._ymapper, component=self.polyplot) self.polyplot.overlays.append(left) # Add a bottom axis to the plot bottom = PlotAxis(orientation='bottom', title= "x", mapper=self.polyplot.index_mapper._xmapper, component=self.polyplot) self.polyplot.overlays.append(bottom) # Add some tools to the plot self.polyplot.tools.append(PanTool(self.polyplot, constrain_key="shift")) self.polyplot.overlays.append(ZoomTool(component=self.polyplot, tool_mode="box", always_on=False)) self.polyplot.overlays.append(LineInspector(component=self.polyplot, axis='index_x', inspect_mode="indexed", write_metadata=True, is_listener=False, color="white")) self.polyplot.overlays.append(LineInspector(component=self.polyplot, axis='index_y', inspect_mode="indexed", write_metadata=True, color="white", is_listener=False)) # Add these two plots to one container contour_container = OverlayPlotContainer(padding=20, use_backbuffer=True, unified_draw=True) contour_container.add(self.polyplot) contour_container.add(self.lineplot) # Create a colorbar cbar_index_mapper = LinearMapper(range=image_value_range) self.colorbar = ColorBar(index_mapper=cbar_index_mapper, plot=self.polyplot, padding_top=self.polyplot.padding_top, padding_bottom=self.polyplot.padding_bottom, padding_right=40, resizable='v', width=30) self.pd = ArrayPlotData(line_index = array([]), line_value = array([]), scatter_index = array([]), scatter_value = array([]), scatter_color = array([])) self.cross_plot = Plot(self.pd, resizable="h") self.cross_plot.height = 100 self.cross_plot.padding = 20 self.cross_plot.plot(("line_index", "line_value"), line_style="dot") self.cross_plot.plot(("scatter_index","scatter_value","scatter_color"), type="cmap_scatter", name="dot", color_mapper=self._cmap(image_value_range), marker="circle", marker_size=8) self.cross_plot.index_range = self.polyplot.index_range.x_range self.pd.set_data("line_index2", array([])) self.pd.set_data("line_value2", array([])) self.pd.set_data("scatter_index2", array([])) self.pd.set_data("scatter_value2", array([])) self.pd.set_data("scatter_color2", array([])) self.cross_plot2 = Plot(self.pd, width = 140, orientation="v", resizable="v", padding=20, padding_bottom=160) self.cross_plot2.plot(("line_index2", "line_value2"), line_style="dot") self.cross_plot2.plot(("scatter_index2","scatter_value2","scatter_color2"), type="cmap_scatter", name="dot", color_mapper=self._cmap(image_value_range), marker="circle", marker_size=8) self.cross_plot2.index_range = self.polyplot.index_range.y_range # Create a container and add components self.container = HPlotContainer(padding=40, fill_padding=True, bgcolor = "white", use_backbuffer=False) inner_cont = VPlotContainer(padding=0, use_backbuffer=True) inner_cont.add(self.cross_plot) inner_cont.add(contour_container) self.container.add(self.colorbar) self.container.add(inner_cont) self.container.add(self.cross_plot2) def update(self, model): self.minz = model.minz self.maxz = model.maxz self.colorbar.index_mapper.range.low = self.minz self.colorbar.index_mapper.range.high = self.maxz self._image_index.set_data(model.xs, model.ys) self._image_value.data = model.zs self.pd.set_data("line_index", model.xs) self.pd.set_data("line_index2", model.ys) self.container.invalidate_draw() self.container.request_redraw() #--------------------------------------------------------------------------- # Event handlers #--------------------------------------------------------------------------- def _metadata_changed(self, old, new): """ This function takes out a cross section from the image data, based on the line inspector selections, and updates the line and scatter plots.""" self.cross_plot.value_range.low = self.minz self.cross_plot.value_range.high = self.maxz self.cross_plot2.value_range.low = self.minz self.cross_plot2.value_range.high = self.maxz if self._image_index.metadata.has_key("selections"): x_ndx, y_ndx = self._image_index.metadata["selections"] if y_ndx and x_ndx: self.pd.set_data("line_value", self._image_value.data[y_ndx,:]) self.pd.set_data("line_value2", self._image_value.data[:,x_ndx]) xdata, ydata = self._image_index.get_data() xdata, ydata = xdata.get_data(), ydata.get_data() self.pd.set_data("scatter_index", array([xdata[x_ndx]])) self.pd.set_data("scatter_index2", array([ydata[y_ndx]])) self.pd.set_data("scatter_value", array([self._image_value.data[y_ndx, x_ndx]])) self.pd.set_data("scatter_value2", array([self._image_value.data[y_ndx, x_ndx]])) self.pd.set_data("scatter_color", array([self._image_value.data[y_ndx, x_ndx]])) self.pd.set_data("scatter_color2", array([self._image_value.data[y_ndx, x_ndx]])) else: self.pd.set_data("scatter_value", array([])) self.pd.set_data("scatter_value2", array([])) self.pd.set_data("line_value", array([])) self.pd.set_data("line_value2", array([])) def _colormap_changed(self): self._cmap = color_map_name_dict[self.colormap] if hasattr(self, "polyplot"): value_range = self.polyplot.color_mapper.range self.polyplot.color_mapper = self._cmap(value_range) value_range = self.cross_plot.color_mapper.range self.cross_plot.color_mapper = self._cmap(value_range) # FIXME: change when we decide how best to update plots using # the shared colormap in plot object self.cross_plot.plots["dot"][0].color_mapper = self._cmap(value_range) self.cross_plot2.plots["dot"][0].color_mapper = self._cmap(value_range) self.container.request_redraw() def _num_levels_changed(self): if self.num_levels > 3: self.polyplot.levels = self.num_levels self.lineplot.levels = self.num_levels class Controller(Handler): #--------------------------------------------------------------------------- # State traits #--------------------------------------------------------------------------- model = Instance(Model) view = Instance(PlotUI) #--------------------------------------------------------------------------- # Handler interface #--------------------------------------------------------------------------- def init(self, info): self.model = info.object.model self.view = info.object.view self.model.on_trait_change(self._model_changed, "model_changed") #--------------------------------------------------------------------------- # Public Controller interface #--------------------------------------------------------------------------- def edit_model(self, ui_info): self.model.configure_traits() def edit_plot(self, ui_info): self.view.configure_traits(view="plot_edit_view") #--------------------------------------------------------------------------- # Private Controller interface #--------------------------------------------------------------------------- def _model_changed(self): if self.view is not None: self.view.update(self.model) class ModelView(HasTraits): model = Instance(Model) view = Instance(PlotUI) traits_view = View(Item('@view', show_label=False), menubar=MenuBar(Menu(Action(name="Edit Model", action="edit_model"), Action(name="Edit Plot", action="edit_plot"), CloseAction, name="File")), handler = Controller, title = "Function Inspector", resizable=True) @on_trait_change('model, view') def update_view(self): if self.model is not None and self.view is not None: self.view.update(self.model) options_dict = {'colormap' : "jet", 'num_levels' : 15, 'function' : "tanh(x**2+y)*cos(y)*jn(0,x+y*2)"} model=Model(**options_dict) view=PlotUI(**options_dict) popup = ModelView(model=model, view=view) def show_plot(**kwargs): model = Model(**kwargs) view = PlotUI(**kwargs) modelview=ModelView(model=model, view=view) modelview.configure_traits() def main(argv=None): if argv is None: argv = sys.argv usage = "usage: %prog [options]" parser = OptionParser(usage=usage, version="%prog 1.0") parser.add_option("-c", "--colormap", action="store", type="string", dest="colormap", default="jet", metavar="CMAP", help="choose a default colormapper") parser.add_option("-n", "--nlevels", action="store", type="int", dest="num_levels", default=15, help="number countour levels to plot [default: %default]") parser.add_option("-f", "--function", action="store", type="string", dest="function", default="tanh(x**2+y)*cos(y)*jn(0,x+y*2)", help="function of x and y [default: %default]") opts, args = parser.parse_args(argv[1:]) if len(args) > 0: parser.error("Incorrect number of arguments") show_plot(colormap=opts.colormap, num_levels=opts.num_levels, function=opts.function) if __name__ == "__main__": sys.exit(main()) chaco-4.1.0/examples/demo/advanced/javascript_hover_tools.py0000644000175100001440000005202311674464170025240 0ustar ischnellusers00000000000000""" Demo of a javascript inspector tool that shows a black bar over the active value axis, as well as the values at the current index, with the numbers shown in the colors matching the legend. To Use ------ Run Python on this file which will generate six files, plot_hover_coords.html plot_hover_coords.png plot_hover2_coords.png hover_coords.js plot_hover_coords_png_hover_data.js plot_hover2_coords_png_hover_data.js Alternatively, if you pass in '-e' or '--embedded' on the command-line, then a single HTML file will be created that has all JavaScript and images directly embedded into it. The script should automatically load your webbrowser on the output file, but if it does not, then manually open the file hover_coords_plot.html in your browser to see the output. Author: Judah De Paula Date: November 21, 2008. """ # Standard library imports import os, sys, webbrowser, cStringIO from base64 import encodestring # Major library imports import Image from numpy import arange, searchsorted, where, array, vstack, linspace from scipy.special import jn # Chaco imports from chaco.api \ import ArrayPlotData, Plot, PlotGraphicsContext, LinePlot from chaco.example_support import COLOR_PALETTE #-- Constants ----------------------------------------------------------------- DPI = 72.0 #------------------------------------------------------------------------------ # File templates: # In a real application, these templates should be their own files, # and a real templating engine (ex. Mako) would make things more flexible. #------------------------------------------------------------------------------ html_template_keys = {'filename1' : 'plot_hover_coords.png', 'filename2' : 'plot_hover2_coords.png', 'file1_src' : 'plot_hover_coords.png', 'file2_src' : 'plot_hover2_coords.png', 'hover_coords' :'src="hover_coords.js">', 'data1' :'src="plot_hover_coords_png_hover_data.js">', 'data2' :'src="plot_hover2_coords_png_hover_data.js">' } # Turns into index.html. html_template = """ chaco-4.1.0/docs/chaco_talk_apr_2006/ui/default/slides.css0000644000175100001440000000035611674464170024157 0ustar ischnellusers00000000000000@import url(s5-core.css); /* required to make the slide show run at all */ @import url(framing.css); /* sets basic placement and size of slide components */ @import url(pretty.css); /* stuff that makes the slides look better than blah */chaco-4.1.0/docs/chaco_talk_apr_2006/ui/default/outline.css0000644000175100001440000000127011674464170024347 0ustar ischnellusers00000000000000/* don't change this unless you want the layout stuff to show up in the outline view! */ .layout div, #footer *, #controlForm * {display: none;} #footer, #controls, #controlForm, #navLinks, #toggle { display: block; visibility: visible; margin: 0; padding: 0;} #toggle {float: right; padding: 0.5em;} html>body #toggle {position: fixed; top: 0; right: 0;} /* making the outline look pretty-ish */ #slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} #slide0 h1 {padding-top: 1.5em;} .slide h1 {margin: 1.5em 0 0; padding-top: 0.25em; border-top: 1px solid #888; border-bottom: 1px solid #AAA;} #toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} chaco-4.1.0/docs/chaco_talk_apr_2006/ui/default/s5-core.css0000644000175100001440000000061211674464170024144 0ustar ischnellusers00000000000000/* Do not edit or override these styles! The system will likely break if you do. */ div#header, div#footer, div#controls, .slide {position: absolute;} html>body div#header, html>body div#footer, html>body div#controls, html>body .slide {position: fixed;} .handout {display: none;} .layout {display: block;} .slide, .hideme, .incremental {visibility: hidden;} #slide0 {visibility: visible;} chaco-4.1.0/docs/chaco_talk_apr_2006/ui/default/print.css0000644000175100001440000000167111674464170024031 0ustar ischnellusers00000000000000/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ .slide, ul {page-break-inside: avoid; visibility: visible !important;} h1 {page-break-after: avoid;} body {font-size: 12pt; background: white;} * {color: black;} #slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} #slide0 h3 {margin: 0; padding: 0;} #slide0 h4 {margin: 0 0 0.5em; padding: 0;} #slide0 {margin-bottom: 3em;} h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;} .extra {background: transparent !important;} div.extra, pre.extra, .example {font-size: 10pt; color: #333;} ul.extra a {font-weight: bold;} p.example {display: none;} #header {display: none;} #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} #footer h2, #controls {display: none;} /* The following rule keeps the layout stuff out of print. Remove at your own risk! */ .layout, .layout * {display: none !important;} chaco-4.1.0/docs/chaco_talk_apr_2006/ui/default/blank.gif0000644000175100001440000000006111674464170023731 0ustar ischnellusers00000000000000GIF89a!,T;chaco-4.1.0/docs/chaco_talk_apr_2006/ui/default/slides.js0000644000175100001440000003660611674464170024012 0ustar ischnellusers00000000000000// S5 v1.1 slides.js -- released into the Public Domain // // Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information // about all the wonderful and talented contributors to this code! var undef; var slideCSS = ''; var snum = 0; var smax = 1; var incpos = 0; var number = undef; var s5mode = true; var defaultView = 'slideshow'; var controlVis = 'visible'; var isIE = navigator.appName == 'Microsoft Internet Explorer' && navigator.userAgent.indexOf('Opera') < 1 ? 1 : 0; var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; function hasClass(object, className) { if (!object.className) return false; return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); } function hasValue(object, value) { if (!object) return false; return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); } function removeClass(object,className) { if (!object) return; object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); } function addClass(object,className) { if (!object || hasClass(object, className)) return; if (object.className) { object.className += ' '+className; } else { object.className = className; } } function GetElementsWithClassName(elementName,className) { var allElements = document.getElementsByTagName(elementName); var elemColl = new Array(); for (var i = 0; i< allElements.length; i++) { if (hasClass(allElements[i], className)) { elemColl[elemColl.length] = allElements[i]; } } return elemColl; } function isParentOrSelf(element, id) { if (element == null || element.nodeName=='BODY') return false; else if (element.id == id) return true; else return isParentOrSelf(element.parentNode, id); } function nodeValue(node) { var result = ""; if (node.nodeType == 1) { var children = node.childNodes; for (var i = 0; i < children.length; ++i) { result += nodeValue(children[i]); } } else if (node.nodeType == 3) { result = node.nodeValue; } return(result); } function slideLabel() { var slideColl = GetElementsWithClassName('*','slide'); var list = document.getElementById('jumplist'); smax = slideColl.length; for (var n = 0; n < smax; n++) { var obj = slideColl[n]; var did = 'slide' + n.toString(); obj.setAttribute('id',did); if (isOp) continue; var otext = ''; var menu = obj.firstChild; if (!menu) continue; // to cope with empty slides while (menu && menu.nodeType == 3) { menu = menu.nextSibling; } if (!menu) continue; // to cope with slides with only text nodes var menunodes = menu.childNodes; for (var o = 0; o < menunodes.length; o++) { otext += nodeValue(menunodes[o]); } list.options[list.length] = new Option(n + ' : ' + otext, n); } } function currentSlide() { var cs; if (document.getElementById) { cs = document.getElementById('currentSlide'); } else { cs = document.currentSlide; } cs.innerHTML = '' + snum + '<\/span> ' + '\/<\/span> ' + '' + (smax-1) + '<\/span>'; if (snum == 0) { cs.style.visibility = 'hidden'; } else { cs.style.visibility = 'visible'; } } function go(step) { if (document.getElementById('slideProj').disabled || step == 0) return; var jl = document.getElementById('jumplist'); var cid = 'slide' + snum; var ce = document.getElementById(cid); if (incrementals[snum].length > 0) { for (var i = 0; i < incrementals[snum].length; i++) { removeClass(incrementals[snum][i], 'current'); removeClass(incrementals[snum][i], 'incremental'); } } if (step != 'j') { snum += step; lmax = smax - 1; if (snum > lmax) snum = lmax; if (snum < 0) snum = 0; } else snum = parseInt(jl.value); var nid = 'slide' + snum; var ne = document.getElementById(nid); if (!ne) { ne = document.getElementById('slide0'); snum = 0; } if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;} if (incrementals[snum].length > 0 && incpos == 0) { for (var i = 0; i < incrementals[snum].length; i++) { if (hasClass(incrementals[snum][i], 'current')) incpos = i + 1; else addClass(incrementals[snum][i], 'incremental'); } } if (incrementals[snum].length > 0 && incpos > 0) addClass(incrementals[snum][incpos - 1], 'current'); ce.style.visibility = 'hidden'; ne.style.visibility = 'visible'; jl.selectedIndex = snum; currentSlide(); number = 0; } function goTo(target) { if (target >= smax || target == snum) return; go(target - snum); } function subgo(step) { if (step > 0) { removeClass(incrementals[snum][incpos - 1],'current'); removeClass(incrementals[snum][incpos], 'incremental'); addClass(incrementals[snum][incpos],'current'); incpos++; } else { incpos--; removeClass(incrementals[snum][incpos],'current'); addClass(incrementals[snum][incpos], 'incremental'); addClass(incrementals[snum][incpos - 1],'current'); } } function toggle() { var slideColl = GetElementsWithClassName('*','slide'); var slides = document.getElementById('slideProj'); var outline = document.getElementById('outlineStyle'); if (!slides.disabled) { slides.disabled = true; outline.disabled = false; s5mode = false; fontSize('1em'); for (var n = 0; n < smax; n++) { var slide = slideColl[n]; slide.style.visibility = 'visible'; } } else { slides.disabled = false; outline.disabled = true; s5mode = true; fontScale(); for (var n = 0; n < smax; n++) { var slide = slideColl[n]; slide.style.visibility = 'hidden'; } slideColl[snum].style.visibility = 'visible'; } } function showHide(action) { var obj = GetElementsWithClassName('*','hideme')[0]; switch (action) { case 's': obj.style.visibility = 'visible'; break; case 'h': obj.style.visibility = 'hidden'; break; case 'k': if (obj.style.visibility != 'visible') { obj.style.visibility = 'visible'; } else { obj.style.visibility = 'hidden'; } break; } } // 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/) function keys(key) { if (!key) { key = event; key.which = key.keyCode; } if (key.which == 84) { toggle(); return; } if (s5mode) { switch (key.which) { case 10: // return case 13: // enter if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; if (key.target && isParentOrSelf(key.target, 'controls')) return; if(number != undef) { goTo(number); break; } case 32: // spacebar case 34: // page down case 39: // rightkey case 40: // downkey if(number != undef) { go(number); } else if (!incrementals[snum] || incpos >= incrementals[snum].length) { go(1); } else { subgo(1); } break; case 33: // page up case 37: // leftkey case 38: // upkey if(number != undef) { go(-1 * number); } else if (!incrementals[snum] || incpos <= 0) { go(-1); } else { subgo(-1); } break; case 36: // home goTo(0); break; case 35: // end goTo(smax-1); break; case 67: // c showHide('k'); break; } if (key.which < 48 || key.which > 57) { number = undef; } else { if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; if (key.target && isParentOrSelf(key.target, 'controls')) return; number = (((number != undef) ? number : 0) * 10) + (key.which - 48); } } return false; } function clicker(e) { number = undef; var target; if (window.event) { target = window.event.srcElement; e = window.event; } else target = e.target; if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true; if (!e.which || e.which == 1) { if (!incrementals[snum] || incpos >= incrementals[snum].length) { go(1); } else { subgo(1); } } } function findSlide(hash) { var target = null; var slides = GetElementsWithClassName('*','slide'); for (var i = 0; i < slides.length; i++) { var targetSlide = slides[i]; if ( (targetSlide.name && targetSlide.name == hash) || (targetSlide.id && targetSlide.id == hash) ) { target = targetSlide; break; } } while(target != null && target.nodeName != 'BODY') { if (hasClass(target, 'slide')) { return parseInt(target.id.slice(5)); } target = target.parentNode; } return null; } function slideJump() { if (window.location.hash == null) return; var sregex = /^#slide(\d+)$/; var matches = sregex.exec(window.location.hash); var dest = null; if (matches != null) { dest = parseInt(matches[1]); } else { dest = findSlide(window.location.hash.slice(1)); } if (dest != null) go(dest - snum); } function fixLinks() { var thisUri = window.location.href; thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length); var aelements = document.getElementsByTagName('A'); for (var i = 0; i < aelements.length; i++) { var a = aelements[i].href; var slideID = a.match('\#slide[0-9]{1,2}'); if ((slideID) && (slideID[0].slice(0,1) == '#')) { var dest = findSlide(slideID[0].slice(1)); if (dest != null) { if (aelements[i].addEventListener) { aelements[i].addEventListener("click", new Function("e", "if (document.getElementById('slideProj').disabled) return;" + "go("+dest+" - snum); " + "if (e.preventDefault) e.preventDefault();"), true); } else if (aelements[i].attachEvent) { aelements[i].attachEvent("onclick", new Function("", "if (document.getElementById('slideProj').disabled) return;" + "go("+dest+" - snum); " + "event.returnValue = false;")); } } } } } function externalLinks() { if (!document.getElementsByTagName) return; var anchors = document.getElementsByTagName('a'); for (var i=0; i' + '