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

Lines changed: 53 additions & 12 deletions
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

Lines changed: 20 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy