dcc.Tooltip

New in Dash 2.0

dcc.Tooltip gives you a tooltip pointing to a precise pixel
location on the page. It was designed primarily for greater flexibility over
the hover information built into dcc.Graph figures, but it can
be used with any component that draws diagrams or graphs on the page.

Here’s an example of creating a tooltip with images and text in them, loaded
by their URLs:

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.graph_objects as go
import pandas as pd

# Small molcule drugbank dataset
# Source: <a href="https://raw.githubusercontent.com/plotly/dash-sample-apps/main/apps/dash-drug-discovery/data/small_molecule_drugbank.csv'">https://raw.githubusercontent.com/plotly/dash-sample-apps/main/apps/dash-drug-discovery/data/small_molecule_drugbank.csv'</a>
data_path = 'datasets/small_molecule_drugbank.csv'

df = pd.read_csv(data_path, header=0, index_col=0)

fig = go.Figure(data=[
    go.Scatter(
        x=df["LOGP"],
        y=df["PKA"],
        mode="markers",
        marker=dict(
            colorscale='viridis',
            color=df["MW"],
            size=df["MW"],
            colorbar={"title": "Molecular&lt;br&gt;Weight"},
            line={"color": "#444"},
            reversescale=True,
            sizeref=45,
            sizemode="diameter",
            opacity=0.8,
        )
    )
])

# turn off native plotly.js hover effects - make sure to use
# hoverinfo="none" rather than "skip" which also halts events.
fig.update_traces(hoverinfo="none", hovertemplate=None)

fig.update_layout(
    xaxis=dict(title='Log P'),
    yaxis=dict(title='pkA'),
    plot_bgcolor='rgba(255,255,255,0.1)'
)

app = Dash(__name__)

app.layout = html.Div([
    dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True),
    dcc.Tooltip(id="graph-tooltip"),
])


@app.callback(
    Output("graph-tooltip", "show"),
    Output("graph-tooltip", "bbox"),
    Output("graph-tooltip", "children"),
    Input("graph-basic-2", "hoverData"),
)
def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update

    # demo only shows the first point, but other points may also be available
    pt = hoverData["points"][0]
    bbox = pt["bbox"]
    num = pt["pointNumber"]

    df_row = df.iloc[num]
    img_src = df_row['IMG_URL']
    name = df_row['NAME']
    form = df_row['FORM']
    desc = df_row['DESC']
    if len(desc) > 300:
        desc = desc[:100] + '...'

    children = [
        html.Div([
            html.Img(src=img_src, style={"width": "100%"}),
            html.H2(f"{name}", style={"color": "darkblue"}),
            html.P(f"{form}"),
            html.P(f"{desc}"),
        ], style={'width': '200px', 'white-space': 'normal'})
    ]

    return True, bbox, children


if __name__ == "__main__":
    app.run_server(debug=True)

Example Visualizing t-SNE Plot of MNIST Images

The following example visualizes the t-SNE results of handwritten digit images from the MNIST dataset,
with the images shown in the tooltips when hovered:

import io
import base64
import pickle

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.graph_objects as go

from PIL import Image

from sklearn.manifold import TSNE

# Contains 100 images for each digit from MNIST
mnist_path = 'datasets/mini-mnist-1000.pickle'

# Helper functions
def np_image_to_base64(im_matrix):
    im = Image.fromarray(im_matrix)
    buffer = io.BytesIO()
    im.save(buffer, format="jpeg")
    encoded_image = base64.b64encode(buffer.getvalue()).decode()
    im_url = "data:image/jpeg;base64, " + encoded_image
    return im_url

def load_mini_mnist():
    with open(mnist_path, 'rb') as f:
        data = pickle.load(f)
    return data

# Load the data
data = load_mini_mnist()
images = data['images']
labels = data['labels']

# Flatten image matrices from (28,28) to (784,)
flattenend_images = [i.flatten() for i in images]

# t-SNE Outputs a 3 dimensional point for each image
tsne = TSNE(
    random_state=123,
    n_components=3,
    verbose=0,
    perplexity=40,
    n_iter=300) \
    .fit_transform(flattenend_images)

# Color for each digit
color_map = {
    0: "#E52B50",
    1: "#9F2B68",
    2: "#3B7A57",
    3: "#3DDC84",
    4: "#FFBF00",
    5: "#915C83",
    6: "#008000",
    7: "#7FFFD4",
    8: "#E9D66B",
    9: "#007FFF",
}
colors = [color_map[label] for label in labels]

fig = go.Figure(data=[go.Scatter3d(
    x=tsne[:, 0],
    y=tsne[:, 1],
    z=tsne[:, 2],
    mode='markers',
    marker=dict(
        size=2,
        color=colors,
    )
)])

fig.update_traces(
    hoverinfo="none",
    hovertemplate=None,
)

app = Dash(__name__)

app.layout = html.Div(
    className="container",
    children=[
        dcc.Graph(id="graph-5", figure=fig, clear_on_unhover=True),
        dcc.Tooltip(id="graph-tooltip-5", direction='bottom'),
    ],
)

@app.callback(
    Output("graph-tooltip-5", "show"),
    Output("graph-tooltip-5", "bbox"),
    Output("graph-tooltip-5", "children"),
    Input("graph-5", "hoverData"),
)
def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update

    # demo only shows the first point, but other points may also be available
    hover_data = hoverData["points"][0]
    bbox = hover_data["bbox"]
    num = hover_data["pointNumber"]

    im_matrix = images[num]
    im_url = np_image_to_base64(im_matrix)
    children = [
        html.Div([
            html.Img(
                src=im_url,
                style={"width": "50px", 'display': 'block', 'margin': '0 auto'},
            ),
            html.P("MNIST Digit " + str(labels[num]), style={'font-weight': 'bold'})
        ])
    ]

    return True, bbox, children

if __name__ == "__main__":
    app.run_server(debug=True)

Using base64 Encoded Images

This example uses python PIL library to encode an image into base64 format and then
returns it from a callback:

import io
import base64

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px

from PIL import Image

data_x = [1,1,2,2]
data_y = [1,2,1,2]
fig = px.scatter(x=data_x, y=data_y)
fig.update_traces(
    hoverinfo="none",
    hovertemplate=None,
    marker=dict(size=30)
)
fig.update_layout(
    xaxis=dict(range=[-1,4]),
    yaxis=dict(range=[-1,4])
)

# Set up the app now
app = Dash(__name__)

app.layout = html.Div(
    className="container",
    children=[
        dcc.Graph(id="graph-2-dcc", figure=fig, clear_on_unhover=True),
        dcc.Tooltip(id="graph-tooltip-2", direction='bottom'),
    ],
)

@app.callback(
    Output("graph-tooltip-2", "show"),
    Output("graph-tooltip-2", "bbox"),
    Output("graph-tooltip-2", "children"),
    Output("graph-tooltip-2", "direction"),

    Input("graph-2-dcc", "hoverData"),
)
def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update, no_update

    # Load image with pillow
    image_path = 'dash_docs/assets/images/sample.jpg'
    im = Image.open(image_path)

    # dump it to base64
    buffer = io.BytesIO()
    im.save(buffer, format="jpeg")
    encoded_image = base64.b64encode(buffer.getvalue()).decode()
    im_url = "data:image/jpeg;base64, " + encoded_image

    # demo only shows the first point, but other points may also be available
    hover_data = hoverData["points"][0]
    bbox = hover_data["bbox"]

    # control the position of the tooltip
    y = hover_data["y"]
    direction = "bottom" if y > 1.5 else "top"

    children = [
        html.Img(
            src=im_url,
            style={"width": "150px"},
        ),
        html.P("Image from base64 string"),
    ]

    return True, bbox, children, direction

if __name__ == "__main__":
    app.run_server(debug=True)

Loading Text

The loading text of the tooltip can be set using loading_text, which is set “Loading…”
by default. Here’s an example that uses the loading_text parameter along with a frontend
callback.

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px
import time

data_x = [1,1,2,2]
data_y = [1,2,1,2]
fig = px.scatter(x=data_x, y=data_y)
fig.update_traces(
    hoverinfo="none",
    hovertemplate=None,
    marker=dict(size=30)
)

app = Dash(__name__)

app.layout = html.Div(
    className="container",
    children=[
        dcc.Graph(
            id="graph-4",
            figure=fig,
            clear_on_unhover=True),
        dcc.Tooltip(
            id="graph-tooltip-4",
            loading_text="LOADING",
            direction="bottom"),
    ],
)

# This callback is executed very quickly
app.clientside_callback(
    """
    function show_tooltip(hoverData) {
        if(!hoverData) {
            return [false, dash_clientside.no_update];
        }
        var pt = hoverData.points[0];
        return [true, pt.bbox];
    }
    """,
    Output("graph-tooltip-4", "show"),
    Output("graph-tooltip-4", "bbox"),
    Input("graph-4", "hoverData"),
)

# This callback is executed after 1s to simulate a long-running process
@app.callback(
    Output("graph-tooltip-4", "children"),
    Input("graph-4", "hoverData"),
)
def update_tooltip_content(hoverData):
    if hoverData is None:
        return no_update

    time.sleep(1)

    # Display the x0 and y0 coordinate
    bbox = hoverData["points"][0]["bbox"]
    return [
        html.P(f"x0={bbox['x0']}, y0={bbox['y0']}"),
    ]

if __name__ == "__main__":
    app.run_server(debug=True)

Styling Tooltip with Background and Border Color

The tooltips can be styled using the background_color and border_color parameters:

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px

data_x = [1,2,3]
data_y = [1,2,1]
fig = px.scatter(x=data_x, y=data_y)
fig.update_traces(
    hoverinfo="none",
    hovertemplate=None,
    marker=dict(size=30)
)

app = Dash(__name__)

app.layout = html.Div(
    className="container",
    children=[
        dcc.Graph(
            id="graph-3",
            figure=fig,
            clear_on_unhover=True),
        dcc.Tooltip(
            id="graph-tooltip-3",
            background_color="darkblue",
            border_color="blue"),
    ],
)

@app.callback(
    Output("graph-tooltip-3", "show"),
    Output("graph-tooltip-3", "bbox"),
    Output("graph-tooltip-3", "children"),
    Input("graph-3", "hoverData"),
)
def update_tooltip_content(hoverData):
    if hoverData is None:
        return no_update

    pt = hoverData["points"][0]
    bbox = pt["bbox"]

    children = [
        html.P(f"x: {pt['x']}, y: {pt['y']}")
    ]

    return True, bbox, children

if __name__ == "__main__":
    app.run_server(debug=True)

Tooltip Properties

Access this documentation in your Python terminal with:
```python

help(dash.dcc.Tooltip)
```

Our recommended IDE for writing Dash apps is Dash Enterprise’s
Data Science Workspaces,
which has typeahead support for Dash Component Properties.
Find out if your company is using
Dash Enterprise
.

children (list of or a singular dash component, string or number; optional):
The contents of the tooltip.

id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components in
an app.

className (string; default ''):
The class of the tooltip.

style (dict; optional):
The style of the tooltip.

bbox (dict; optional):
The bounding box coordinates of the item to label, in px relative to
the positioning parent of the Tooltip component.

bbox is a dict with keys:

show (boolean; default True):
Whether to show the tooltip.

direction (a value equal to: ‘top’, ‘right’, ‘bottom’ or ‘left’; default 'right'):
The side of the bbox on which the tooltip should open.

border_color (string; default '#d6d6d6'):
Color of the tooltip border, as a CSS color string.

background_color (string; default 'white'):
Color of the tooltip background, as a CSS color string.

loading_text (string; default 'Loading...'):
The text displayed in the tooltip while loading.

zindex (number; default 1):
The z-index CSS property to assign to the tooltip. Components with
higher values will be displayed on top of components with lower values.

targetable (boolean; default False):
Whether the tooltip itself can be targeted by pointer events. For
tooltips triggered by hover events, typically this should be left
False to avoid the tooltip interfering with those same events.

loading_state (dict; optional):
Object that holds the loading state object coming from dash-renderer.

loading_state is a dict with keys: