diff --git a/packages/python/plotly/plotly/express/_core.py b/packages/python/plotly/plotly/express/_core.py index 437df83de7d..a1c14ae8846 100644 --- a/packages/python/plotly/plotly/express/_core.py +++ b/packages/python/plotly/plotly/express/_core.py @@ -1295,11 +1295,14 @@ def build_dataframe(args, constructor): # make copies of all the fields via dict() and list() for field in args: if field in array_attrables and args[field] is not None: - args[field] = ( - dict(args[field]) - if isinstance(args[field], dict) - else list(args[field]) - ) + if isinstance(args[field], dict): + args[field] = dict(args[field]) + elif field in ["custom_data", "hover_data"] and isinstance( + args[field], str + ): + args[field] = [args[field]] + else: + args[field] = list(args[field]) # Cast data_frame argument to DataFrame (it could be a numpy array, dict etc.) df_provided = args["data_frame"] is not None diff --git a/packages/python/plotly/plotly/express/_doc.py b/packages/python/plotly/plotly/express/_doc.py index 7984549c133..9db9ece315a 100644 --- a/packages/python/plotly/plotly/express/_doc.py +++ b/packages/python/plotly/plotly/express/_doc.py @@ -199,8 +199,8 @@ "Values from this column or array_like appear in bold in the hover tooltip.", ], hover_data=[ - "list of str or int, or Series or array-like, or dict", - "Either a list of names of columns in `data_frame`, or pandas Series,", + "str, or list of str or int, or Series or array-like, or dict", + "Either a name or list of names of columns in `data_frame`, or pandas Series,", "or array_like objects", "or a dict with column names as keys, with values True (for default formatting)", "False (in order to remove this column from hover information),", @@ -211,8 +211,8 @@ "Values from these columns appear as extra data in the hover tooltip.", ], custom_data=[ - colref_list_type, - colref_list_desc, + "str, or list of str or int, or Series or array-like", + "Either name or list of names of columns in `data_frame`, or pandas Series, or array_like objects", "Values from these columns are extra data, to be used in widgets or Dash callbacks for example. This data is not user-visible but is included in events emitted by the figure (lasso selection etc.)", ], text=[ diff --git a/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_hover.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_hover.py index c3de1ebf87e..26ee1a26198 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_hover.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_hover.py @@ -17,6 +17,17 @@ def test_skip_hover(): assert fig.data[0].hovertemplate == "species_id=%{marker.size}" +def test_hover_data_string_column(): + df = px.data.tips() + fig = px.scatter( + df, + x="tip", + y="total_bill", + hover_data="sex", + ) + assert "sex" in fig.data[0].hovertemplate + + def test_composite_hover(): df = px.data.tips() hover_dict = OrderedDict( @@ -89,17 +100,20 @@ def test_formatted_hover_and_labels(): def test_fail_wrong_column(): - with pytest.raises(ValueError) as err_msg: - px.scatter( - {"a": [1, 2], "b": [3, 4], "c": [2, 1]}, - x="a", - y="b", - hover_data={"d": True}, + # Testing for each of bare string, list, and basic dictionary + for hover_data_value in ["d", ["d"], {"d": True}]: + with pytest.raises(ValueError) as err_msg: + px.scatter( + {"a": [1, 2], "b": [3, 4], "c": [2, 1]}, + x="a", + y="b", + hover_data=hover_data_value, + ) + assert ( + "Value of 'hover_data_0' is not the name of a column in 'data_frame'." + in str(err_msg.value) ) - assert ( - "Value of 'hover_data_0' is not the name of a column in 'data_frame'." - in str(err_msg.value) - ) + # Testing other dictionary possibilities below with pytest.raises(ValueError) as err_msg: px.scatter( {"a": [1, 2], "b": [3, 4], "c": [2, 1]},