@@ -1990,14 +1990,10 @@ def on_key_press(self, event):
1990
1990
self .update ()
1991
1991
return
1992
1992
for (state , modifier ) in self ._state_modifier_keys .items ():
1993
- if modifier in key .split ('+' ):
1994
- # rotate and data_coordinates are enable/disable
1995
- # on key press
1996
- if (state in ['rotate' , 'data_coordinates' ] and
1997
- state in self ._state ):
1998
- self ._state .discard (state )
1999
- else :
2000
- self ._state .add (state )
1993
+ # 'rotate' and 'data_coordinates' are added in _default_state
1994
+ if (modifier in key .split ('+' ) and
1995
+ state not in ['rotate' , 'data_coordinates' ]):
1996
+ self ._state .add (state )
2001
1997
self ._on_key_press (event )
2002
1998
2003
1999
def _on_key_press (self , event ):
@@ -2007,9 +2003,9 @@ def on_key_release(self, event):
2007
2003
"""Key release event handler and validator."""
2008
2004
if self .active :
2009
2005
key = event .key or ''
2006
+ key = key .replace ('ctrl' , 'control' )
2010
2007
for (state , modifier ) in self ._state_modifier_keys .items ():
2011
- if (modifier in key .split ('+' ) and
2012
- state not in ['rotate' , 'data_coordinates' ]):
2008
+ if modifier in key .split ('+' ):
2013
2009
self ._state .discard (state )
2014
2010
self ._on_key_release (event )
2015
2011
@@ -2795,7 +2791,8 @@ def __init__(self, ax, onselect, drawtype='box',
2795
2791
self ._interactive = interactive
2796
2792
self .drag_from_anywhere = drag_from_anywhere
2797
2793
self .ignore_event_outside = ignore_event_outside
2798
- self ._rotation = 0
2794
+ self ._rotation = 0.0
2795
+ self ._aspect_ratio_correction = 1.0
2799
2796
2800
2797
if drawtype == 'none' : # draw a line but make it invisible
2801
2798
_api .warn_deprecated (
@@ -2814,6 +2811,7 @@ def __init__(self, ax, onselect, drawtype='box',
2814
2811
_props = props
2815
2812
self .visible = _props .pop ('visible' , self .visible )
2816
2813
self ._to_draw = self ._init_shape (** _props )
2814
+ self ._set_aspect_ratio_correction ()
2817
2815
self .ax .add_patch (self ._to_draw )
2818
2816
if drawtype == 'line' :
2819
2817
_api .warn_deprecated (
@@ -2909,6 +2907,7 @@ def _press(self, event):
2909
2907
self .set_visible (True )
2910
2908
2911
2909
self ._extents_on_press = self .extents
2910
+ self ._rotation_on_press = self ._rotation
2912
2911
2913
2912
return False
2914
2913
@@ -2984,13 +2983,8 @@ def _onmove(self, event):
2984
2983
dy = event .ydata - eventpress .ydata
2985
2984
refmax = None
2986
2985
if 'data_coordinates' in state :
2987
- aspect_ratio = 1
2988
2986
refx , refy = dx , dy
2989
2987
else :
2990
- figure_size = self .ax .get_figure ().get_size_inches ()
2991
- ll , ur = self .ax .get_position () * figure_size
2992
- width , height = ur - ll
2993
- aspect_ratio = height / width * self .ax .get_data_ratio ()
2994
2988
refx = event .xdata / (eventpress .xdata + 1e-6 )
2995
2989
refy = event .ydata / (eventpress .ydata + 1e-6 )
2996
2990
@@ -3001,8 +2995,9 @@ def _onmove(self, event):
3001
2995
a = np .array ([eventpress .xdata , eventpress .ydata ])
3002
2996
b = np .array (self .center )
3003
2997
c = np .array ([event .xdata , event .ydata ])
3004
- self ._rotation = (np .arctan2 (c [1 ]- b [1 ], c [0 ]- b [0 ]) -
3005
- np .arctan2 (a [1 ]- b [1 ], a [0 ]- b [0 ]))
2998
+ angle = (np .arctan2 (c [1 ]- b [1 ], c [0 ]- b [0 ]) -
2999
+ np .arctan2 (a [1 ]- b [1 ], a [0 ]- b [0 ]))
3000
+ self ._rotation = self ._rotation_on_press + angle
3006
3001
3007
3002
# resize an existing shape
3008
3003
elif self ._active_handle and self ._active_handle != 'C' :
@@ -3017,10 +3012,10 @@ def _onmove(self, event):
3017
3012
refmax = max (refx , refy , key = abs )
3018
3013
if self ._active_handle in ['E' , 'W' ] or refmax == refx :
3019
3014
dw = event .xdata - center [0 ]
3020
- dh = dw / aspect_ratio
3015
+ dh = dw
3021
3016
else :
3022
3017
dh = event .ydata - center [1 ]
3023
- dw = dh * aspect_ratio
3018
+ dw = dh
3024
3019
else :
3025
3020
dw = sizepress [0 ] / 2
3026
3021
dh = sizepress [1 ] / 2
@@ -3053,10 +3048,10 @@ def _onmove(self, event):
3053
3048
refmax = max (refx , refy , key = abs )
3054
3049
if self ._active_handle in ['E' , 'W' ] or refmax == refx :
3055
3050
sign = np .sign (event .ydata - y0 )
3056
- y1 = y0 + sign * abs (x1 - x0 ) / aspect_ratio
3051
+ y1 = y0 + sign * abs (x1 - x0 )
3057
3052
else :
3058
3053
sign = np .sign (event .xdata - x0 )
3059
- x1 = x0 + sign * abs (y1 - y0 ) * aspect_ratio
3054
+ x1 = x0 + sign * abs (y1 - y0 )
3060
3055
3061
3056
# move existing shape
3062
3057
elif self ._active_handle == 'C' :
@@ -3083,9 +3078,9 @@ def _onmove(self, event):
3083
3078
if 'square' in state :
3084
3079
refmax = max (refx , refy , key = abs )
3085
3080
if refmax == refx :
3086
- dy = dx / aspect_ratio
3081
+ dy = dx
3087
3082
else :
3088
- dx = dy * aspect_ratio
3083
+ dx = dy
3089
3084
3090
3085
# from center
3091
3086
if 'center' in state :
@@ -3102,6 +3097,18 @@ def _onmove(self, event):
3102
3097
3103
3098
self .extents = x0 , x1 , y0 , y1
3104
3099
3100
+ def _on_key_press (self , event ):
3101
+ key = event .key or ''
3102
+ key = key .replace ('ctrl' , 'control' )
3103
+ for (state , modifier ) in self ._state_modifier_keys .items ():
3104
+ if modifier in key .split ('+' ):
3105
+ if state in ['rotate' , 'data_coordinates' ]:
3106
+ if state in self ._default_state :
3107
+ self ._default_state .discard (state )
3108
+ else :
3109
+ self ._default_state .add (state )
3110
+ self ._set_aspect_ratio_correction ()
3111
+
3105
3112
@property
3106
3113
def _rect_bbox (self ):
3107
3114
if self ._drawtype == 'box' :
@@ -3112,8 +3119,19 @@ def _rect_bbox(self):
3112
3119
y0 , y1 = min (y ), max (y )
3113
3120
return x0 , y0 , x1 - x0 , y1 - y0
3114
3121
3122
+ def _set_aspect_ratio_correction (self ):
3123
+ if 'data_coordinates' in self ._state | self ._default_state :
3124
+ self ._aspect_ratio_correction = 1
3125
+ else :
3126
+ self ._aspect_ratio_correction = self .ax ._get_aspect_ratio ()
3127
+ self ._to_draw ._aspect_ratio_correction = self ._aspect_ratio_correction
3128
+
3115
3129
def _get_rotation_transform (self ):
3116
- return Affine2D ().rotate_around (* self .center , self ._rotation )
3130
+ return Affine2D ().translate (- self .center [0 ], - self .center [1 ]) \
3131
+ .scale (1 , self ._aspect_ratio_correction ) \
3132
+ .rotate (self ._rotation ) \
3133
+ .scale (1 , 1 / self ._aspect_ratio_correction ) \
3134
+ .translate (* self .center )
3117
3135
3118
3136
@property
3119
3137
def corners (self ):
@@ -3285,7 +3303,7 @@ def _draw_shape(self, extents):
3285
3303
self ._to_draw .center = center
3286
3304
self ._to_draw .width = 2 * a
3287
3305
self ._to_draw .height = 2 * b
3288
- self ._to_draw .set_angle ( self .rotation )
3306
+ self ._to_draw .angle = self .rotation
3289
3307
else :
3290
3308
rad = np .deg2rad (np .arange (31 ) * 12 )
3291
3309
x = a * np .cos (rad ) + center [0 ]
0 commit comments