hvplot.labels: TypeError: '<' not supported between instances of 'str' and 'int'
hvplot==0.8.1
A colleague of mine was trying to add labels to her plot. She got an exception that was hard to find the cause of. The problem was that she was using heterogenous data as text labels.
Here is a minimum, reproducible example.
import hvplot.pandas
import pandas as pd
df = pd.DataFrame({
"x": [1,2],
"y": [3,4],
"text": [0, "+1"],
})
df.hvplot.labels(x="x", y="y", text="text")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
File /opt/conda/lib/python3.10/site-packages/IPython/core/formatters.py:972, in MimeBundleFormatter.__call__(self, obj, include, exclude)
969 method = get_real_method(obj, self.print_method)
971 if method is not None:
--> 972 return method(include=include, exclude=exclude)
973 return None
974 else:
File /opt/conda/lib/python3.10/site-packages/holoviews/core/dimension.py:1294, in Dimensioned._repr_mimebundle_(self, include, exclude)
1287 def _repr_mimebundle_(self, include=None, exclude=None):
1288 """
1289 Resolves the class hierarchy for the class rendering the
1290 object using any display hooks registered on Store.display
1291 hooks. The output of all registered display_hooks is then
1292 combined and returned.
1293 """
-> 1294 return Store.render(self)
File /opt/conda/lib/python3.10/site-packages/holoviews/core/options.py:1426, in Store.render(cls, obj)
1424 data, metadata = {}, {}
1425 for hook in hooks:
-> 1426 ret = hook(obj)
1427 if ret is None:
1428 continue
File /opt/conda/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:277, in pprint_display(obj)
275 if not ip.display_formatter.formatters['text/plain'].pprint:
276 return None
--> 277 return display(obj, raw_output=True)
File /opt/conda/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:247, in display(obj, raw_output, **kwargs)
245 elif isinstance(obj, (CompositeOverlay, ViewableElement)):
246 with option_state(obj):
--> 247 output = element_display(obj)
248 elif isinstance(obj, (Layout, NdLayout, AdjointLayout)):
249 with option_state(obj):
File /opt/conda/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:141, in display_hook.<locals>.wrapped(element)
139 try:
140 max_frames = OutputSettings.options['max_frames']
--> 141 mimebundle = fn(element, max_frames=max_frames)
142 if mimebundle is None:
143 return {}, {}
File /opt/conda/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:187, in element_display(element, max_frames)
184 if type(element) not in Store.registry[backend]:
185 return None
--> 187 return render(element)
File /opt/conda/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:68, in render(obj, **kwargs)
65 if renderer.fig == 'pdf':
66 renderer = renderer.instance(fig='png')
---> 68 return renderer.components(obj, **kwargs)
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/renderer.py:398, in Renderer.components(self, obj, fmt, comm, **kwargs)
395 embed = (not (dynamic or streams or self.widget_mode == 'live') or config.embed)
397 if embed or config.comms == 'default':
--> 398 return self._render_panel(plot, embed, comm)
399 return self._render_ipywidget(plot)
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/renderer.py:405, in Renderer._render_panel(self, plot, embed, comm)
403 doc = Document()
404 with config.set(embed=embed):
--> 405 model = plot.layout._render_model(doc, comm)
406 if embed:
407 return render_model(model, comm)
File /opt/conda/lib/python3.10/site-packages/panel/viewable.py:507, in Renderable._render_model(self, doc, comm)
505 if comm is None:
506 comm = state._comm_manager.get_server_comm()
--> 507 model = self.get_root(doc, comm)
509 if config.embed:
510 embed_state(self, model, doc,
511 json=config.embed_json,
512 json_prefix=config.embed_json_prefix,
513 save_path=config.embed_save_path,
514 load_path=config.embed_load_path,
515 progress=False)
File /opt/conda/lib/python3.10/site-packages/panel/viewable.py:558, in Renderable.get_root(self, doc, comm, preprocess)
541 """
542 Returns the root model and applies pre-processing hooks
543
(...)
555 Returns the bokeh model corresponding to this panel object
556 """
557 doc = init_doc(doc)
--> 558 root = self._get_model(doc, comm=comm)
559 if preprocess:
560 self._preprocess(root)
File /opt/conda/lib/python3.10/site-packages/panel/layout/base.py:146, in Panel._get_model(self, doc, root, parent, comm)
144 if root is None:
145 root = model
--> 146 objects = self._get_objects(model, [], doc, root, comm)
147 props = dict(self._init_params(), objects=objects)
148 model.update(**self._process_param_change(props))
File /opt/conda/lib/python3.10/site-packages/panel/layout/base.py:131, in Panel._get_objects(self, model, old_objects, doc, root, comm)
129 else:
130 try:
--> 131 child = pane._get_model(doc, root, model, comm)
132 except RerenderError:
133 return self._get_objects(model, current_objects[:i], doc, root, comm)
File /opt/conda/lib/python3.10/site-packages/panel/pane/holoviews.py:248, in HoloViews._get_model(self, doc, root, parent, comm)
246 plot = self.object
247 else:
--> 248 plot = self._render(doc, comm, root)
250 plot.pane = self
251 backend = plot.renderer.backend
File /opt/conda/lib/python3.10/site-packages/panel/pane/holoviews.py:324, in HoloViews._render(self, doc, comm, root)
321 if comm:
322 kwargs['comm'] = comm
--> 324 return renderer.get_plot(self.object, **kwargs)
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/bokeh/renderer.py:70, in BokehRenderer.get_plot(self_or_cls, obj, doc, renderer, **kwargs)
63 @bothmethod
64 def get_plot(self_or_cls, obj, doc=None, renderer=None, **kwargs):
65 """
66 Given a HoloViews Viewable return a corresponding plot instance.
67 Allows supplying a document attach the plot to, useful when
68 combining the bokeh model with another plot.
69 """
---> 70 plot = super().get_plot(obj, doc, renderer, **kwargs)
71 if plot.document is None:
72 plot.document = Document() if self_or_cls.notebook_context else curdoc()
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/renderer.py:240, in Renderer.get_plot(self_or_cls, obj, doc, renderer, comm, **kwargs)
237 defaults = [kd.default for kd in plot.dimensions]
238 init_key = tuple(v if d is None else d for v, d in
239 zip(plot.keys[0], defaults))
--> 240 plot.update(init_key)
241 else:
242 plot = obj
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/plot.py:948, in DimensionedPlot.update(self, key)
946 def update(self, key):
947 if len(self) == 1 and ((key == 0) or (key == self.keys[0])) and not self.drawn:
--> 948 return self.initialize_plot()
949 item = self.__getitem__(key)
950 self.traverse(lambda x: setattr(x, '_updated', True))
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/bokeh/element.py:1380, in ElementPlot.initialize_plot(self, ranges, plot, plots, source)
1378 element = self.hmap.last
1379 key = util.wrap_tuple(self.hmap.last_key)
-> 1380 ranges = self.compute_ranges(self.hmap, key, ranges)
1381 self.current_ranges = ranges
1382 self.current_frame = element
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/plot.py:607, in DimensionedPlot.compute_ranges(self, obj, key, ranges)
603 # Only compute ranges if not axiswise on a composite plot
604 # or not framewise on a Overlay or ElementPlot
605 if (not (axiswise and not isinstance(obj, HoloMap)) or
606 (not framewise and isinstance(obj, HoloMap))):
--> 607 self._compute_group_range(group, elements, ranges, framewise,
608 axiswise, robust, self.top_level,
609 prev_frame)
610 self.ranges.update(ranges)
611 return ranges
File /opt/conda/lib/python3.10/site-packages/holoviews/plotting/plot.py:717, in DimensionedPlot._compute_group_range(cls, group, elements, ranges, framewise, axiswise, robust, top_level, prev_frame)
715 data_range = ds.range(el_dim, dimension_range=False)
716 else:
--> 717 data_range = el.range(el_dim, dimension_range=False)
719 data_ranges[(el, el_dim)] = data_range
720 if dtype is not None and dtype.kind == 'uif' and robust:
File /opt/conda/lib/python3.10/site-packages/holoviews/core/data/__init__.py:204, in PipelineMeta.pipelined.<locals>.pipelined_fn(*args, **kwargs)
201 inst._in_method = True
203 try:
--> 204 result = method_fn(*args, **kwargs)
205 if PipelineMeta.disable:
206 return result
File /opt/conda/lib/python3.10/site-packages/holoviews/core/data/__init__.py:515, in Dataset.range(self, dim, data_range, dimension_range)
513 return dim.range
514 elif dim in self.dimensions() and data_range and bool(self):
--> 515 lower, upper = self.interface.range(self, dim)
516 else:
517 lower, upper = (np.NaN, np.NaN)
File /opt/conda/lib/python3.10/site-packages/holoviews/core/data/pandas.py:179, in PandasInterface.range(cls, dataset, dimension)
177 column = column.sort(inplace=False)
178 else:
--> 179 column = column.sort_values()
180 try:
181 column = column[~column.isin([None, pd.NA])]
File /opt/conda/lib/python3.10/site-packages/pandas/util/_decorators.py:331, in deprecate_nonkeyword_arguments.<locals>.decorate.<locals>.wrapper(*args, **kwargs)
325 if len(args) > num_allow_args:
326 warnings.warn(
327 msg.format(arguments=_format_argument_list(allow_args)),
328 FutureWarning,
329 stacklevel=find_stack_level(),
330 )
--> 331 return func(*args, **kwargs)
File /opt/conda/lib/python3.10/site-packages/pandas/core/series.py:3768, in Series.sort_values(self, axis, ascending, inplace, kind, na_position, ignore_index, key)
3766 # GH 35922. Make sorting stable by leveraging nargsort
3767 values_to_sort = ensure_key_mapped(self, key)._values if key else self._values
-> 3768 sorted_index = nargsort(values_to_sort, kind, bool(ascending), na_position)
3770 result = self._constructor(
3771 self._values[sorted_index], index=self.index[sorted_index]
3772 )
3774 if ignore_index:
File /opt/conda/lib/python3.10/site-packages/pandas/core/sorting.py:438, in nargsort(items, kind, ascending, na_position, key, mask)
436 non_nans = non_nans[::-1]
437 non_nan_idx = non_nan_idx[::-1]
--> 438 indexer = non_nan_idx[non_nans.argsort(kind=kind)]
439 if not ascending:
440 indexer = indexer[::-1]
TypeError: '<' not supported between instances of 'str' and 'int'
Thanks for the reproducible example!
@MarcSkovMadsen could you please not assign milestones and labels on hvPlot repo? I've been trying to careful curate them and I'm still in the process of doing so. I'll let you know once this is done and will make it clearer how it should be done. Thanks!
Same problem arises when using heterogeneous data column using hover_cols : df.hvplot(y='numeric',hover_cols=['heterogeneous']) with df:
| numeric | heterogeneous | |
|---|---|---|
| row1 | 0.0 | "string" |
| row2 | 1.0 | 0 |
quick user side fix using df = df.assign(heterogeneous=df.heterogeneous.astype('str'))
I just came across a similar situation using holoviews and had troubles debugging. It seem the issue above is not limited to hvplot (but I guess also the traceback indicates that), and not limited to when the hetereeogenous columns is actually used. I am on the following versions:
- pandas: 2.1.3
- holoviews: 1.18.1
- hvplot: 0.9.1
Your code example @MarcSkovMadsen converted to holoviews:
import pandas as pd
import holoviews as hv
hv.extension('bokeh')
df = pd.DataFrame({
"x": [1,2],
"y": [3,4],
"text": [0, "+1"],
})
hv.Points(df, ["x", "y"])
even though the heterogenous column is not part of the picture.
while if one exclude the column with heterogenous info entirely then there is no error.
hv.Points(df[["x", "y"]], ["x", "y"])
hv.Points(df, ["x", "y"]) use the text column as the vdims. You can see this by: print(hv.Points(df, ["x", "y"]))