Skip to content

Bars plot crashes with AttributeError when using datetime x-axis with single or duplicate values #6813

@ghostiee-11

Description

@ghostiee-11

Description

hv.Bars crashes with AttributeError: 'int' object has no attribute 'astype' when the datetime x-axis has either:

  1. A single data point
  2. 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

Image

Crash vs Working Comparison

Image

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions