-
-
Notifications
You must be signed in to change notification settings - Fork 414
Description
Description
hv.Bars crashes with AttributeError: 'int' object has no attribute 'astype' when the datetime x-axis has either:
- A single data point
- All identical x-values
This happens because the bar width calculation in BarPlot.get_data() replaces xdiff (a NumPy array) with the plain Python int 1 when the diff array is empty or all-zero, but then tries to call .astype('timedelta64[ms]') on it — which only works on NumPy arrays.
Reproduction
import holoviews as hv
import pandas as pd
hv.extension('bokeh')
# Case 1: Single datetime bar — crashes
hv.render(hv.Bars([(pd.Timestamp('2024-01-01'), 5)]))
# Case 2: Duplicate datetime x-values — crashes
hv.render(hv.Bars([(pd.Timestamp('2024-01-01'), 5), (pd.Timestamp('2024-01-01'), 3)]))
# Works fine: multiple bars with distinct datetime values
hv.render(hv.Bars((pd.date_range('2024-01-01', periods=3), [5, 3, 7])))
# Works fine: single bar with numeric (non-datetime) x-axis
hv.render(hv.Bars([(1, 5)]))Traceback
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "holoviews/util/__init__.py", line 878, in render
return renderer_obj.get_plot_state(obj)
File "holoviews/plotting/renderer.py", line 273, in get_plot_state
obj = self_or_cls.get_plot(obj=obj, renderer=renderer, **kwargs)
File "holoviews/plotting/bokeh/renderer.py", line 70, in get_plot
plot = super().get_plot(obj, doc, renderer, **kwargs)
File "holoviews/plotting/renderer.py", line 239, in get_plot
plot.update(init_key)
File "holoviews/plotting/plot.py", line 957, in update
return self.initialize_plot()
File "holoviews/plotting/bokeh/element.py", line 2221, in initialize_plot
self._init_glyphs(plot, element, ranges, source)
File "holoviews/plotting/bokeh/element.py", line 2121, in _init_glyphs
data, mapping, style = self.get_data(element, ranges, style)
File "holoviews/plotting/bokeh/chart.py", line 1065, in get_data
width *= xdiff.astype('timedelta64[ms]').astype(np.int64)
^^^^^^^^^^^^
AttributeError: 'int' object has no attribute 'astype'
Screenshots
Full Traceback
Crash vs Working Comparison
Root Cause
In holoviews/plotting/bokeh/chart.py lines 1060-1065:
xdiff = np.abs(np.diff(xvals[xslice]))
diff_size = len(np.unique(xdiff))
if diff_size == 0 or (diff_size == 1 and xdiff[0] == 0):
xdiff = 1 # <-- becomes a plain int
if is_dt:
width *= xdiff.astype('timedelta64[ms]').astype(np.int64) # <-- crash: int has no .astype()When there is only one x-value, np.diff() returns an empty array, so diff_size == 0 and xdiff is reassigned to the plain Python int 1. The subsequent .astype() call then fails because int doesn't have that method.
The non-datetime path (else branch on line 1067) also uses np.min(xdiff) on the scalar, but NumPy's np.min() handles scalars gracefully so that path doesn't crash.
Version Info
- HoloViews: main branch (1.23.0b1.dev)
- Bokeh: 3.x
- Python: 3.12
- OS: macOS
I've identified the root cause and have a fix ready. If this issue is confirmed, I'd be happy to open a PR with the fix along with test coverage for these edge cases.