Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 68eb00a

Browse files
committed
added editable poly example
svn path=/trunk/matplotlib/; revision=1128
1 parent d4d2d21 commit 68eb00a

File tree

9 files changed

+285
-26
lines changed

9 files changed

+285
-26
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
New entries should be added at the top
22

3+
2005-04-01 Added editable polygon example
4+
35
==========================================================================
46

57
2005-03-31 0.74 released

TODO

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,3 +694,7 @@ ZeroDivisionError: SeparableTransformation::eval_scalars yin interval is zero; c
694694
-- add a get description to axes which returns the args and kwargs to construct it
695695

696696
-- restore __all__ to pylab and add ArtistInspector
697+
698+
699+
-- create set_window_title in the figure manager interface expose this
700+
in the figure command

examples/poly_editor.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""
2+
This is an example to show how to build cross-GUI applications using
3+
matplotlib event handling to interact with objects on the canvas
4+
5+
"""
6+
from matplotlib.patches import Polygon
7+
from matplotlib.numerix import sqrt, nonzero, equal, asarray, dot, Float
8+
from matplotlib.numerix.mlab import amin
9+
from matplotlib.mlab import dist_point_to_segment
10+
11+
12+
13+
14+
class EditablePolygon(Polygon):
15+
"""
16+
An editable polygon.
17+
18+
Key-bindings
19+
20+
't' toggle vertex markers on and off. When vertex markers are on,
21+
you can move them, delete them
22+
23+
'd' delete the vertex under point
24+
25+
'i' insert a vertex at point. You must be within epsilon of the
26+
line connecting two existing vertices
27+
28+
"""
29+
30+
showverts = True
31+
epsilon = 5 # max pixel distance to count as a vertex hit
32+
def __init__(self, *args, **kwargs):
33+
Polygon.__init__(self, *args, **kwargs)
34+
self.line = Line2D([],[],marker='o', markerfacecolor='r')
35+
self._ind = None # the active vert
36+
37+
self.xy = list(self.xy) # make sure it is editable
38+
39+
def set_figure(self, fig):
40+
Polygon.set_figure(self, fig)
41+
self.line.set_figure(fig)
42+
self.figure.canvas.mpl_connect('button_press_event', self.button_press_callback)
43+
self.figure.canvas.mpl_connect('key_press_event', self.key_press_callback)
44+
self.figure.canvas.mpl_connect('button_release_event', self.button_release_callback)
45+
self.figure.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
46+
47+
48+
def set_transform(self, trans):
49+
Polygon.set_transform(self, trans)
50+
self.line.set_transform(trans)
51+
52+
def set_clip_on(self, b):
53+
Polygon.set_clip_on(self, b)
54+
self.line.set_clip_on(b)
55+
56+
def set_clip_box(self, b):
57+
Polygon.set_clip_box(self, b)
58+
self.line.set_clip_box(b)
59+
60+
61+
def draw(self, renderer):
62+
if not self._visible: return
63+
Polygon.draw(self, renderer)
64+
if self.showverts:
65+
self.line.set_data(zip(*self.xy))
66+
self.line.draw(renderer)
67+
68+
def get_ind_under_point(self, event):
69+
x, y = zip(*self.xy)
70+
# display coords
71+
xt, yt = self._transform.numerix_x_y(x, y)
72+
d = sqrt((xt-event.x)**2 + (yt-event.y)**2)
73+
indseq = nonzero(equal(d, amin(d)))
74+
ind = indseq[0]
75+
if d[ind]>=self.epsilon:
76+
ind = None
77+
78+
return ind
79+
80+
def button_press_callback(self, event):
81+
if not self.showverts: return
82+
if event.inaxes==None: return
83+
self._ind = self.get_ind_under_point(event)
84+
85+
86+
def button_release_callback(self, event):
87+
if not self.showverts: return
88+
self._ind = None
89+
90+
def key_press_callback(self, event):
91+
if not event.inaxes: return
92+
if event.key=='t':
93+
self.showverts = not self.showverts
94+
if not self.showverts: self._ind = None
95+
elif event.key=='d':
96+
ind = self.get_ind_under_point(event)
97+
if ind is not None:
98+
self.xy = [tup for i,tup in enumerate(self.xy) if i!=ind]
99+
elif event.key=='i':
100+
xys = self._transform.seq_xy_tups(self.xy)
101+
p = event.x, event.y # display coords
102+
for i in range(len(xys)-1):
103+
s0 = xys[i]
104+
s1 = xys[i+1]
105+
d = dist_point_to_segment(p, s0, s1)
106+
if d<=self.epsilon:
107+
self.xy.insert(i+1, (event.xdata, event.ydata))
108+
break
109+
110+
111+
112+
113+
self.figure.canvas.draw()
114+
115+
def motion_notify_callback(self, event):
116+
if not self.showverts: return
117+
if self._ind is None: return
118+
if event.inaxes is None: return
119+
x,y = event.xdata, event.ydata
120+
self.xy[self._ind] = x,y
121+
self.figure.canvas.draw_idle()
122+
123+
124+
from pylab import *
125+
verts = Circle((.5,.5),.5).get_verts()
126+
p = EditablePolygon(verts)
127+
128+
fig = figure()
129+
ax = subplot(111)
130+
ax.add_patch(p)
131+
title('Click and drag a point to move it')
132+
axis([0,1,0,1])
133+
show()

lib/matplotlib/backend_bases.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,12 @@ def draw(self, *args, **kwargs):
748748
"""
749749
pass
750750

751+
def draw_idle(self, *args, **kwargs):
752+
"""
753+
draw only if idle; defaults to draw but backends can overrride
754+
"""
755+
self.draw(self, *args, **kwargs)
756+
751757
def draw_cursor(self, event):
752758
"""
753759
Draw a cursor in the event.axes if inaxes is not None. Use

lib/matplotlib/backends/backend_gtk.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ def draw(self):
203203
self._draw_pixmap = True
204204
self.expose_event(self, None)
205205

206+
def draw_idle(self):
207+
def idle_draw(*args):
208+
self.draw()
209+
self._idleID = 0
210+
return False
211+
if self._idleID==0:
212+
self._idleID = gtk.idle_add(idle_draw)
213+
206214

207215
def _renderer_init(self):
208216
"""Override by GTK backends to select a different renderer
@@ -461,13 +469,9 @@ def release(self, event):
461469
except AttributeError: pass
462470

463471
def dynamic_update(self):
464-
def idle_draw(*args):
465-
self.canvas.draw()
466-
self._idleId = 0
467-
return False
468-
if self._idleId==0:
469-
self._idleId = gtk.idle_add(idle_draw)
470-
472+
# legacy method; new method is canvas.draw_idle
473+
self.canvas.draw_idle()
474+
471475
def draw_rubberband(self, event, x0, y0, x1, y1):
472476
'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744'
473477
drawable = self.canvas.window

lib/matplotlib/backends/backend_tkagg.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class FigureCanvasTkAgg(FigureCanvasAgg):
9898

9999
def __init__(self, figure, master=None, resize_callback=None):
100100
FigureCanvasAgg.__init__(self, figure)
101+
self._idle = True
101102
t1,t2,w,h = self.figure.bbox.get_bounds()
102103
w, h = int(w), int(h)
103104
self._tkcanvas = Tk.Canvas(
@@ -146,6 +147,16 @@ def draw(self):
146147

147148
show = draw
148149

150+
def draw_idle(self):
151+
'update drawing area only if idle'
152+
d = self._idle
153+
self._idle = False
154+
def idle_draw(*args):
155+
self.draw()
156+
self._idle = True
157+
158+
if d: self._tkcanvas.after_idle(idle_draw)
159+
149160
def get_tk_widget(self):
150161
"""returns the Tk widget used to implement FigureCanvasTkAgg.
151162
Although the initial implementation uses a Tk canvas, this routine
@@ -613,14 +624,9 @@ def update(self):
613624

614625
def dynamic_update(self):
615626
'update drawing area only if idle'
616-
d = self._idle
617-
self._idle = False
618-
def idle_draw(*args):
619-
self.canvas.draw()
620-
self._idle = True
627+
# legacy method; new method is canvas.draw_idle
628+
self.canvas.draw_idle()
621629

622-
if d: self.canvas._tkcanvas.after_idle(idle_draw)
623-
624630

625631
FigureManager = FigureManagerTkAgg
626632

lib/matplotlib/backends/backend_wx.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ def __init__(self, parent, id, figure):
691691
l,b,w,h = figure.bbox.get_bounds()
692692
w = int(math.ceil(w))
693693
h = int(math.ceil(h))
694-
694+
self._idle = True
695695
wxPanel.__init__(self, parent, id, size=wxSize(w, h))
696696
# Create the drawing bitmap
697697
self.bitmap = wxEmptyBitmap(w, h)
@@ -847,6 +847,13 @@ def draw(self):
847847
self.figure.draw(self.renderer)
848848
self.gui_repaint()
849849

850+
def draw_idle(self):
851+
d = self._idle
852+
self._idle = False
853+
if d:
854+
self.draw()
855+
self._idle = True
856+
850857
def _get_imagesave_wildcards(self):
851858
'return the wildcard string for the filesave dialog'
852859
return "JPEG (*.jpg)|*.jpg|" \
@@ -1500,11 +1507,7 @@ def release(self, event):
15001507
except AttributeError: pass
15011508

15021509
def dynamic_update(self):
1503-
d = self._idle
1504-
self._idle = False
1505-
if d:
1506-
self.canvas.draw()
1507-
self._idle = True
1510+
self.canvas.draw_idle()
15081511

15091512
def draw_rubberband(self, event, x0, y0, x1, y1):
15101513
'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744'

lib/matplotlib/mlab.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,38 @@ def get_sparse_matrix(M,N,frac=0.1):
11861186
data[x,y] = rand()
11871187
return data
11881188

1189+
def dist(x,y):
1190+
'return the distance between two points'
1191+
d = x-y
1192+
return numerix.mlab.sqrt(dot(d,d))
1193+
1194+
def dist_point_to_segment(p, s0, s1):
1195+
"""
1196+
get the distance of a point to a segment.
1197+
1198+
p, s0, s1 are xy sequences
1199+
1200+
This algorithm from
1201+
http://softsurfer.com/Archive/algorithm_0102/algorithm_0102.htm#Distance%20to%20Ray%20or%20Segment
1202+
"""
1203+
p = asarray(p, Float)
1204+
s0 = asarray(s0, Float)
1205+
s1 = asarray(s1, Float)
1206+
v = s1 - s0
1207+
w = p - s0
1208+
1209+
c1 = dot(w,v);
1210+
if ( c1 <= 0 ):
1211+
return dist(p, s0);
1212+
1213+
c2 = dot(v,v)
1214+
if ( c2 <= c1 ):
1215+
return dist(p, s1);
1216+
1217+
b = c1 / c2
1218+
pb = s0 + b * v;
1219+
return dist(p, pb)
1220+
11891221

11901222
### the following code was written and submitted by Fernando Perez
11911223
### from the ipython numutils package under a BSD license

0 commit comments

Comments
 (0)