Skip to content

Commit 9c58dba

Browse files
authored
Merge pull request #13837 from meeseeksmachine/auto-backport-of-pr-8638-on-v3.1.x
Backport PR #8638 on branch v3.1.x (FIX: if bins input to hist is str, treat like no bins)
2 parents 502034a + 8eff016 commit 9c58dba

File tree

2 files changed

+73
-12
lines changed

2 files changed

+73
-12
lines changed

lib/matplotlib/axes/_axes.py

+53-12
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,30 @@
3636
from matplotlib.axes._base import _AxesBase, _process_plot_format
3737
from matplotlib.axes._secondary_axes import SecondaryAxis
3838

39+
try:
40+
from numpy.lib.histograms import histogram_bin_edges
41+
except ImportError:
42+
# this function is new in np 1.15
43+
def histogram_bin_edges(arr, bins, range=None, weights=None):
44+
# this in True for 1D arrays, and False for None and str
45+
if np.ndim(bins) == 1:
46+
return bins
47+
48+
if isinstance(bins, str):
49+
# rather than backporting the internals, just do the full
50+
# computation. If this is too slow for users, they can
51+
# update numpy, or pick a manual number of bins
52+
return np.histogram(arr, bins, range, weights)[1]
53+
else:
54+
if bins is None:
55+
# hard-code numpy's default
56+
bins = 10
57+
if range is None:
58+
range = np.min(arr), np.max(arr)
59+
60+
return np.linspace(*range, bins + 1)
61+
62+
3963
_log = logging.getLogger(__name__)
4064

4165

@@ -6649,9 +6673,6 @@ def hist(self, x, bins=None, range=None, density=None, weights=None,
66496673
if bin_range is not None:
66506674
bin_range = self.convert_xunits(bin_range)
66516675

6652-
# Check whether bins or range are given explicitly.
6653-
binsgiven = np.iterable(bins) or bin_range is not None
6654-
66556676
# We need to do to 'weights' what was done to 'x'
66566677
if weights is not None:
66576678
w = cbook._reshape_2D(weights, 'weights')
@@ -6676,22 +6697,42 @@ def hist(self, x, bins=None, range=None, density=None, weights=None,
66766697
"sets and %d colors were provided" % (nx, len(color)))
66776698
raise ValueError(error_message)
66786699

6679-
# If bins are not specified either explicitly or via range,
6680-
# we need to figure out the range required for all datasets,
6681-
# and supply that to np.histogram.
6682-
if not binsgiven and not input_empty:
6700+
hist_kwargs = dict()
6701+
6702+
# if the bin_range is not given, compute without nan numpy
6703+
# does not do this for us when guessing the range (but will
6704+
# happily ignore nans when computing the histogram).
6705+
if bin_range is None:
66836706
xmin = np.inf
66846707
xmax = -np.inf
66856708
for xi in x:
6686-
if len(xi) > 0:
6709+
if len(xi):
6710+
# python's min/max ignore nan,
6711+
# np.minnan returns nan for all nan input
66876712
xmin = min(xmin, np.nanmin(xi))
66886713
xmax = max(xmax, np.nanmax(xi))
6689-
bin_range = (xmin, xmax)
6714+
# make sure we have seen at least one non-nan and finite
6715+
# value before we reset the bin range
6716+
if not np.isnan([xmin, xmax]).any() and not (xmin > xmax):
6717+
bin_range = (xmin, xmax)
6718+
6719+
# If bins are not specified either explicitly or via range,
6720+
# we need to figure out the range required for all datasets,
6721+
# and supply that to np.histogram.
6722+
if not input_empty and len(x) > 1:
6723+
if weights is not None:
6724+
_w = np.concatenate(w)
6725+
else:
6726+
_w = None
6727+
6728+
bins = histogram_bin_edges(np.concatenate(x),
6729+
bins, bin_range, _w)
6730+
else:
6731+
hist_kwargs['range'] = bin_range
6732+
66906733
density = bool(density) or bool(normed)
66916734
if density and not stacked:
6692-
hist_kwargs = dict(range=bin_range, density=density)
6693-
else:
6694-
hist_kwargs = dict(range=bin_range)
6735+
hist_kwargs = dict(density=density)
66956736

66966737
# List to store all the top coordinates of the histograms
66976738
tops = []

lib/matplotlib/tests/test_axes.py

+20
Original file line numberDiff line numberDiff line change
@@ -6347,3 +6347,23 @@ def test_datetime_masked():
63476347
ax.plot(x, m)
63486348
# these are the default viewlim
63496349
assert ax.get_xlim() == (730120.0, 733773.0)
6350+
6351+
6352+
def test_hist_auto_bins():
6353+
_, bins, _ = plt.hist([[1, 2, 3], [3, 4, 5, 6]], bins='auto')
6354+
assert bins[0] <= 1
6355+
assert bins[-1] >= 6
6356+
6357+
6358+
def test_hist_nan_data():
6359+
fig, (ax1, ax2) = plt.subplots(2)
6360+
6361+
data = [1, 2, 3]
6362+
nan_data = data + [np.nan]
6363+
6364+
bins, edges, _ = ax1.hist(data)
6365+
with np.errstate(invalid='ignore'):
6366+
nanbins, nanedges, _ = ax2.hist(nan_data)
6367+
6368+
assert np.allclose(bins, nanbins)
6369+
assert np.allclose(edges, nanedges)

0 commit comments

Comments
 (0)