Skip to content

Commit 26728a2

Browse files
committed
Fix bug in polar plots: if rmax - rmin was too small, the old rpad padding heuristic broke down and sent the rlabels way off of the plot axes. The new approach is to not have rpad, but to change the alignment of the rlabels depending on the quadrant of the plot. This seems to work quite well, but is perhaps slightly backward incompatible.
1 parent 521e58b commit 26728a2

File tree

2 files changed

+50
-42
lines changed

2 files changed

+50
-42
lines changed

CHANGELOG

+6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
2012-02-29 errorevery keyword added to errorbar to enable errorbar
22
subsampling. fixes issue #600.
33

4+
2012-01-23 The radius labels in polar plots no longer use a fixed
5+
padding, but use a different alignment depending on the
6+
quadrant they are in. This fixes numerical problems when
7+
(rmax - rmin) gets too small. - MGD
8+
49
2012-01-08 Add axes.streamplot to plot streamlines of a velocity field.
510
Adapted from Tom Flannaghan streamplot implementation. -TSY
611

712
2011-12-29 ps and pdf markers are now stroked only if the line width
813
is nonzero for consistency with agg, fixes issue #621. - JKS
914

15+
1016
2011-12-27 Work around an EINTR bug in some versions of subprocess. - JKS
1117

1218

lib/matplotlib/projections/polar.py

+44-42
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def transform(self, tr):
6363

6464
t *= theta_direction
6565
t += theta_offset
66-
66+
6767
if rmin != 0:
6868
r = r - rmin
6969
mask = r < 0
@@ -150,7 +150,7 @@ def transform(self, xy):
150150
rmin = 0
151151
theta_offset = 0
152152
theta_direction = 1
153-
153+
154154
x = xy[:, 0:1]
155155
y = xy[:, 1:]
156156
r = np.sqrt(x*x + y*y)
@@ -161,7 +161,7 @@ def transform(self, xy):
161161
theta *= theta_direction
162162

163163
r += rmin
164-
164+
165165
return np.concatenate((theta, r), 1)
166166
transform.__doc__ = Transform.transform.__doc__
167167

@@ -230,7 +230,6 @@ def __init__(self, *args, **kwargs):
230230
interpolation.
231231
"""
232232

233-
self._rpad = 0.05
234233
self.resolution = kwargs.pop('resolution', None)
235234
if self.resolution not in (None, 1):
236235
warnings.warn(
@@ -262,7 +261,7 @@ def cla(self):
262261

263262
self.set_theta_offset(0)
264263
self.set_theta_direction(1)
265-
264+
266265
def _init_axis(self):
267266
"move this out of __init__ because non-separable axes don't use it"
268267
self.xaxis = maxis.XAxis(self)
@@ -320,21 +319,10 @@ def _set_lim_and_transforms(self):
320319
Affine2D().scale(np.pi * 2.0, 1.0) +
321320
self.transData)
322321
# The r-axis labels are put at an angle and padded in the r-direction
323-
self._r_label1_position = ScaledTranslation(
324-
22.5, self._rpad,
325-
blended_transform_factory(
326-
Affine2D(), BboxTransformToMaxOnly(self.viewLim)))
327-
self._yaxis_text1_transform = (
328-
self._r_label1_position +
329-
Affine2D().scale(1.0 / 360.0, 1.0) +
330-
self._yaxis_transform
331-
)
332-
self._r_label2_position = ScaledTranslation(
333-
22.5, -self._rpad,
334-
blended_transform_factory(
335-
Affine2D(), BboxTransformToMaxOnly(self.viewLim)))
336-
self._yaxis_text2_transform = (
337-
self._r_label2_position +
322+
self._r_label_position = ScaledTranslation(
323+
22.5, 0.0, Affine2D())
324+
self._yaxis_text_transform = (
325+
self._r_label_position +
338326
Affine2D().scale(1.0 / 360.0, 1.0) +
339327
self._yaxis_transform
340328
)
@@ -354,10 +342,26 @@ def get_yaxis_transform(self,which='grid'):
354342
return self._yaxis_transform
355343

356344
def get_yaxis_text1_transform(self, pad):
357-
return self._yaxis_text1_transform, 'center', 'center'
345+
angle = self._r_label_position.to_values()[4]
346+
if angle < 90.:
347+
return self._yaxis_text_transform, 'bottom', 'left'
348+
elif angle < 180.:
349+
return self._yaxis_text_transform, 'bottom', 'right'
350+
elif angle < 270.:
351+
return self._yaxis_text_transform, 'top', 'right'
352+
else:
353+
return self._yaxis_text_transform, 'top', 'left'
358354

359355
def get_yaxis_text2_transform(self, pad):
360-
return self._yaxis_text2_transform, 'center', 'center'
356+
angle = self._r_label_position.to_values()[4]
357+
if angle < 90.:
358+
return self._yaxis_text_transform, 'top', 'right'
359+
elif angle < 180.:
360+
return self._yaxis_text_transform, 'top', 'left'
361+
elif angle < 270.:
362+
return self._yaxis_text_transform, 'bottom', 'left'
363+
else:
364+
return self._yaxis_text_transform, 'bottom', 'right'
361365

362366
def _gen_axes_patch(self):
363367
return Circle((0.5, 0.5), 0.5)
@@ -407,7 +411,7 @@ def set_theta_zero_location(self, loc):
407411
'E': 0,
408412
'NE': np.pi * 0.25 }
409413
return self.set_theta_offset(mapping[loc])
410-
414+
411415
def set_theta_direction(self, direction):
412416
"""
413417
Set the direction in which theta increases.
@@ -438,7 +442,7 @@ def get_theta_direction(self):
438442
Theta increases in the counterclockwise direction
439443
"""
440444
return self._direction
441-
445+
442446
def set_rlim(self, *args, **kwargs):
443447
if 'rmin' in kwargs:
444448
kwargs['ymin'] = kwargs.pop('rmin')
@@ -497,7 +501,7 @@ def set_thetagrids(self, angles, labels=None, frac=None, fmt=None,
497501
return self.xaxis.get_ticklines(), self.xaxis.get_ticklabels()
498502

499503
@docstring.dedent_interpd
500-
def set_rgrids(self, radii, labels=None, angle=None, rpad=None, fmt=None,
504+
def set_rgrids(self, radii, labels=None, angle=None, fmt=None,
501505
**kwargs):
502506
"""
503507
Set the radial locations and labels of the *r* grids.
@@ -510,9 +514,6 @@ def set_rgrids(self, radii, labels=None, angle=None, rpad=None, fmt=None,
510514
511515
If *labels* is None, the built-in formatter will be used.
512516
513-
*rpad* is a fraction of the max of *radii* which will pad each of
514-
the radial labels in the radial direction.
515-
516517
Return value is a list of tuples (*line*, *label*), where
517518
*line* is :class:`~matplotlib.lines.Line2D` instances and the
518519
*label* is :class:`~matplotlib.text.Text` instances.
@@ -536,13 +537,9 @@ def set_rgrids(self, radii, labels=None, angle=None, rpad=None, fmt=None,
536537
elif fmt is not None:
537538
self.yaxis.set_major_formatter(FormatStrFormatter(fmt))
538539
if angle is None:
539-
angle = self._r_label1_position.to_values()[4]
540-
if rpad is not None:
541-
self._rpad = rpad
542-
self._r_label1_position._t = (angle, self._rpad)
543-
self._r_label1_position.invalidate()
544-
self._r_label2_position._t = (angle, -self._rpad)
545-
self._r_label2_position.invalidate()
540+
angle = self._r_label_position.to_values()[4]
541+
self._r_label_position._t = (angle, 0.0)
542+
self._r_label_position.invalidate()
546543
for t in self.yaxis.get_ticklabels():
547544
t.update(kwargs)
548545
return self.yaxis.get_gridlines(), self.yaxis.get_ticklabels()
@@ -594,7 +591,7 @@ def can_pan(self) :
594591
return True
595592

596593
def start_pan(self, x, y, button):
597-
angle = self._r_label1_position.to_values()[4] / 180.0 * np.pi
594+
angle = np.deg2rad(self._r_label_position.to_values()[4])
598595
mode = ''
599596
if button == 1:
600597
epsilon = np.pi / 45.0
@@ -608,7 +605,7 @@ def start_pan(self, x, y, button):
608605
rmax = self.get_rmax(),
609606
trans = self.transData.frozen(),
610607
trans_inverse = self.transData.inverted().frozen(),
611-
r_label_angle = self._r_label1_position.to_values()[4],
608+
r_label_angle = self._r_label_position.to_values()[4],
612609
x = x,
613610
y = y,
614611
mode = mode
@@ -633,11 +630,16 @@ def drag_pan(self, button, key, x, y):
633630
dt = dt0 * -1.0
634631
dt = (dt / np.pi) * 180.0
635632

636-
rpad = self._rpad
637-
self._r_label1_position._t = (p.r_label_angle - dt, rpad)
638-
self._r_label1_position.invalidate()
639-
self._r_label2_position._t = (p.r_label_angle - dt, -rpad)
640-
self._r_label2_position.invalidate()
633+
self._r_label_position._t = (p.r_label_angle - dt, 0.0)
634+
self._r_label_position.invalidate()
635+
636+
trans, vert1, horiz1 = self.get_yaxis_text1_transform(0.0)
637+
trans, vert2, horiz2 = self.get_yaxis_text2_transform(0.0)
638+
for t in self.yaxis.majorTicks + self.yaxis.minorTicks:
639+
t.label1.set_va(vert1)
640+
t.label1.set_ha(horiz1)
641+
t.label2.set_va(vert2)
642+
t.label2.set_ha(horiz2)
641643

642644
elif p.mode == 'zoom':
643645
startt, startr = p.trans_inverse.transform_point((p.x, p.y))

0 commit comments

Comments
 (0)