diff --git a/doc/api/next_api_changes/2019-06-19-AL.rst b/doc/api/next_api_changes/2019-06-19-AL.rst new file mode 100644 index 000000000000..9d00100dc096 --- /dev/null +++ b/doc/api/next_api_changes/2019-06-19-AL.rst @@ -0,0 +1,10 @@ +log-scale bar() / hist() autolimits change +`````````````````````````````````````````` + +The autolimits computation in `~.Axes.bar` and `~.Axes.hist` when the axes +already uses log-scale has changed to match the computation when the axes is +switched to log-scale after the call to `~.Axes.bar` and `~.Axes.hist`, and +when calling ``bar(..., log=True)`` / ``hist(..., log=True)``: if there are +at least two different bar heights, add the normal axes margins to them (in +log-scale); if there is only a single bar height, expand the axes limits by one +order of magnitude around it and then apply axes margins. diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 44467581f446..ccda3de44657 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2303,20 +2303,12 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", label = kwargs.pop('label', '') tick_labels = kwargs.pop('tick_label', None) - adjust_ylim = False - adjust_xlim = False - y = bottom # Matches barh call signature. if orientation == 'vertical': - if bottom is None: - if self.get_yscale() == 'log': - adjust_ylim = True + if y is None: y = 0 - elif orientation == 'horizontal': if x is None: - if self.get_xscale() == 'log': - adjust_xlim = True x = 0 if orientation == 'vertical': @@ -2429,21 +2421,6 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", else: errorbar = None - if adjust_xlim: - xmin, xmax = self.dataLim.intervalx - xmin = min(w for w in width if w > 0) - if xerr is not None: - xmin = xmin - np.max(xerr) - xmin = max(xmin * 0.9, 1e-100) - self.dataLim.intervalx = (xmin, xmax) - - if adjust_ylim: - ymin, ymax = self.dataLim.intervaly - ymin = min(h for h in height if h > 0) - if yerr is not None: - ymin = ymin - np.max(yerr) - ymin = max(ymin * 0.9, 1e-100) - self.dataLim.intervaly = (ymin, ymax) self._request_autoscale_view() bar_container = BarContainer(patches, errorbar, label=label) @@ -6741,30 +6718,8 @@ def hist(self, x, bins=None, range=None, density=False, weights=None, if log: if orientation == 'horizontal': self.set_xscale('log', nonposx='clip') - logbase = self.xaxis._scale.base else: # orientation == 'vertical' self.set_yscale('log', nonposy='clip') - logbase = self.yaxis._scale.base - - # Setting a minimum of 0 results in problems for log plots - if np.min(bottom) > 0: - minimum = np.min(bottom) - elif density or weights is not None: - # For data that is normed to form a probability density, - # set to minimum data value / logbase - # (gives 1 full tick-label unit for the lowest filled bin) - ndata = np.array(tops) - minimum = (np.min(ndata[ndata > 0])) / logbase - else: - # For non-normed (density = False) data, - # set the min to 1 / log base, - # again so that there is 1 full tick-label unit - # for the lowest bin - minimum = 1.0 / logbase - - y[0], y[-1] = minimum, minimum - else: - minimum = 0 if align == 'left': x -= 0.5*(bins[1]-bins[0]) @@ -6785,8 +6740,6 @@ def hist(self, x, bins=None, range=None, density=False, weights=None, # set the top of this polygon y[1:2*len(bins)-1:2], y[2:2*len(bins):2] = (m + bottom, m + bottom) - if log: - y[y < minimum] = minimum if orientation == 'horizontal': xvals.append(y.copy()) yvals.append(x.copy()) @@ -6809,9 +6762,9 @@ def hist(self, x, bins=None, range=None, density=False, weights=None, for patch_list in patches: for patch in patch_list: if orientation == 'vertical': - patch.sticky_edges.y.append(minimum) + patch.sticky_edges.y.append(0) elif orientation == 'horizontal': - patch.sticky_edges.x.append(minimum) + patch.sticky_edges.x.append(0) # we return patches, so put it back in the expected order patches.reverse() diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_log_bottom.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_log_bottom.png deleted file mode 100644 index 8f45e3c8b473..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_log_bottom.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.pdf deleted file mode 100644 index ae9807cac00c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.png deleted file mode 100644 index ba9d2e1b2296..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.svg deleted file mode 100644 index e95ecae5ff8f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.svg +++ /dev/null @@ -1,3544 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index f7036342d720..281b0fefa5b4 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1628,6 +1628,22 @@ def test_hist_log(): ax.hist(data, fill=False, log=True) +@check_figures_equal(extensions=["png"]) +def test_hist_log_2(fig_test, fig_ref): + axs_test = fig_test.subplots(2, 3) + axs_ref = fig_ref.subplots(2, 3) + for i, histtype in enumerate(["bar", "step", "stepfilled"]): + # Set log scale, then call hist(). + axs_test[0, i].set_yscale("log") + axs_test[0, i].hist(1, 1, histtype=histtype) + # Call hist(), then set log scale. + axs_test[1, i].hist(1, 1, histtype=histtype) + axs_test[1, i].set_yscale("log") + # Use hist(..., log=True). + for ax in axs_ref[:, i]: + ax.hist(1, 1, log=True, histtype=histtype) + + @image_comparison(['hist_bar_empty.png'], remove_text=True) def test_hist_bar_empty(): # From #3886: creating hist from empty dataset raises ValueError @@ -1642,23 +1658,6 @@ def test_hist_step_empty(): ax.hist([], histtype='step') -@image_comparison(['hist_steplog'], remove_text=True, tol=0.1) -def test_hist_steplog(): - np.random.seed(0) - data = np.random.standard_normal(2000) - data += -2.0 - np.min(data) - data_pos = data + 2.1 - data_big = data_pos + 30 - weights = np.ones_like(data) * 1.e-5 - - axs = plt.figure().subplots(4) - axs[0].hist(data, 100, histtype='stepfilled', log=True) - axs[1].hist(data_pos, 100, histtype='stepfilled', log=True) - axs[2].hist(data, 100, weights=weights, histtype='stepfilled', log=True) - axs[3].hist(data_big, 100, histtype='stepfilled', log=True, - orientation='horizontal') - - @image_comparison(['hist_step_filled.png'], remove_text=True) def test_hist_step_filled(): np.random.seed(0) @@ -1686,29 +1685,6 @@ def test_hist_density(): ax.hist(data, density=True) -@image_comparison(['hist_step_log_bottom.png'], remove_text=True) -def test_hist_step_log_bottom(): - # check that bottom doesn't get overwritten by the 'minimum' on a - # log scale histogram (https://github.com/matplotlib/matplotlib/pull/4608) - np.random.seed(0) - data = np.random.standard_normal(2000) - fig = plt.figure() - ax = fig.add_subplot(111) - # normal hist (should clip minimum to 1/base) - ax.hist(data, bins=10, log=True, histtype='stepfilled', - alpha=0.5, color='b') - # manual bottom < 1/base (previously buggy, see #4608) - ax.hist(data, bins=10, log=True, histtype='stepfilled', - alpha=0.5, color='g', bottom=1e-2) - # manual bottom > 1/base - ax.hist(data, bins=10, log=True, histtype='stepfilled', - alpha=0.5, color='r', bottom=0.5) - # array bottom with some less than 1/base (should clip to 1/base) - ax.hist(data, bins=10, log=True, histtype='stepfilled', - alpha=0.5, color='y', bottom=np.arange(10)) - ax.set_ylim(9e-3, 1e3) - - def test_hist_unequal_bins_density(): # Test correct behavior of normalized histogram with unequal bins # https://github.com/matplotlib/matplotlib/issues/9557