{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tooltip Customization\n",
"\n",
"A few examples of tooltip configuring in *Lets-Plot* via the 'tooltips' parameter and 'theme()' function. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.682627Z",
"iopub.status.busy": "2025-11-05T13:38:56.682531Z",
"iopub.status.idle": "2025-11-05T13:38:56.685784Z",
"shell.execute_reply": "2025-11-05T13:38:56.685577Z"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"from lets_plot import *"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.686810Z",
"iopub.status.busy": "2025-11-05T13:38:56.686738Z",
"iopub.status.idle": "2025-11-05T13:38:56.688391Z",
"shell.execute_reply": "2025-11-05T13:38:56.688232Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
\n",
" \n",
" "
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"LetsPlot.setup_html()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.701882Z",
"iopub.status.busy": "2025-11-05T13:38:56.701741Z",
"iopub.status.idle": "2025-11-05T13:38:56.795615Z",
"shell.execute_reply": "2025-11-05T13:38:56.795429Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(234, 12)\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Unnamed: 0 | \n",
" manufacturer | \n",
" model | \n",
" displ | \n",
" year | \n",
" cyl | \n",
" trans | \n",
" drv | \n",
" cty | \n",
" hwy | \n",
" fl | \n",
" class | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 1 | \n",
" audi | \n",
" a4 | \n",
" 1.8 | \n",
" 1999 | \n",
" 4 | \n",
" auto(l5) | \n",
" f | \n",
" 18 | \n",
" 29 | \n",
" p | \n",
" compact | \n",
"
\n",
" \n",
" | 1 | \n",
" 2 | \n",
" audi | \n",
" a4 | \n",
" 1.8 | \n",
" 1999 | \n",
" 4 | \n",
" manual(m5) | \n",
" f | \n",
" 21 | \n",
" 29 | \n",
" p | \n",
" compact | \n",
"
\n",
" \n",
" | 2 | \n",
" 3 | \n",
" audi | \n",
" a4 | \n",
" 2.0 | \n",
" 2008 | \n",
" 4 | \n",
" manual(m6) | \n",
" f | \n",
" 20 | \n",
" 31 | \n",
" p | \n",
" compact | \n",
"
\n",
" \n",
" | 3 | \n",
" 4 | \n",
" audi | \n",
" a4 | \n",
" 2.0 | \n",
" 2008 | \n",
" 4 | \n",
" auto(av) | \n",
" f | \n",
" 21 | \n",
" 30 | \n",
" p | \n",
" compact | \n",
"
\n",
" \n",
" | 4 | \n",
" 5 | \n",
" audi | \n",
" a4 | \n",
" 2.8 | \n",
" 1999 | \n",
" 6 | \n",
" auto(l5) | \n",
" f | \n",
" 16 | \n",
" 26 | \n",
" p | \n",
" compact | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Unnamed: 0 manufacturer model displ year cyl trans drv cty hwy \\\n",
"0 1 audi a4 1.8 1999 4 auto(l5) f 18 29 \n",
"1 2 audi a4 1.8 1999 4 manual(m5) f 21 29 \n",
"2 3 audi a4 2.0 2008 4 manual(m6) f 20 31 \n",
"3 4 audi a4 2.0 2008 4 auto(av) f 21 30 \n",
"4 5 audi a4 2.8 1999 6 auto(l5) f 16 26 \n",
"\n",
" fl class \n",
"0 p compact \n",
"1 p compact \n",
"2 p compact \n",
"3 p compact \n",
"4 p compact "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mpg_df = pd.read_csv(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/mpg.csv\")\n",
"print(mpg_df.shape)\n",
"mpg_df.head()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.796653Z",
"iopub.status.busy": "2025-11-05T13:38:56.796584Z",
"iopub.status.idle": "2025-11-05T13:38:56.798675Z",
"shell.execute_reply": "2025-11-05T13:38:56.798498Z"
}
},
"outputs": [],
"source": [
"p = ggplot(mpg_df, aes(x='displ', y='cty', fill='drv', size='hwy')) + \\\n",
" scale_size(range=[5, 15], breaks=[15, 40]) + \\\n",
" ggsize(600, 350)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.799634Z",
"iopub.status.busy": "2025-11-05T13:38:56.799567Z",
"iopub.status.idle": "2025-11-05T13:38:56.830461Z",
"shell.execute_reply": "2025-11-05T13:38:56.830237Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Default tooltips.\n",
"p + geom_point(shape=21)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.831554Z",
"iopub.status.busy": "2025-11-05T13:38:56.831481Z",
"iopub.status.idle": "2025-11-05T13:38:56.836232Z",
"shell.execute_reply": "2025-11-05T13:38:56.836060Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# No tooltips.\n",
"p + geom_point(shape=21, tooltips=\"none\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.837084Z",
"iopub.status.busy": "2025-11-05T13:38:56.837013Z",
"iopub.status.idle": "2025-11-05T13:38:56.841551Z",
"shell.execute_reply": "2025-11-05T13:38:56.841377Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Change format for the \"size\" aesthetic which is already shown in the tooltip by default.\n",
"p + geom_point(shape=21,\n",
" tooltips=layer_tooltips().format('^size', '{.0f} mpg'))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.842246Z",
"iopub.status.busy": "2025-11-05T13:38:56.842174Z",
"iopub.status.idle": "2025-11-05T13:38:56.846936Z",
"shell.execute_reply": "2025-11-05T13:38:56.846761Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Show the vehicle \"class\" value in the tooltip (instead of the value of the \"size\" aesthetic).\n",
"p + geom_point(shape=21,\n",
" tooltips=layer_tooltips().line('@class'))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.847634Z",
"iopub.status.busy": "2025-11-05T13:38:56.847561Z",
"iopub.status.idle": "2025-11-05T13:38:56.853383Z",
"shell.execute_reply": "2025-11-05T13:38:56.853210Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Configure a multiline tooltip.\n",
"p + geom_point(shape=21,\n",
" tooltips=layer_tooltips()\n",
" .format('cty', '.0f')\n",
" .format('hwy', '.0f')\n",
" .format('drv', '{}wd')\n",
" .format('@year', 'd')\n",
" .line('@manufacturer @model')\n",
" .line('cty/hwy [mpg]|@cty/@hwy')\n",
" .line('@|@class')\n",
" .line('drive train|@drv')\n",
" .line('@|@year')) "
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.854105Z",
"iopub.status.busy": "2025-11-05T13:38:56.854036Z",
"iopub.status.idle": "2025-11-05T13:38:56.859437Z",
"shell.execute_reply": "2025-11-05T13:38:56.859266Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# List of variables to place in a multiline tooltip with the default formatting\n",
"p + geom_point(shape=21,\n",
" tooltips=layer_tooltips(['manufacturer', 'model', 'class', 'year']).format('@year', 'd')) "
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.860142Z",
"iopub.status.busy": "2025-11-05T13:38:56.860073Z",
"iopub.status.idle": "2025-11-05T13:38:56.865640Z",
"shell.execute_reply": "2025-11-05T13:38:56.865454Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Define the format for the variable from the list and specify an additional line\n",
"p + geom_point(shape=21,\n",
" tooltips=layer_tooltips(['manufacturer', 'model', 'class', 'drv'])\n",
" .format('drv', '{}wd')\n",
" .line('cty/hwy [mpg]|@cty/@hwy')) "
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.866369Z",
"iopub.status.busy": "2025-11-05T13:38:56.866299Z",
"iopub.status.idle": "2025-11-05T13:38:56.871724Z",
"shell.execute_reply": "2025-11-05T13:38:56.871550Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Anchor the tooltip in the top-right corner of the plot.\n",
"p + geom_point(shape=21,\n",
" tooltips=layer_tooltips()\n",
" .anchor('top_right')\n",
" .min_width(180)\n",
" .format('cty', '.0f')\n",
" .format('hwy', '.0f')\n",
" .format('drv', '{}wd')\n",
" .format('@year', 'd')\n",
" .line('@manufacturer @model')\n",
" .line('cty/hwy [mpg]|@cty/@hwy')\n",
" .line('@|@class')\n",
" .line('drive train|@drv')\n",
" .line('@|@year'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Side tooltips"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.872403Z",
"iopub.status.busy": "2025-11-05T13:38:56.872333Z",
"iopub.status.idle": "2025-11-05T13:38:56.877398Z",
"shell.execute_reply": "2025-11-05T13:38:56.877226Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"p2 = ggplot(mpg_df, aes('class','hwy')) + \\\n",
" theme(legend_position='none') + \\\n",
" ggsize(600, 350)\n",
"\n",
"# Default tooltips\n",
"p2 + geom_boxplot()"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.878022Z",
"iopub.status.busy": "2025-11-05T13:38:56.877952Z",
"iopub.status.idle": "2025-11-05T13:38:56.882469Z",
"shell.execute_reply": "2025-11-05T13:38:56.882299Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Configure text in side tootips using the 'format()' function.\n",
"p2 + geom_boxplot(tooltips=layer_tooltips()\n",
" .format('^Y', '{.0f}') # all Y-positionals (note: no 'labels')\n",
" .format('^middle', '.2f') # different precision for 'middle' (note: default 'label')\n",
" .format('^ymin', 'min: {}') # ymin/ymax aesthetics:\n",
" .format('^ymax', 'max: {}')) # - add custom 'label'; keep formatting that is current default (i.e. '.0f')"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.883098Z",
"iopub.status.busy": "2025-11-05T13:38:56.883028Z",
"iopub.status.idle": "2025-11-05T13:38:56.887695Z",
"shell.execute_reply": "2025-11-05T13:38:56.887524Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Replace side tooltips with an anchored \"general\" tooltip.\n",
"# The 'line()' function assigns aesthetic or 'variable' to a general multiline tooltip.\n",
"p2 + geom_boxplot(tooltips=layer_tooltips()\n",
" .anchor('top_center')\n",
" .format('^Y', '.0f')\n",
" .format('^middle', '.2f')\n",
" .line('@|^middle')\n",
" .line('lower/upper|^lower/^upper')\n",
" .line('min/max|^ymin/^ymax'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Showing constants in tooltip"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.888349Z",
"iopub.status.busy": "2025-11-05T13:38:56.888279Z",
"iopub.status.idle": "2025-11-05T13:38:56.889955Z",
"shell.execute_reply": "2025-11-05T13:38:56.889776Z"
}
},
"outputs": [],
"source": [
"def get_data(*, seed=42):\n",
" np.random.seed(seed)\n",
" return {'x': np.append(np.random.normal(0, 1, 100), np.random.normal(3, 1, 100)),\n",
" 'y': np.append(np.random.normal(0, 1, 100), np.random.normal(3, 1, 100))}\n",
"\n",
"data = get_data()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.890559Z",
"iopub.status.busy": "2025-11-05T13:38:56.890484Z",
"iopub.status.idle": "2025-11-05T13:38:56.894538Z",
"shell.execute_reply": "2025-11-05T13:38:56.894363Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# By default tooltip never shows values defined via layer parameters (constants).\n",
"# Still, these values can be added to a layer tooltip using the 'layer_tooltips()' function.\n",
"ggplot(data, aes('x', 'y')) + \\\n",
" geom_point() + \\\n",
" geom_vline(xintercept=np.mean(data['x']), color=\"red\", linetype=\"dashed\", size=1,\n",
" tooltips=layer_tooltips()\n",
" .format('^xintercept', '.4f')\n",
" .line('mean = ^xintercept'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Some other examples"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:56.895181Z",
"iopub.status.busy": "2025-11-05T13:38:56.895112Z",
"iopub.status.idle": "2025-11-05T13:38:57.222444Z",
"shell.execute_reply": "2025-11-05T13:38:57.222127Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(150, 5)\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" sepal_length | \n",
" sepal_width | \n",
" petal_length | \n",
" petal_width | \n",
" species | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 5.1 | \n",
" 3.5 | \n",
" 1.4 | \n",
" 0.2 | \n",
" setosa | \n",
"
\n",
" \n",
" | 1 | \n",
" 4.9 | \n",
" 3.0 | \n",
" 1.4 | \n",
" 0.2 | \n",
" setosa | \n",
"
\n",
" \n",
" | 2 | \n",
" 4.7 | \n",
" 3.2 | \n",
" 1.3 | \n",
" 0.2 | \n",
" setosa | \n",
"
\n",
" \n",
" | 3 | \n",
" 4.6 | \n",
" 3.1 | \n",
" 1.5 | \n",
" 0.2 | \n",
" setosa | \n",
"
\n",
" \n",
" | 4 | \n",
" 5.0 | \n",
" 3.6 | \n",
" 1.4 | \n",
" 0.2 | \n",
" setosa | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" sepal_length sepal_width petal_length petal_width species\n",
"0 5.1 3.5 1.4 0.2 setosa\n",
"1 4.9 3.0 1.4 0.2 setosa\n",
"2 4.7 3.2 1.3 0.2 setosa\n",
"3 4.6 3.1 1.5 0.2 setosa\n",
"4 5.0 3.6 1.4 0.2 setosa"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"iris_df = pd.read_csv(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/iris.csv\")\n",
"print(iris_df.shape)\n",
"iris_df.head()"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:57.223322Z",
"iopub.status.busy": "2025-11-05T13:38:57.223249Z",
"iopub.status.idle": "2025-11-05T13:38:57.242150Z",
"shell.execute_reply": "2025-11-05T13:38:57.241950Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Default density plot.\n",
"ggplot(iris_df) + \\\n",
" geom_area(aes(x='sepal_length', fill='species'), \n",
" stat='density', \n",
" color='white') + \\\n",
" ggsize(650, 300)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:57.243046Z",
"iopub.status.busy": "2025-11-05T13:38:57.242970Z",
"iopub.status.idle": "2025-11-05T13:38:57.259711Z",
"shell.execute_reply": "2025-11-05T13:38:57.259521Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Change tooltips content and move to the corner\n",
"ggplot(iris_df) + \\\n",
" geom_area(aes(x='sepal_length', fill='species'), \n",
" stat='density',\n",
" color='white',\n",
" tooltips=layer_tooltips()\n",
" .anchor('top_right')\n",
" .line('^fill')\n",
" .line('length|^x')\n",
" .line('density|^y')) + \\\n",
" ggsize(650, 300)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-05T13:38:57.260578Z",
"iopub.status.busy": "2025-11-05T13:38:57.260505Z",
"iopub.status.idle": "2025-11-05T13:38:57.276610Z",
"shell.execute_reply": "2025-11-05T13:38:57.276431Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Use '..density..' variable in the tooltip\n",
"ggplot(iris_df) + \\\n",
" geom_area(aes(x='sepal_length', fill='species'), \n",
" stat='density',\n",
" color='white',\n",
" tooltips=layer_tooltips()\n",
" .anchor('top_right')\n",
" .format('..density..', '.4f')\n",
" .line('density|@..density..')) + \\\n",
" ggsize(650, 300)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 4
}