From 18d25f92d941ac35386d9b24446219f5192f7335 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 28 May 2013 15:43:50 -0400 Subject: [PATCH 1/3] Correctly set the initial data limit bounding box to null limits rather than the unit bounding box. --- lib/matplotlib/axes.py | 10 +- .../baseline_images/test_scale/log_scales.pdf | Bin 2034 -> 1551 bytes .../baseline_images/test_scale/log_scales.png | Bin 5047 -> 4032 bytes .../baseline_images/test_scale/log_scales.svg | 492 ++---------------- lib/matplotlib/tests/test_axes.py | 11 + lib/matplotlib/tests/test_transforms.py | 6 +- lib/matplotlib/transforms.py | 12 +- 7 files changed, 62 insertions(+), 469 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index 1f93652e09dd..a57d440a5e14 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -522,7 +522,7 @@ def set_figure(self, fig): self.bbox = mtransforms.TransformedBbox(self._position, fig.transFigure) # these will be updated later as data is added - self.dataLim = mtransforms.Bbox.unit() + self.dataLim = mtransforms.Bbox.null() self.viewLim = mtransforms.Bbox.unit() self.transScale = mtransforms.TransformWrapper( mtransforms.IdentityTransform()) @@ -1625,13 +1625,16 @@ def relim(self): # Collections are deliberately not supported (yet); see # the TODO note in artists.py. self.dataLim.ignore(True) + self.dataLim.set_points(mtransforms.Bbox.null().get_points()) self.ignore_existing_data_limits = True + for line in self.lines: self._update_line_limits(line) for p in self.patches: self._update_patch_limits(p) + def update_datalim(self, xys, updatex=True, updatey=True): """ Update the data lim bbox with seq of xy tups or equiv. 2-D array @@ -8467,11 +8470,11 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, for x, y, c in reversed(zip(xvals, yvals, color)): if fill: patches.append(self.fill(x, y, - closed=False, + closed=True, facecolor=c)) else: patches.append(self.fill(x, y, - closed=False, edgecolor=c, + closed=True, edgecolor=c, fill=False)) # we return patches, so put it back in the expected order @@ -8531,6 +8534,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, self.set_autoscalex_on(_saved_autoscalex) self.set_autoscaley_on(_saved_autoscaley) + self.relim() self.autoscale_view() if nx == 1: diff --git a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.pdf b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.pdf index 24b284d9f7a709ceca0caa4713590a14ab9891e6..182416404c08cd80e6b428ef16aae31ace340b79 100644 GIT binary patch delta 618 zcmeyw-_NsQBV+wkZ@(i3JZ;}CUHt@p3O?VM+I)mBqJT-xsextoPP@F>FSq!mF)WNs z$@=~Mxm8}%zpE4Xe|$0D_DA!&>wI7C@18!Vq;~f86HERtSgZfeGkKlt;+BYof3HYp zTuS6DtgOi9kMYv@mBQlwdCL3CR?k^jM8brt`h+I^ulmCO&sp2{NBzp6FXd5QPZ<?N^LSRQ~pH+KR_BgIS(MoL;c{7*wcCYXVbHtIvrkRf|66KRd!D{z&1T zP^5i}%F=*EMlV)<%kV|p3~IG!qC*z z(8zSMF`F~9k)Gk?O1AiP0|P?^0}xQiQ{VzK3=AwR%`n6)4b3sdj4d$5Of50REDR>w gv-?OGSeRoNY-nI+IC(LX>5tpi}tG^o;06*;mod5s; delta 1105 zcmeC@`NY3rBV+vx@4Pz(0xsXJTKya*JaT_>O`7?pYTOf+p9%#`DzkU))7+?Px_V_< z(}C`f8&>@)ykZ>Wo%hdB_jCKrv-i`i?O(nAobtNf{`rn&zkco7&$j={f1SN`^Y?|F z|NJD@WMRaw)r%sx%{i^M#eDsjW6yJnYS|l;D_4J)KDzfnl6bM+&YSh^8JGS%KmDij zUugNS8QbUX`WbxJ>*KLoGio%?Elt+m;I-#v>Mx7``uujDUB{LQC2`nI`K)lDNcncv zmbYbFeD7%AlXZ`Y-Og-f%lYNs!j`+wH`HHS-ud-$&bh$u?a%LgnfYgT?a}%>;X&U- zuhuRt{}y`WRfF(3{pD+>#O7{av1NUI+|(0SwB|~M6m?H+-F9@f-{vhw?MoD+^~H`!`RtmwZPuP= zBFSsQI~mtbmgG%x5zbq1wR>W4)wR>&yve<4cYkDW-@5v{@9WfWuiGOQdzxRGW9*nI z^P;ESk;!Yng4$+{v&?ga6)OZ<8w9y|6F9Ma7= znzFWi@3~3=n}$RB>+%n(fOzXG1XLD%Q8p9}-XizSN;zpl$EE%wR!S~Q+vlFC5Kx{| zz#V1QeeH1Ea~lphhlk?9uC}MMY~PgHr8|IBZf-hzOxu=at}nkt&XGo-eY0ZURo^(> zQ_pUAh|~Piw3JDgoG(c7H?vHsGdz8D^I9P9X9>Hbl9#=Za}c}41xdkXmnn5B*EU8- zCRNS+sNiPt(Ct>)^W|SRT!-j#)OlsVY^6T!qJ{AXWkdJU1&nhA4Lw|5x+m?G3{0C9 zmuAx;=(nRVX?xt< zK9^7TK%CbUoGt}*oukhyAD}(UF8UaM=x+D-1DWQ+BNX^+V#ND3Q)VukF3F$NBAi$F zJm>06wvsyiTzBKM2lP7vf$E+gv6z*~_V3%7uZ7>IEU3=2+S?;1JT3Oo@AHZIzK_*6 zUA5cGIJGrl&*Ug(X=Y19!^suQ=Q#}x%?ynVjf^ZO2e3FZ8|zg}p2iZNZen4gU;qLN zc?w)$hJm56xg~~}2~Y*PIuj#9OfeH9OffU#$uX=x5{Aa6mdIwiY09Ol J>gw;t1pvc0@w5N{ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.png b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.png index 939961f0dcbc808a889adf9f310cc1f280f391ef..52bb6bd9a2b5d7a0a6573c39db1199bfc519b1e1 100644 GIT binary patch literal 4032 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 R!{=UL-#h#LDtu^J{{<7tw>ba+ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg index 9c6f9cfecafb..db0974b7495f 100644 --- a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg +++ b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg @@ -35,8 +35,8 @@ L393.006 43.2" style="fill:none;stroke:#0000ff;"/> +M315.491 256.775 +L518.4 256.775" style="fill:none;stroke:#0000ff;"/> @@ -134,550 +134,118 @@ L-4 0" id="m0d5b0a6425" style="stroke:#000000;stroke-linecap:butt;stroke-width:0 - + - + + + + - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index a812e3b14418..bf0d509725e4 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1610,6 +1610,17 @@ def make_patch_spines_invisible(ax): host.tick_params(axis='x', **tkw) +@cleanup +def test_vline_limit(): + fig = plt.figure() + ax = fig.gca() + ax.axvline(0.5) + ax.plot([-0.1, 0, 0.2, 0.1]) + (ymin, ymax) = ax.get_ylim() + assert ymin == -0.1 + assert ymax == 0.25 + + if __name__ == '__main__': import nose nose.runmodule(argv=['-s', '--with-doctest'], exit=False) diff --git a/lib/matplotlib/tests/test_transforms.py b/lib/matplotlib/tests/test_transforms.py index 54586d608c1a..95d28a3cbef3 100644 --- a/lib/matplotlib/tests/test_transforms.py +++ b/lib/matplotlib/tests/test_transforms.py @@ -359,7 +359,7 @@ def test_line_extent_axes_coords(self): # a simple line in axes coordinates ax = plt.axes() ax.plot([0.1, 1.2, 0.8], [0.9, 0.5, 0.8], transform=ax.transAxes) - np.testing.assert_array_equal(ax.dataLim.get_points(), np.array([[0, 0], [1, 1]])) + np.testing.assert_array_equal(ax.dataLim.get_points(), np.array([[np.inf, np.inf], [-np.inf, -np.inf]])) def test_line_extent_data_coords(self): # a simple line in data coordinates @@ -372,7 +372,7 @@ def test_line_extent_compound_coords1(self): ax = plt.axes() trans = mtrans.blended_transform_factory(ax.transAxes, ax.transData) ax.plot([0.1, 1.2, 0.8], [35, -5, 18], transform=trans) - np.testing.assert_array_equal(ax.dataLim.get_points(), np.array([[ 0., -5.], [ 1., 35.]])) + np.testing.assert_array_equal(ax.dataLim.get_points(), np.array([[ np.inf, -5.], [ -np.inf, 35.]])) plt.close() def test_line_extent_predata_transform_coords(self): @@ -388,7 +388,7 @@ def test_line_extent_compound_coords2(self): ax = plt.axes() trans = mtrans.blended_transform_factory(ax.transAxes, mtrans.Affine2D().scale(10) + ax.transData) ax.plot([0.1, 1.2, 0.8], [35, -5, 18], transform=trans) - np.testing.assert_array_equal(ax.dataLim.get_points(), np.array([[ 0., -50.], [ 1., 350.]])) + np.testing.assert_array_equal(ax.dataLim.get_points(), np.array([[ np.inf, -50.], [ -np.inf, 350.]])) plt.close() def test_line_extents_affine(self): diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index e2ff4ba3222d..ad3d7398ecf1 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -774,7 +774,7 @@ def __init__(self, points, **kwargs): BboxBase.__init__(self, **kwargs) points = np.asarray(points, np.float_) if points.shape != (2, 2): - raise ValueError('Bbox points must be of the form ' + raise ValueError('Bbox points must be of the form ' '"[[x0, y0], [x1, y1]]".') self._points = points self._minpos = np.array([0.0000001, 0.0000001]) @@ -804,6 +804,16 @@ def unit(): """ return Bbox(Bbox._unit_values.copy()) + _null_values = np.array([[np.inf, np.inf], [-np.inf, -np.inf]], np.float_) + + @staticmethod + def null(): + """ + (staticmethod) Create a new null :class:`Bbox` from (inf, inf) to + (-inf, -inf). + """ + return Bbox(Bbox._null_values.copy()) + @staticmethod def from_bounds(x0, y0, width, height): """ From a129662c26ae481a16f85fbcb4650d2ec1652e33 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 29 May 2013 11:58:18 -0400 Subject: [PATCH 2/3] Only do the strange autoscale on/off thing when doing a histogram bar plot --- lib/matplotlib/axes.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index a57d440a5e14..1980e5e9e20c 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -8293,14 +8293,6 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, else: w = [None]*nx - # Save autoscale state for later restoration; turn autoscaling - # off so we can do it all a single time at the end, instead - # of having it done by bar or fill and then having to be redone. - _saved_autoscalex = self.get_autoscalex_on() - _saved_autoscaley = self.get_autoscaley_on() - self.set_autoscalex_on(False) - self.set_autoscaley_on(False) - # Save the datalimits for the same reason: _saved_bounds = self.dataLim.bounds @@ -8358,6 +8350,14 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, patches = [] if histtype.startswith('bar'): + # Save autoscale state for later restoration; turn autoscaling + # off so we can do it all a single time at the end, instead + # of having it done by bar or fill and then having to be redone. + _saved_autoscalex = self.get_autoscalex_on() + _saved_autoscaley = self.get_autoscaley_on() + self.set_autoscalex_on(False) + self.set_autoscaley_on(False) + totwidth = np.diff(bins) if rwidth is not None: @@ -8407,6 +8407,10 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, bottom[:] = m boffset += dw + self.set_autoscalex_on(_saved_autoscalex) + self.set_autoscaley_on(_saved_autoscaley) + self.autoscale_view() + elif histtype.startswith('step'): # these define the perimeter of the polygon x = np.zeros(4 * len(bins) - 3, np.float) @@ -8532,11 +8536,6 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None, self.update_datalim( [(0, bins[0]), (0, bins[-1])], updatex=False) - self.set_autoscalex_on(_saved_autoscalex) - self.set_autoscaley_on(_saved_autoscaley) - self.relim() - self.autoscale_view() - if nx == 1: return n[0], bins, cbook.silent_list('Patch', patches[0]) else: From 412f1b39201889f580f502b4652e5387d5a98956 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 29 May 2013 11:58:37 -0400 Subject: [PATCH 3/3] Simplify handling of unit and null bboxes --- lib/matplotlib/transforms.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index ad3d7398ecf1..68491c3c3610 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -794,17 +794,13 @@ def invalidate(self): self._check(self._points) TransformNode.invalidate(self) - _unit_values = np.array([[0.0, 0.0], [1.0, 1.0]], np.float_) - @staticmethod def unit(): """ (staticmethod) Create a new unit :class:`Bbox` from (0, 0) to (1, 1). """ - return Bbox(Bbox._unit_values.copy()) - - _null_values = np.array([[np.inf, np.inf], [-np.inf, -np.inf]], np.float_) + return Bbox(np.array([[0.0, 0.0], [1.0, 1.0]], np.float)) @staticmethod def null(): @@ -812,7 +808,7 @@ def null(): (staticmethod) Create a new null :class:`Bbox` from (inf, inf) to (-inf, -inf). """ - return Bbox(Bbox._null_values.copy()) + return Bbox(np.array([[np.inf, np.inf], [-np.inf, -np.inf]], np.float)) @staticmethod def from_bounds(x0, y0, width, height):