@@ -200,16 +200,34 @@ def _get_range(values, frac=0.2, factor=3.0):
200200
201201
202202def _get_safe_hist_range (values ):
203- # make sure numpy can find bin edges between the range low and high bounds
203+ # Get a safe min, max range for the histogram (the 'range' parameter of
204+ # np.histogram).
205+ #
206+ # This handles a corner case where the range of the data is very narrow and
207+ # there are less than 10 (the default number of bins) representable
208+ # floating-point numbers between the data min and max (with the precision
209+ # of the input column dtype). In this case numpy/matplotlib histogram with
210+ # default parameters fails, so we pass the 'range' parameter to extend it
211+ # slightly beyond the data range so that it is wide enough to contain 10
212+ # bins.
204213 if not len (values ) or not (
205214 np .issubdtype (values .dtype , np .floating )
206215 or np .issubdtype (values .dtype , np .integer )
207216 ):
217+ # empty or non-numeric inputs (datetimes) need no special handling.
208218 return None
209219 vmin , vmax = values .min (), values .max ()
210220 delta = max (np .spacing (vmin ), np .spacing (vmax ))
211221 if vmax - vmin > 12 * delta :
222+ # Min and max are far enough to divide the data range into 10 bins, we
223+ # can keep the default range=None.
224+ #
225+ # 12 is a bit conservative, 10 is probably enough, but there is no
226+ # harm in having the plot range slightly wider than is strictly
227+ # required.
212228 return None
229+ # Extend the range by 12 spacing steps (6 on each side) so the new range
230+ # can contain the bins.
213231 return vmin - 6 * delta , vmax + 6 * delta
214232
215233
0 commit comments