Skip to content

Commit 61dec52

Browse files
authored
Merge pull request matplotlib#12300 from jklymak/fix-polar-ylim-order
API: Polar: allow flipped y/rlims....
2 parents 369618a + 3ecd588 commit 61dec52

File tree

5 files changed

+109
-17
lines changed

5 files changed

+109
-17
lines changed

lib/matplotlib/axes/_base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3122,8 +3122,8 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False,
31223122
limit unchanged.
31233123
31243124
The left and right xlims may be passed as the tuple
3125-
(`left`, `right`) as the first positional argument (or as
3126-
the `left` keyword argument).
3125+
(*left*, *right*) as the first positional argument (or as
3126+
the *left* keyword argument).
31273127
31283128
right : scalar, optional
31293129
The right xlim in data coordinates. Passing *None* leaves the
@@ -3169,7 +3169,7 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False,
31693169
>>> set_xlim(right=right_lim)
31703170
31713171
Limits may be passed in reverse order to flip the direction of
3172-
the x-axis. For example, suppose ``x`` represents the number of
3172+
the x-axis. For example, suppose *x* represents the number of
31733173
years before present. The x-axis limits might be set like the
31743174
following so 5000 years ago is on the left of the plot and the
31753175
present is on the right.
@@ -3510,15 +3510,15 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False,
35103510
limit unchanged.
35113511
35123512
The bottom and top ylims may be passed as the tuple
3513-
(`bottom`, `top`) as the first positional argument (or as
3514-
the `bottom` keyword argument).
3513+
(*bottom*, *top*) as the first positional argument (or as
3514+
the *bottom* keyword argument).
35153515
35163516
top : scalar, optional
35173517
The top ylim in data coordinates. Passing *None* leaves the
35183518
limit unchanged.
35193519
35203520
emit : bool, optional
3521-
Whether to notify observers of limit change (default: True).
3521+
Whether to notify observers of limit change (default: ``True``).
35223522
35233523
auto : bool or None, optional
35243524
Whether to turn on autoscaling of the y-axis. *True* turns on,

lib/matplotlib/projections/polar.py

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import types
33

44
import numpy as np
5+
import warnings
56

67
from matplotlib.axes import Axes
78
import matplotlib.axis as maxis
@@ -57,7 +58,8 @@ def transform_non_affine(self, tr):
5758
t += self._axis.get_theta_offset()
5859

5960
if self._use_rmin and self._axis is not None:
60-
r = r - self._axis.get_rorigin()
61+
r = (r - self._axis.get_rorigin()) * self._axis.get_rsign()
62+
6163
mask = r < 0
6264
x[:] = np.where(mask, np.nan, r * np.cos(t))
6365
y[:] = np.where(mask, np.nan, r * np.sin(t))
@@ -161,6 +163,7 @@ def transform_non_affine(self, xy):
161163

162164
if self._use_rmin and self._axis is not None:
163165
r += self._axis.get_rorigin()
166+
r *= self._axis.get_rsign()
164167

165168
return np.concatenate((theta, r), 1)
166169
transform_non_affine.__doc__ = \
@@ -421,10 +424,9 @@ def __call__(self):
421424
# Ensure previous behaviour with full circle non-annular views.
422425
if self._axes:
423426
if _is_full_circle_rad(*self._axes.viewLim.intervalx):
424-
rorigin = self._axes.get_rorigin()
427+
rorigin = self._axes.get_rorigin() * self._axes.get_rsign()
425428
if self._axes.get_rmin() <= rorigin:
426429
show_all = False
427-
428430
if show_all:
429431
return self.base()
430432
else:
@@ -444,7 +446,10 @@ def refresh(self):
444446

445447
def view_limits(self, vmin, vmax):
446448
vmin, vmax = self.base.view_limits(vmin, vmax)
447-
return mtransforms.nonsingular(min(0, vmin), vmax)
449+
if vmax > vmin:
450+
# this allows inverted r/y-lims
451+
vmin = min(0, vmin)
452+
return mtransforms.nonsingular(vmin, vmax)
448453

449454

450455
class _ThetaShift(mtransforms.ScaledTranslation):
@@ -767,7 +772,6 @@ def __str__(self):
767772
def get_points(self):
768773
if self._invalid:
769774
points = self._viewLim.get_points().copy()
770-
771775
# Scale angular limits to work with Wedge.
772776
points[:, 0] *= 180 / np.pi
773777
if points[0, 0] > points[1, 0]:
@@ -992,8 +996,8 @@ def draw(self, *args, **kwargs):
992996
thetamin, thetamax = np.rad2deg(self._realViewLim.intervalx)
993997
if thetamin > thetamax:
994998
thetamin, thetamax = thetamax, thetamin
995-
rmin, rmax = self._realViewLim.intervaly - self.get_rorigin()
996-
999+
rmin, rmax = ((self._realViewLim.intervaly - self.get_rorigin()) *
1000+
self.get_rsign())
9971001
if isinstance(self.patch, mpatches.Wedge):
9981002
# Backwards-compatibility: Any subclassed Axes might override the
9991003
# patch to not be the Wedge that PolarAxes uses.
@@ -1160,12 +1164,83 @@ def set_rorigin(self, rorigin):
11601164
def get_rorigin(self):
11611165
return self._originViewLim.y0
11621166

1163-
def set_rlim(self, *args, **kwargs):
1167+
def get_rsign(self):
1168+
return np.sign(self._originViewLim.y1 - self._originViewLim.y0)
1169+
1170+
def set_rlim(self, bottom=None, top=None, emit=True, auto=False, **kwargs):
1171+
"""
1172+
See `~.polar.PolarAxes.set_ylim`.
1173+
"""
11641174
if 'rmin' in kwargs:
1165-
kwargs['ymin'] = kwargs.pop('rmin')
1175+
if bottom is None:
1176+
bottom = kwargs.pop('rmin')
1177+
else:
1178+
raise ValueError('Cannot supply both positional "bottom"'
1179+
'argument and kwarg "rmin"')
11661180
if 'rmax' in kwargs:
1167-
kwargs['ymax'] = kwargs.pop('rmax')
1168-
return self.set_ylim(*args, **kwargs)
1181+
if top is None:
1182+
top = kwargs.pop('rmax')
1183+
else:
1184+
raise ValueError('Cannot supply both positional "top"'
1185+
'argument and kwarg "rmax"')
1186+
return self.set_ylim(bottom=bottom, top=top, emit=emit, auto=auto,
1187+
**kwargs)
1188+
1189+
def set_ylim(self, bottom=None, top=None, emit=True, auto=False,
1190+
*, ymin=None, ymax=None):
1191+
"""
1192+
Set the data limits for the radial axis.
1193+
1194+
Parameters
1195+
----------
1196+
bottom : scalar, optional
1197+
The bottom limit (default: None, which leaves the bottom
1198+
limit unchanged).
1199+
The bottom and top ylims may be passed as the tuple
1200+
(*bottom*, *top*) as the first positional argument (or as
1201+
the *bottom* keyword argument).
1202+
1203+
top : scalar, optional
1204+
The top limit (default: None, which leaves the top limit
1205+
unchanged).
1206+
1207+
emit : bool, optional
1208+
Whether to notify observers of limit change (default: True).
1209+
1210+
auto : bool or None, optional
1211+
Whether to turn on autoscaling of the y-axis. True turns on,
1212+
False turns off (default action), None leaves unchanged.
1213+
1214+
ymin, ymax : scalar, optional
1215+
These arguments are deprecated and will be removed in a future
1216+
version. They are equivalent to *bottom* and *top* respectively,
1217+
and it is an error to pass both *ymin* and *bottom* or
1218+
*ymax* and *top*.
1219+
1220+
Returns
1221+
-------
1222+
ylimits : tuple
1223+
Returns the new y-axis limits as (*bottom*, *top*).
1224+
1225+
"""
1226+
1227+
if ymin is not None:
1228+
if bottom is not None:
1229+
raise ValueError('Cannot supply both positional "bottom" '
1230+
'argument and kwarg "ymin"')
1231+
else:
1232+
bottom = ymin
1233+
if ymax is not None:
1234+
if top is not None:
1235+
raise ValueError('Cannot supply both positional "top" '
1236+
'argument and kwarg "ymax"')
1237+
else:
1238+
top = ymax
1239+
if top is None and len(bottom) == 2:
1240+
top = bottom[1]
1241+
bottom = bottom[0]
1242+
1243+
return super().set_ylim(bottom=bottom, top=top, emit=emit, auto=auto)
11691244

11701245
def get_rlabel_position(self):
11711246
"""
Loading
Loading

lib/matplotlib/tests/test_axes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,23 @@ def test_polar_rorigin():
726726
ax.set_rorigin(0.0)
727727

728728

729+
@image_comparison(baseline_images=['polar_invertedylim'], style='default',
730+
extensions=['png'])
731+
def test_polar_invertedylim():
732+
fig = plt.figure()
733+
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
734+
ax.set_ylim(2, 0)
735+
736+
737+
@image_comparison(baseline_images=['polar_invertedylim_rorigin'],
738+
style='default', extensions=['png'])
739+
def test_polar_invertedylim_rorigin():
740+
fig = plt.figure()
741+
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
742+
ax.set_ylim(2, 0)
743+
ax.set_rorigin(3)
744+
745+
729746
@image_comparison(baseline_images=['polar_theta_position'], style='default')
730747
def test_polar_theta_position():
731748
r = np.arange(0, 3.0, 0.01)

0 commit comments

Comments
 (0)