Skip to content

Commit 264474c

Browse files
committed
added Martin's rectangle selector widget
svn path=/trunk/matplotlib/; revision=1710
1 parent 9909572 commit 264474c

File tree

6 files changed

+231
-3
lines changed

6 files changed

+231
-3
lines changed

CHANGELOG

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

3+
2005-09-06 Added Martin's rectangle selector widget
4+
2005-09-04 Fixed a logic err in text.py that was preventing rgxsuper
5+
from matching - JDH
36

47
2005-08-29 Committed Ken's wx blit patch #1275002
58

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Do a mouseclick somewhere, move the mouse to some destination, release
3+
the button. This class gives click- and release-events and also draws
4+
a line or a box from the click-point to the actual mouseposition
5+
(within the same axes) until the button is released. Within the
6+
method 'self.ignore()' it is checked wether the button from eventpress
7+
and eventrelease are the same.
8+
9+
"""
10+
from matplotlib.widgets import RectangleSelector
11+
from pylab import subplot, arange, plot, sin, cos, pi, show
12+
def line_select_callback(event1, event2):
13+
'event1 and event2 are the press and release events'
14+
x1, y1 = event1.xdata, event1.ydata
15+
x2, y2 = event2.xdata, event2.ydata
16+
print "(%3.2f, %3.2f) --> (%3.2f, %3.2f)"%(x1,y1,x2,y2)
17+
print " The button you used were: ",event1.button, event2.button
18+
19+
20+
current_ax=subplot(111) # make a new plotingrange
21+
N=100000 # If N is large one can see improvement
22+
x=10.0*arange(N)/(N-1) # by use blitting!
23+
24+
plot(x,sin(.2*pi*x),lw=3,c='b',alpha=.7) # plot something
25+
plot(x,cos(.2*pi*x),lw=3.5,c='r',alpha=.5)
26+
plot(x,-sin(.2*pi*x),lw=3.5,c='g',alpha=.3)
27+
28+
print "\n click --> release"
29+
30+
# drawtype is 'box' or 'line' or 'none'
31+
LS = RectangleSelector(current_ax, line_select_callback,
32+
drawtype='box',useblit=True)
33+
show()

lib/matplotlib/axes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'jdh'
12
from __future__ import division, generators
23

34
import math, sys

lib/matplotlib/text.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,9 @@ def draw(self, renderer):
297297
ismath = self.is_math_text()
298298

299299
if angle==0:
300-
if ismath!='TeX': m = None
300+
if ismath=='TeX': m = None
301301
else: m = self._rgxsuper.match(self._text)
302-
if m is not None and not rcParams['text.usetex']:
302+
if m is not None:
303303
bbox, info = self._get_layout_super(self._renderer, m)
304304
base, xt, yt = info[0]
305305
renderer.draw_text(gc, xt, yt, base,

lib/matplotlib/widgets.py

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,3 +795,191 @@ def onmove(self, event):
795795
self.rect.set_width(maxx-minx)
796796
self.update()
797797
return False
798+
799+
800+
class RectangleSelector:
801+
"""
802+
Select a min/max range of the x axes for a matplotlib Axes
803+
804+
Example usage:
805+
806+
ax = subplot(111)
807+
ax.plot(x,y)
808+
809+
def onselect(eclick, erelease):
810+
'eclick and erelease are matplotlib events at press and release'
811+
print 'startposition : (%f,%f)'%(eclick.xdata, eclick.ydata)
812+
print 'endposition : (%f,%f)'%(erelease.xdata, erelease.ydata)
813+
print 'used button : ', eclick.button
814+
815+
span = Selector(ax, onselect,drawtype='box')
816+
show()
817+
818+
"""
819+
def __init__(self, ax, onselect, drawtype='box',
820+
minspanx=None, minspany=None, useblit=False,
821+
lineprops=None, rectprops=None):
822+
823+
"""
824+
Create a selector in ax. When a selection is made, clear
825+
the span and call onselect with
826+
827+
onselect(pos_1, pos_2)
828+
829+
and clear the drawn box/line. There pos_i are arrays of length 2
830+
containing the x- and y-coordinate.
831+
832+
If minspanx is not None then events smaller than minspanx
833+
in x direction are ignored(it's the same for y).
834+
835+
The rect is drawn with rectprops; default
836+
rectprops = dict(facecolor='red', edgecolor = 'black',
837+
alpha=0.5, fill=False)
838+
839+
The line is drawn with lineprops; default
840+
lineprops = dict(color='black', linestyle='-',
841+
linewidth = 2, alpha=0.5)
842+
843+
Use type if you want the mouse to draw a line, a box or nothing
844+
between click and actual position ny setting
845+
drawtype = 'line', drawtype='box' or drawtype = 'none'.
846+
847+
848+
"""
849+
self.ax = ax
850+
self.visible = True
851+
self.canvas = ax.figure.canvas
852+
self.canvas.mpl_connect('motion_notify_event', self.onmove)
853+
self.canvas.mpl_connect('button_press_event', self.press)
854+
self.canvas.mpl_connect('button_release_event', self.release)
855+
self.canvas.mpl_connect('draw_event', self.update_background)
856+
857+
self.to_draw = None
858+
self.background = None
859+
860+
if drawtype == 'none':
861+
drawtype = 'line' # draw a line but make it
862+
self.visible = False # invisible
863+
864+
if drawtype == 'box':
865+
if rectprops is None:
866+
rectprops = dict(facecolor='white', edgecolor = 'black',
867+
alpha=0.5, fill=False)
868+
self.rectprops = rectprops
869+
self.to_draw = Rectangle((0,0), 0, 1,visible=False,**self.rectprops)
870+
self.ax.add_patch(self.to_draw)
871+
if drawtype == 'line':
872+
if lineprops is None:
873+
lineprops = dict(color='black', linestyle='-',
874+
linewidth = 2, alpha=0.5)
875+
self.lineprops = lineprops
876+
self.to_draw = Line2D([0,0],[0,0],visible=False,**self.lineprops)
877+
self.ax.add_line(self.to_draw)
878+
879+
self.onselect = onselect
880+
self.useblit = useblit
881+
self.minspanx = minspanx
882+
self.minspany = minspany
883+
self.drawtype = drawtype
884+
# will save the data (position at mouseclick)
885+
self.eventpress = None
886+
# will save the data (pos. at mouserelease)
887+
self.eventrelease = None
888+
889+
def update_background(self, event):
890+
'force an update of the background'
891+
if self.useblit:
892+
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
893+
894+
895+
def ignore(self, event):
896+
'return True if event should be ignored'
897+
# If no button was pressed yet ignore the event if it was out
898+
# of the axes
899+
if self.eventpress == None:
900+
return event.inaxes!= self.ax
901+
902+
# If a button was pressed, check if the release-button is the
903+
# same.
904+
return (event.inaxes!=self.ax or
905+
event.button != self.eventpress.button)
906+
907+
def press(self, event):
908+
'on button press event'
909+
# Is the correct button pressed within the correct axes?
910+
if self.ignore(event): return
911+
912+
913+
# make the drawed box/line visible get the click-coordinates,
914+
# button, ...
915+
self.to_draw.set_visible(self.visible)
916+
self.eventpress = event
917+
return False
918+
919+
920+
def release(self, event):
921+
'on button release event'
922+
if self.eventpress is None or self.ignore(event): return
923+
# make the box/line invisible again
924+
self.to_draw.set_visible(False)
925+
self.canvas.draw()
926+
# release coordinates, button, ...
927+
self.eventrelease = event
928+
xmin, ymin = self.eventpress.xdata, self.eventpress.ydata
929+
xmax, ymax = self.eventrelease.xdata, self.eventrelease.ydata
930+
# calculate dimensions of box or line get values in the right
931+
# order
932+
if xmin>xmax: xmin, xmax = xmax, xmin
933+
if ymin>ymax: ymin, ymax = ymax, ymin
934+
935+
936+
937+
spanx = xmax - xmin
938+
spany = ymax - ymin
939+
xproblems = self.minspanx is not None and spanx<self.minspanx
940+
yproblems = self.minspany is not None and spany<self.minspany
941+
if (self.drawtype=='box') and (xproblems or yproblems):
942+
"""Box to small""" # check if drawed distance (if it exists) is
943+
return # not to small in neither x nor y-direction
944+
if (self.drawtype=='line') and (xproblems and yproblems):
945+
"""Line to small""" # check if drawed distance (if it exists) is
946+
return # not to small in neither x nor y-direction
947+
self.onselect(self.eventpress, self.eventrelease)
948+
# call desired function
949+
self.eventpress = None # reset the variables to their
950+
self.eventrelease = None # inital values
951+
return False
952+
953+
def update(self):
954+
'draw using newfangled blit or oldfangled draw depending on useblit'
955+
if self.useblit:
956+
if self.background is not None:
957+
self.canvas.restore_region(self.background)
958+
self.ax.draw_artist(self.to_draw)
959+
self.canvas.blit(self.ax.bbox)
960+
else:
961+
self.canvas.draw_idle()
962+
return False
963+
964+
965+
def onmove(self, event):
966+
'on motion notify event if box/line is wanted'
967+
if self.eventpress is None or self.ignore(event): return
968+
x,y = event.xdata, event.ydata # actual position (with
969+
# (button still pressed)
970+
if self.drawtype == 'box':
971+
minx, maxx = self.eventpress.xdata, x # click-x and actual mouse-x
972+
miny, maxy = self.eventpress.ydata, y # click-y and actual mouse-y
973+
if minx>maxx: minx, maxx = maxx, minx # get them in the right order
974+
if miny>maxy: miny, maxy = maxy, miny
975+
self.to_draw.xy[0] = minx # set lower left of box
976+
self.to_draw.xy[1] = miny
977+
self.to_draw.set_width(maxx-minx) # set width and height of box
978+
self.to_draw.set_height(maxy-miny)
979+
self.update()
980+
return False
981+
if self.drawtype == 'line':
982+
self.to_draw.set_data([self.eventpress.xdata, x],
983+
[self.eventpress.ydata, y])
984+
self.update()
985+
return False

matplotlibrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ font.style : normal
104104
font.variant : normal
105105
font.weight : medium
106106
font.stretch : normal
107-
font.size : medium
107+
# note that font.size controls default text sizes. To configure
108+
# special text sizes tick labels, axes, labels, title, etc, see the rc
109+
# settings for axes and ticks
110+
font.size : medium
108111
font.serif : New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Bitstream Vera Serif, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
109112
font.sans-serif : Lucida Grande, Verdana, Geneva, Lucida, Bitstream Vera Sans, Arial, Helvetica, sans-serif
110113
font.cursive : Apple Chancery, Textile, Zapf Chancery, Sand, cursive

0 commit comments

Comments
 (0)