Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hover_tooltips, hover_mode, hover_formatters opts to easily modify hover #6180

Merged
merged 26 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions examples/gallery/demos/bokeh/html_hover_tooltips.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import holoviews as hv\n",
"\n",
"hv.extension(\"bokeh\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This demo demonstrates how to build custom hover tooltips using HTML. The\n",
"tooltips are displayed when the user hovers over a point in the plot."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df = pd.DataFrame(\n",
" dict(\n",
" x=[1, 2, 3, 4, 5],\n",
" y=[2, 5, 8, 2, 7],\n",
" desc=[\"A\", \"b\", \"C\", \"d\", \"E\"],\n",
" imgs=[\n",
" \"https://docs.bokeh.org/static/snake.jpg\",\n",
" \"https://docs.bokeh.org/static/snake2.png\",\n",
" \"https://docs.bokeh.org/static/snake3D.png\",\n",
" \"https://docs.bokeh.org/static/snake4_TheRevenge.png\",\n",
" \"https://docs.bokeh.org/static/snakebite.jpg\",\n",
" ],\n",
" fonts=[\n",
" \"<i>italics</i>\",\n",
" \"<pre>pre</pre>\",\n",
" \"<b>bold</b>\",\n",
" \"<small>small</small>\",\n",
" \"<del>del</del>\",\n",
" ],\n",
" )\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare plot\n",
"\n",
"Having declared the tooltips' columns, we can reference them in the tooltips with `@`. Just be sure to pass *all the relevant columns* as extra `vdims` ."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"TOOLTIPS = \"\"\"\n",
" <div>\n",
" $label\n",
" <div>\n",
" <img\n",
" src=\"@imgs\" height=\"42\" alt=\"@imgs\" width=\"42\"\n",
" style=\"float: left; margin: 0px 15px 15px 0px;\"\n",
" border=\"2\"\n",
" ></img>\n",
" </div>\n",
" <div>\n",
" <span style=\"font-size: 17px; font-weight: bold;\">@desc</span>\n",
" <span style=\"font-size: 15px; color: #966;\">[$index]</span>\n",
" </div>\n",
" <div>\n",
" <span>@fonts{safe}</span>\n",
" </div>\n",
" <div>\n",
" <span style=\"font-size: 15px;\">Location</span>\n",
" <span style=\"font-size: 10px; color: #696;\">($x, $y)</span>\n",
" </div>\n",
" </div>\n",
"\"\"\"\n",
"\n",
"hv.Scatter(df, kdims=[\"x\"], vdims=[\"y\", \"desc\", \"imgs\", \"fonts\"], label=\"Pictures\").opts(\n",
" hover_tooltips=TOOLTIPS, size=20\n",
")"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
145 changes: 130 additions & 15 deletions examples/user_guide/Plotting_with_Bokeh.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Additionally, you can provide `'vline'`, the equivalent of passing `HoverTool(mode='vline')`, or `'hline'` to set the hit-testing behavior"
"Moreover, you can provide `'vline'`, the equivalent of passing `HoverTool(mode='vline')`, or `'hline'` to set the hit-testing behavior."
]
},
{
Expand All @@ -661,27 +661,142 @@
"metadata": {},
"outputs": [],
"source": [
"error = np.random.rand(100, 3)\n",
"heatmap_data = {(chr(65+i), chr(97+j)):i*j for i in range(5) for j in range(5) if i!=j}\n",
"data = [np.random.normal() for i in range(10000)]\n",
"hist = np.histogram(data, 20)\n",
"hv.Curve(np.arange(100)).opts(tools=[\"vline\"]) + hv.Curve(np.arange(100)).opts(tools=[\"hline\"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Equivalently, you may say `tools=[\"hover\"]` alongside `hover_mode`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"(\n",
" hv.Curve(np.arange(100)).opts(tools=[\"hover\"], hover_mode=\"vline\")\n",
" + hv.Curve(np.arange(100)).opts(tools=[\"hover\"], hover_mode=\"hline\")\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you'd like finer control on the formatting, you may use `hover_tooltips` to declare the tooltips as a list of tuples of the labels and a specification of the dimension name and how to display it.\n",
"\n",
"points = hv.Points(error)\n",
"heatmap = hv.HeatMap(heatmap_data).sort()\n",
"histogram = hv.Histogram(hist)\n",
"image = hv.Image(np.random.rand(50,50))\n",
"Behind the scenes, the `hover_tooltips` feature extends the capabilities of Bokeh's `HoverTool` tooltips by providing additional flexibility and customization options, so for a reference see the [bokeh user guide](https://bokeh.pydata.org/en/latest/docs/user_guide/tools.html#hovertool)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"hover_tooltips = [\n",
" ('Name', '@name'),\n",
" ('Symbol', '@symbol'),\n",
" ('CPK', '$color[hex, swatch]:CPK')\n",
"]\n",
"\n",
"(points + heatmap + histogram + image).opts(\n",
" opts.Points(tools=['hline'], size=5), opts.HeatMap(tools=['hover']),\n",
" opts.Image(tools=['vline']), opts.Histogram(tools=['hover']),\n",
" opts.Layout(shared_axes=False)).cols(2)"
"points.clone().opts(\n",
" tools=[\"hover\"], hover_tooltips=hover_tooltips, color='metal', cmap='Category20',\n",
" line_color='black', size=dim('atomic radius')/10,\n",
" width=600, height=400, show_grid=True,\n",
" title='Chemical Elements by Type (scaled by atomic radius)')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Unique from Bokeh's `HoverTool`, the HoloViews' `hover_tooltips` also supports a mix of string and tuple formats for defining tooltips, allowing for both direct references to data columns and customized display options.\n",
"\n",
"Additionally, you can include as many, or as little, dimension names as desired."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"hover_tooltips = [\n",
" \"name\", # will assume @name\n",
" (\"Symbol\", \"@symbol\"), # @ still required if tuple\n",
" ('CPK', '$color[hex, swatch]:CPK'),\n",
" \"density\"\n",
"]\n",
"\n",
"points.clone().opts(\n",
" tools=[\"hover\"], hover_tooltips=hover_tooltips, color='metal', cmap='Category20',\n",
" line_color='black', size=dim('atomic radius')/10,\n",
" width=600, height=400, show_grid=True,\n",
" title='Chemical Elements by Type (scaled by atomic radius)')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`hover_tooltips` also support displaying the HoloViews element's `label` and `group`.\n",
"\n",
"Keep in mind, to reference these special variables that are not based on the data, a prefix of `$` is required!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"a_curve = hv.Curve([0, 1, 2], label=\"A\", group=\"C\")\n",
"b_curve = hv.Curve([2, 1, 0], label=\"B\", group=\"C\")\n",
"(a_curve * b_curve).opts(\"Curve\", hover_tooltips=[\"$label\", \"$group\", \"@x\", \"y\"]) # $ is required, @ is not needed for string"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you need special formatting, you may also specify the formats inside `hover_tooltips` alongside `hover_formatters`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def datetime(x):\n",
" return np.array(x, dtype=np.datetime64)\n",
"\n",
"\n",
"df = pd.DataFrame(\n",
" {\n",
" \"date\": [\"2019-01-01\", \"2019-01-02\", \"2019-01-03\"],\n",
" \"adj_close\": [100, 101, 100000],\n",
" }\n",
")\n",
"\n",
"curve = hv.Curve((datetime(df[\"date\"]), df[\"adj_close\"]), \"date\", \"adj close\")\n",
"curve.opts(\n",
" hover_tooltips=[\"date\", (\"Close\", \"$@{adj close}{0.2f}\")], # use @{ } for dims with spaces\n",
" hover_formatters={\"@{adj close}\": \"printf\"}, # use 'printf' formatter for '@{adj close}' field\n",
" hover_mode=\"vline\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is also possible to explicitly declare the columns to display by manually constructing a `HoverTool` and declaring the tooltips as a list of tuples of the labels and a specification of the dimension name and how to display it (for a complete reference see the [bokeh user guide](https://bokeh.pydata.org/en/latest/docs/user_guide/tools.html#hovertool))."
"You can provide HTML strings too! See a demo [here](../gallery/demos/bokeh/html_hover_tooltips.ipynb), or explicitly declare the columns to display by manually constructing a Bokeh [`HoverTool`](https://bokeh.pydata.org/en/latest/docs/user_guide/tools.html#hovertool)."
]
},
{
Expand All @@ -695,7 +810,7 @@
"\n",
"points = hv.Points(\n",
" elements, ['electronegativity', 'density'],\n",
" ['name', 'symbol', 'metal', 'CPK', 'atomic radius']\n",
" ['name', 'symbol', 'metal', 'CPK', 'atomic radius'],\n",
").sort('metal')\n",
"\n",
"tooltips = [\n",
Expand Down
Loading
Loading