Skip to content

Commit 5de931c

Browse files
committed
FIX: empty data assymetry
1 parent c56e3c5 commit 5de931c

File tree

5 files changed

+109
-25
lines changed

5 files changed

+109
-25
lines changed

lib/matplotlib/axes/_base.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -2857,8 +2857,8 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
28572857
if self.get_yscale() == 'log':
28582858
y_stickies = y_stickies[y_stickies > 0]
28592859

2860-
def handle_single_axis(scale, autoscaleon, shared_axes, interval,
2861-
minpos, axis, margin, stickies, set_bound):
2860+
def handle_single_axis(scale, autoscaleon, shared_axes, name,
2861+
axis, margin, stickies, set_bound):
28622862

28632863
if not (scale and autoscaleon):
28642864
return # nothing to do...
@@ -2870,12 +2870,16 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
28702870
x_values = []
28712871
minimum_minpos = np.inf
28722872
for ax in shared:
2873-
x_values.extend(getattr(ax.dataLim, interval))
2873+
x_values.extend(getattr(ax.dataLim, f"interval{name}"))
28742874
minimum_minpos = min(minimum_minpos,
2875-
getattr(ax.dataLim, minpos))
2875+
getattr(ax.dataLim, f"minpos{name}"))
28762876
x_values = np.extract(np.isfinite(x_values), x_values)
28772877
if x_values.size >= 1:
28782878
x0, x1 = (x_values.min(), x_values.max())
2879+
elif getattr(self._viewLim, f"mutated{name}")():
2880+
# No data, but explicit viewLims already set:
2881+
# in mutatedx or mutatedy.
2882+
return
28792883
else:
28802884
x0, x1 = (-np.inf, np.inf)
28812885
# If x0 and x1 are non finite, use the locator to figure out
@@ -2919,11 +2923,11 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
29192923
# End of definition of internal function 'handle_single_axis'.
29202924

29212925
handle_single_axis(
2922-
scalex, self._autoscaleXon, self._shared_x_axes, 'intervalx',
2923-
'minposx', self.xaxis, self._xmargin, x_stickies, self.set_xbound)
2926+
scalex, self._autoscaleXon, self._shared_x_axes, 'x',
2927+
self.xaxis, self._xmargin, x_stickies, self.set_xbound)
29242928
handle_single_axis(
2925-
scaley, self._autoscaleYon, self._shared_y_axes, 'intervaly',
2926-
'minposy', self.yaxis, self._ymargin, y_stickies, self.set_ybound)
2929+
scaley, self._autoscaleYon, self._shared_y_axes, 'y',
2930+
self.yaxis, self._ymargin, y_stickies, self.set_ybound)
29272931

29282932
def _get_axis_list(self):
29292933
return self.xaxis, self.yaxis

lib/matplotlib/axis.py

+11-15
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,7 @@ def update_units(self, data):
14571457
if default is not None and self.units is None:
14581458
self.set_units(default)
14591459

1460-
if neednew:
1460+
elif neednew:
14611461
self._update_axisinfo()
14621462
self.stale = True
14631463
return True
@@ -2267,19 +2267,17 @@ def set_inverted(self, inverted):
22672267
def set_default_intervals(self):
22682268
# docstring inherited
22692269
xmin, xmax = 0., 1.
2270-
dataMutated = self.axes.dataLim.mutatedx()
2271-
viewMutated = self.axes.viewLim.mutatedx()
2272-
if not dataMutated or not viewMutated:
2270+
# only change view if dataLim has not changed and user has
2271+
# not changed the view:
2272+
if (not self.axes.dataLim.mutatedx() and
2273+
not self.axes.viewLim.mutatedx()):
22732274
if self.converter is not None:
22742275
info = self.converter.axisinfo(self.units, self)
22752276
if info.default_limits is not None:
22762277
valmin, valmax = info.default_limits
22772278
xmin = self.converter.convert(valmin, self.units, self)
22782279
xmax = self.converter.convert(valmax, self.units, self)
2279-
if not dataMutated:
2280-
self.axes.dataLim.intervalx = xmin, xmax
2281-
if not viewMutated:
2282-
self.axes.viewLim.intervalx = xmin, xmax
2280+
self.axes.viewLim.intervalx = xmin, xmax
22832281
self.stale = True
22842282

22852283
def get_tick_space(self):
@@ -2532,19 +2530,17 @@ def set_inverted(self, inverted):
25322530
def set_default_intervals(self):
25332531
# docstring inherited
25342532
ymin, ymax = 0., 1.
2535-
dataMutated = self.axes.dataLim.mutatedy()
2536-
viewMutated = self.axes.viewLim.mutatedy()
2537-
if not dataMutated or not viewMutated:
2533+
# only change view if dataLim has not changed and user has
2534+
# not changed the view:
2535+
if (not self.axes.dataLim.mutatedy() and
2536+
not self.axes.viewLim.mutatedy()):
25382537
if self.converter is not None:
25392538
info = self.converter.axisinfo(self.units, self)
25402539
if info.default_limits is not None:
25412540
valmin, valmax = info.default_limits
25422541
ymin = self.converter.convert(valmin, self.units, self)
25432542
ymax = self.converter.convert(valmax, self.units, self)
2544-
if not dataMutated:
2545-
self.axes.dataLim.intervaly = ymin, ymax
2546-
if not viewMutated:
2547-
self.axes.viewLim.intervaly = ymin, ymax
2543+
self.axes.viewLim.intervaly = ymin, ymax
25482544
self.stale = True
25492545

25502546
def get_tick_space(self):
Binary file not shown.

lib/matplotlib/tests/test_dates.py

+43-1
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,55 @@ def test_date2num_NaT_scalar(units):
7070
assert np.isnan(tmpl)
7171

7272

73-
@image_comparison(['date_empty.png'])
7473
def test_date_empty():
7574
# make sure we do the right thing when told to plot dates even
7675
# if no date data has been presented, cf
7776
# http://sourceforge.net/tracker/?func=detail&aid=2850075&group_id=80706&atid=560720
7877
fig, ax = plt.subplots()
7978
ax.xaxis_date()
79+
fig.draw_no_output()
80+
np.testing.assert_allclose(ax.get_xlim(),
81+
[mdates.date2num(np.datetime64('2000-01-01')),
82+
mdates.date2num(np.datetime64('2010-01-01'))])
83+
84+
mdates._reset_epoch_test_example()
85+
mdates.set_epoch('0000-12-31')
86+
fig, ax = plt.subplots()
87+
ax.xaxis_date()
88+
fig.draw_no_output()
89+
np.testing.assert_allclose(ax.get_xlim(),
90+
[mdates.date2num(np.datetime64('2000-01-01')),
91+
mdates.date2num(np.datetime64('2010-01-01'))])
92+
mdates._reset_epoch_test_example()
93+
94+
95+
def test_date_not_empty():
96+
fig = plt.figure()
97+
ax = fig.add_subplot()
98+
99+
ax.plot([50, 70], [1, 2])
100+
ax.xaxis.axis_date()
101+
np.testing.assert_allclose(ax.get_xlim(), [50, 70])
102+
103+
104+
def test_axhline():
105+
# make sure that axhline doesn't set the xlimits...
106+
fig, ax = plt.subplots()
107+
ax.axhline(1.5)
108+
ax.plot([np.datetime64('2016-01-01'), np.datetime64('2016-01-02')], [1, 2])
109+
np.testing.assert_allclose(ax.get_xlim(),
110+
[mdates.date2num(np.datetime64('2016-01-01')),
111+
mdates.date2num(np.datetime64('2016-01-02'))])
112+
113+
mdates._reset_epoch_test_example()
114+
mdates.set_epoch('0000-12-31')
115+
fig, ax = plt.subplots()
116+
ax.axhline(1.5)
117+
ax.plot([np.datetime64('2016-01-01'), np.datetime64('2016-01-02')], [1, 2])
118+
np.testing.assert_allclose(ax.get_xlim(),
119+
[mdates.date2num(np.datetime64('2016-01-01')),
120+
mdates.date2num(np.datetime64('2016-01-02'))])
121+
mdates._reset_epoch_test_example()
80122

81123

82124
@image_comparison(['date_axhspan.png'])

lib/matplotlib/tests/test_units.py

+43-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ def default_units(value, axis):
6767
return None
6868

6969
qc.convert = MagicMock(side_effect=convert)
70-
qc.axisinfo = MagicMock(side_effect=lambda u, a: munits.AxisInfo(label=u))
70+
qc.axisinfo = MagicMock(side_effect=lambda u, a:
71+
munits.AxisInfo(label=u, default_limits=(0, 100)))
7172
qc.default_units = MagicMock(side_effect=default_units)
7273
return qc
7374

@@ -219,3 +220,44 @@ def test_shared_axis_categorical():
219220
ax2.plot(d2.keys(), d2.values())
220221
ax1.xaxis.set_units(UnitData(["c", "d"]))
221222
assert "c" in ax2.xaxis.get_units()._mapping.keys()
223+
224+
225+
def test_empty_default_limits(quantity_converter):
226+
munits.registry[Quantity] = quantity_converter
227+
fig, ax1 = plt.subplots()
228+
ax1.xaxis.update_units(Quantity([10], "miles"))
229+
fig.draw_no_output()
230+
assert ax1.get_xlim() == (0, 100)
231+
ax1.yaxis.update_units(Quantity([10], "miles"))
232+
fig.draw_no_output()
233+
assert ax1.get_ylim() == (0, 100)
234+
235+
fig, ax = plt.subplots()
236+
ax.axhline(30)
237+
ax.plot(Quantity(np.arange(0, 3), "miles"),
238+
Quantity(np.arange(0, 6, 2), "feet"))
239+
fig.draw_no_output()
240+
assert ax.get_xlim() == (0, 2)
241+
assert ax.get_ylim() == (0, 30)
242+
243+
fig, ax = plt.subplots()
244+
ax.axvline(30)
245+
ax.plot(Quantity(np.arange(0, 3), "miles"),
246+
Quantity(np.arange(0, 6, 2), "feet"))
247+
fig.draw_no_output()
248+
assert ax.get_xlim() == (0, 30)
249+
assert ax.get_ylim() == (0, 4)
250+
251+
fig, ax = plt.subplots()
252+
ax.xaxis.update_units(Quantity([10], "miles"))
253+
ax.axhline(30)
254+
fig.draw_no_output()
255+
assert ax.get_xlim() == (0, 100)
256+
assert ax.get_ylim() == (28.5, 31.5)
257+
258+
fig, ax = plt.subplots()
259+
ax.yaxis.update_units(Quantity([10], "miles"))
260+
ax.axvline(30)
261+
fig.draw_no_output()
262+
assert ax.get_ylim() == (0, 100)
263+
assert ax.get_xlim() == (28.5, 31.5)

0 commit comments

Comments
 (0)