Skip to content

Commit dc3f787

Browse files
committed
FIX: allow flipped ylimits
1 parent 369618a commit dc3f787

File tree

3 files changed

+112
-17
lines changed

3 files changed

+112
-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: 87 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,7 @@ 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+
return mtransforms.nonsingular(vmin, vmax)
448450

449451

450452
class _ThetaShift(mtransforms.ScaledTranslation):
@@ -767,7 +769,6 @@ def __str__(self):
767769
def get_points(self):
768770
if self._invalid:
769771
points = self._viewLim.get_points().copy()
770-
771772
# Scale angular limits to work with Wedge.
772773
points[:, 0] *= 180 / np.pi
773774
if points[0, 0] > points[1, 0]:
@@ -992,8 +993,8 @@ def draw(self, *args, **kwargs):
992993
thetamin, thetamax = np.rad2deg(self._realViewLim.intervalx)
993994
if thetamin > thetamax:
994995
thetamin, thetamax = thetamax, thetamin
995-
rmin, rmax = self._realViewLim.intervaly - self.get_rorigin()
996-
996+
rmin, rmax = ((self._realViewLim.intervaly - self.get_rorigin()) *
997+
self.get_rsign())
997998
if isinstance(self.patch, mpatches.Wedge):
998999
# Backwards-compatibility: Any subclassed Axes might override the
9991000
# patch to not be the Wedge that PolarAxes uses.
@@ -1160,12 +1161,87 @@ def set_rorigin(self, rorigin):
11601161
def get_rorigin(self):
11611162
return self._originViewLim.y0
11621163

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

11701246
def get_rlabel_position(self):
11711247
"""

lib/matplotlib/tests/test_axes.py

Lines changed: 19 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)
@@ -738,6 +755,8 @@ def test_polar_theta_position():
738755
ax.set_theta_direction('clockwise')
739756

740757

758+
759+
741760
@image_comparison(baseline_images=['polar_rlabel_position'], style='default')
742761
def test_polar_rlabel_position():
743762
fig = plt.figure()

0 commit comments

Comments
 (0)