Modification of the edit_line.py example from Chaco

  • Download Gist
edit_plot_with_coordinates_feedback.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
"""
Allows editing of a line plot.
 
Left-dragging a point will move its position.
 
Right-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 control-y and
control-z (use Meta-y and Meta-z on Mac) moves you forwards and backwards
through the "zoom history".
"""
 
# Major library imports
from numpy import linspace, array
from scipy.special import jn
 
from chaco.example_support import COLOR_PALETTE
 
# Enthought library imports
from enable.tools.api import DragTool
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance, Int, Tuple, Array, Delegate, on_trait_change
from traitsui.api import UItem, View, Item
 
# Chaco imports
from chaco.api import add_default_axes, add_default_grids, \
OverlayPlotContainer, PlotLabel, ScatterPlot, create_line_plot
from chaco.tools.api import PanTool, ZoomTool
 
 
 
class PointDraggingTool(DragTool):
 
component = Instance(Component)
x_u = component.x_u
y_u = component.y_u
 
# The pixel distance from a point that the cursor is still considered
# to be 'on' the point
threshold = Int(5)
 
# The index of the point being dragged
_drag_index = Int(-1)
 
# The original dataspace values of the index and value datasources
# corresponding to _drag_index
_orig_value = Tuple
 
def is_draggable(self, x, y):
# Check to see if (x,y) are over one of the points in self.component
if self._lookup_point(x, y) is not None:
return True
else:
return False
 
def normal_mouse_move(self, event):
plot = self.component
ndx = plot.map_index((event.x, event.y), self.threshold)
if ndx is None:
if plot.index.metadata.has_key('selections'):
del plot.index.metadata['selections']
else:
plot.index.metadata['selections'] = [ndx]
plot.invalidate_draw()
plot.request_redraw()
 
 
def drag_start(self, event):
plot = self.component
ndx = plot.map_index((event.x, event.y), self.threshold)
if ndx is None:
return
self._drag_index = ndx
self._orig_value = (plot.index.get_data()[ndx], plot.value.get_data()[ndx])
 
def dragging(self, event):
plot = self.component
data_x, data_y = plot.map_data((event.x, event.y))
plot.index._data[self._drag_index] = data_x
plot.value._data[self._drag_index] = data_y
plot.index.data_changed = True
plot.value.data_changed = True
plot.request_redraw()
 
def drag_cancel(self, event):
plot = self.component
plot.index._data[self._drag_index] = self._orig_value[0]
plot.value._data[self._drag_index] = self._orig_value[1]
plot.index.data_changed = True
plot.value.data_changed = True
plot.request_redraw()
 
def drag_end(self, event):
plot = self.component
if plot.index.metadata.has_key('selections'):
del plot.index.metadata['selections']
self.component.x_u = plot.index.get_data()
self.component.y_u = plot.value.get_data()
print "Draggable point has moved: x=", self.component.x_u, "y=", self.component.y_u
plot.invalidate_draw()
plot.request_redraw()
 
def _lookup_point(self, x, y):
""" Finds the point closest to a screen point if it is within self.threshold
 
Parameters
==========
x : float
screen x-coordinate
y : float
screen y-coordinate
 
Returns
=======
(screen_x, screen_y, distance) of datapoint nearest to the input *(x,y)*.
If no data points are within *self.threshold* of *(x,y)*, returns None.
"""
 
if hasattr(self.component, 'get_closest_point'):
# This is on BaseXYPlots
return self.component.get_closest_point((x,y), threshold=self.threshold)
 
return None
 
 
 
 
 
#===============================================================================
# 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)
x = Array
y = Array
traits_view = View(UItem('plot', editor=ComponentEditor()),
Item('x'),
Item('y'),
width=size[0], height=size[1], resizable=True,
title=title
)
 
@on_trait_change('plot.container.scatter.x_u')
def update_xy(self):
print "From Demo - point has moved: x=", self.plot.component.x_u, "y=", self.plot.component.y_u
self.x = self.plot.component.x_u
self.y = self.plot.component.y_u
 
def _plot_default(self):
# return _create_plot_component()
 
#===============================================================================
# # Create the Chaco plot.
#===============================================================================
#def _create_plot_component(self):
 
container = OverlayPlotContainer(padding = 50, fill_padding = True,
bgcolor = "lightgray", use_backbuffer=True)
self.x=array([0.])
self.y=array([0.])
 
lineplot = create_line_plot((self.x,self.y), color=tuple(COLOR_PALETTE[0]), width=2.0)
lineplot.selected_color = "none"
scatter = ScatterPlot(index = lineplot.index,
value = lineplot.value,
index_mapper = lineplot.index_mapper,
value_mapper = lineplot.value_mapper,
x_u = Array,
y_u = Array,
color = tuple(COLOR_PALETTE[0]),
marker_size = 5)
scatter.index.sort_order = "ascending"
 
scatter.bgcolor = "white"
scatter.border_visible = True
 
add_default_grids(scatter)
add_default_axes(scatter)
 
scatter.tools.append(PanTool(scatter, drag_button="right"))
 
# The ZoomTool tool is stateful and allows drawing a zoom
# box to select a zoom region.
zoom = ZoomTool(scatter, tool_mode="box", always_on=False)
scatter.overlays.append(zoom)
 
scatter.tools.append(PointDraggingTool(scatter))
 
container.add(lineplot)
container.add(scatter)
 
# Add the title at the top
container.overlays.append(PlotLabel("Line Editor",
component=container,
font = "swiss 16",
overlay_position="top"))
 
return container
 
 
if __name__ == "__main__":
demo = Demo()
 
demo.configure_traits()
 
#--EOF---

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.