Labels element raises an exception on matplotlib backend when the X axis is categorical
import holoviews as hv
hv.extension('matplotlib')
hv.Labels([("hello", 12, "text")])
# This is particularly problematic for this use case
hv.Bars([('hello', 10), ('world', 20)]) * hv.Labels([("hello", 12, "text")])
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~/venv-3.9/lib/python3.9/site-packages/matplotlib/axis.py in convert_units(self, x)
1499 try:
-> 1500 ret = self.converter.convert(x, self.units, self)
1501 except Exception as e:
~/venv-3.9/lib/python3.9/site-packages/matplotlib/category.py in convert(value, unit, axis)
48 if unit is None:
---> 49 raise ValueError(
50 'Missing category information for StrCategoryConverter; '
ValueError: Missing category information for StrCategoryConverter; this might be caused by unintendedly mixing categorical and numeric data
The above exception was the direct cause of the following exception:
ConversionError Traceback (most recent call last)
~/venv-3.9/lib/python3.9/site-packages/IPython/core/formatters.py in __call__(self, obj, include, exclude)
968
969 if method is not None:
--> 970 return method(include=include, exclude=exclude)
971 return None
972 else:
~/venv-3.9/lib/python3.9/site-packages/holoviews/core/dimension.py in _repr_mimebundle_(self, include, exclude)
1315 combined and returned.
1316 """
-> 1317 return Store.render(self)
1318
1319
~/venv-3.9/lib/python3.9/site-packages/holoviews/core/options.py in render(cls, obj)
1403 data, metadata = {}, {}
1404 for hook in hooks:
-> 1405 ret = hook(obj)
1406 if ret is None:
1407 continue
~/venv-3.9/lib/python3.9/site-packages/holoviews/ipython/display_hooks.py in pprint_display(obj)
280 if not ip.display_formatter.formatters['text/plain'].pprint:
281 return None
--> 282 return display(obj, raw_output=True)
283
284
~/venv-3.9/lib/python3.9/site-packages/holoviews/ipython/display_hooks.py in display(obj, raw_output, **kwargs)
250 elif isinstance(obj, (CompositeOverlay, ViewableElement)):
251 with option_state(obj):
--> 252 output = element_display(obj)
253 elif isinstance(obj, (Layout, NdLayout, AdjointLayout)):
254 with option_state(obj):
~/venv-3.9/lib/python3.9/site-packages/holoviews/ipython/display_hooks.py in wrapped(element)
144 try:
145 max_frames = OutputSettings.options['max_frames']
--> 146 mimebundle = fn(element, max_frames=max_frames)
147 if mimebundle is None:
148 return {}, {}
~/venv-3.9/lib/python3.9/site-packages/holoviews/ipython/display_hooks.py in element_display(element, max_frames)
190 return None
191
--> 192 return render(element)
193
194
~/venv-3.9/lib/python3.9/site-packages/holoviews/ipython/display_hooks.py in render(obj, **kwargs)
66 renderer = renderer.instance(fig='png')
67
---> 68 return renderer.components(obj, **kwargs)
69
70
~/venv-3.9/lib/python3.9/site-packages/holoviews/plotting/renderer.py in components(self, obj, fmt, comm, **kwargs)
448 return data, {}
449 else:
--> 450 html = self._figure_data(plot, fmt, as_script=True, **kwargs)
451 data['text/html'] = html
452
~/venv-3.9/lib/python3.9/site-packages/holoviews/plotting/mpl/renderer.py in _figure_data(self, plot, fmt, bbox_inches, as_script, **kwargs)
173 pass
174 bytes_io = BytesIO()
--> 175 fig.canvas.print_figure(bytes_io, **kw)
176 data = bytes_io.getvalue()
177
~/venv-3.9/lib/python3.9/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2228 else suppress())
2229 with ctx:
-> 2230 self.figure.draw(renderer)
2231
2232 if bbox_inches:
~/venv-3.9/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
72 @wraps(draw)
73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74 result = draw(artist, renderer, *args, **kwargs)
75 if renderer._rasterizing:
76 renderer.stop_rasterizing()
~/venv-3.9/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
49 renderer.start_filter()
50
---> 51 return draw(artist, renderer, *args, **kwargs)
52 finally:
53 if artist.get_agg_filter() is not None:
~/venv-3.9/lib/python3.9/site-packages/matplotlib/figure.py in draw(self, renderer)
2778
2779 self.patch.draw(renderer)
-> 2780 mimage._draw_list_compositing_images(
2781 renderer, self, artists, self.suppressComposite)
2782
~/venv-3.9/lib/python3.9/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
130 if not_composite or not has_images:
131 for a in artists:
--> 132 a.draw(renderer)
133 else:
134 # Composite any adjacent images together
~/venv-3.9/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
49 renderer.start_filter()
50
---> 51 return draw(artist, renderer, *args, **kwargs)
52 finally:
53 if artist.get_agg_filter() is not None:
~/venv-3.9/lib/python3.9/site-packages/matplotlib/_api/deprecation.py in wrapper(*inner_args, **inner_kwargs)
429 else deprecation_addendum,
430 **kwargs)
--> 431 return func(*inner_args, **inner_kwargs)
432
433 return wrapper
~/venv-3.9/lib/python3.9/site-packages/matplotlib/axes/_base.py in draw(self, renderer, inframe)
2919 renderer.stop_rasterizing()
2920
-> 2921 mimage._draw_list_compositing_images(renderer, self, artists)
2922
2923 renderer.close_group('axes')
~/venv-3.9/lib/python3.9/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
130 if not_composite or not has_images:
131 for a in artists:
--> 132 a.draw(renderer)
133 else:
134 # Composite any adjacent images together
~/venv-3.9/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
49 renderer.start_filter()
50
---> 51 return draw(artist, renderer, *args, **kwargs)
52 finally:
53 if artist.get_agg_filter() is not None:
~/venv-3.9/lib/python3.9/site-packages/matplotlib/text.py in draw(self, renderer)
677
678 with _wrap_text(self) as textobj:
--> 679 bbox, info, descent = textobj._get_layout(renderer)
680 trans = textobj.get_transform()
681
~/venv-3.9/lib/python3.9/site-packages/matplotlib/text.py in _get_layout(self, renderer)
291 of a rotated text when necessary.
292 """
--> 293 key = self.get_prop_tup(renderer=renderer)
294 if key in self._cached:
295 return self._cached[key]
~/venv-3.9/lib/python3.9/site-packages/matplotlib/text.py in get_prop_tup(self, renderer)
840 need to know if the text has changed.
841 """
--> 842 x, y = self.get_unitless_position()
843 renderer = renderer or self._renderer
844 return (x, y, self.get_text(), self._color,
~/venv-3.9/lib/python3.9/site-packages/matplotlib/text.py in get_unitless_position(self)
822 # This will get the position with all unit information stripped away.
823 # This is here for convenience since it is done in several locations.
--> 824 x = float(self.convert_xunits(self._x))
825 y = float(self.convert_yunits(self._y))
826 return x, y
~/venv-3.9/lib/python3.9/site-packages/matplotlib/artist.py in convert_xunits(self, x)
201 if ax is None or ax.xaxis is None:
202 return x
--> 203 return ax.xaxis.convert_units(x)
204
205 def convert_yunits(self, y):
~/venv-3.9/lib/python3.9/site-packages/matplotlib/axis.py in convert_units(self, x)
1500 ret = self.converter.convert(x, self.units, self)
1501 except Exception as e:
-> 1502 raise munits.ConversionError('Failed to convert value(s) to axis '
1503 f'units: {x!r}') from e
1504 return ret
ConversionError: Failed to convert value(s) to axis units: 'hello'
import holoviews as hv
hv.extension('bokeh')
hv.Bars([('hello', 10), ('world', 20)]) * hv.Labels([("hello", 12, "text")])
ALL software version info
holoviews 1.14.4
jupyterlab 2.3.1
matplotlib 3.4.2
bokeh 2.3.2
Description of expected behavior and the observed behavior
Labels element raises an exception on matplotlib backend when the X axis is categorical
Complete, minimal, self-contained example code that reproduces the issue
Stack traceback and/or browser JavaScript console output
Screenshots or screencasts of the bug in action
Works on bokeh as following, raises an exception on matplotlib: