Plotly: Including additional data in hovertemplate
Asked Answered
A

5

14

enter image description here hovertemplate= 'Continent: %{df['continent']}
'+ 'Country: %{df['country']}
'+ 'gdpPercap: %{x:,.4f}
'+ 'lifeExp: %{y}'+ ''

I'm trying to use hovertemplate to customize hover information. However I can't get it to display what I want. I am getting x & y to work well. I can't figure out how to add other fields to the hovertemplate though. Any help would be appreciated.

import numpy as np
df = df[df['year'] == 1952]
customdata = np.stack((df['continent'], df['country']), axis=-1)
fig = go.Figure()
for i in df['continent'].unique():
    df_by_continent = df[df['continent'] == i]
    fig.add_trace(go.Scatter(x=df_by_continent['gdpPercap'], 
                         y=df_by_continent['lifeExp'],
                         mode='markers',
                         opacity=.7,
                         marker = {'size':15},
                         name=i,
                         hovertemplate=
                            'Continent: %{customdata[0]}<br>'+
                            'Country: %{customdata[1]}<br>'+
                            'gdpPercap: %{x:,.4f} <br>'+
                            'lifeExp: %{y}'+
                             '<extra></extra>',
                            ))
fig.update_layout(title="My Plot",
                 xaxis={'title':'GDP Per Cap',
                       'type':'log'},
                 yaxis={'title':'Life Expectancy'},
                )
fig.show()

Updated with more code. The first answer didn't work just returning the text value of comdata.

Ayotte answered 22/9, 2021 at 4:35 Comment(0)
S
19

See below for an additional example of how to use customdata with multiple traces based on the code included in your question. Note that you actually need to add the customdata to the figure traces in order to use it in the hovertemplate, this was also shown in Derek O's answer.

import numpy as np
import pandas as pd
import plotly.graph_objects as go

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
df = df[df['year'] == 1952]

fig = go.Figure()

for continent in df['continent'].unique():

    df_by_continent = df[df['continent'] == continent]

    fig.add_trace(
        go.Scatter(
            x=df_by_continent['gdpPercap'],
            y=df_by_continent['lifeExp'],
            customdata=np.stack((df_by_continent['country'], df_by_continent['pop']), axis=-1),
            mode='markers',
            opacity=0.7,
            marker={'size': 15},
            name=continent,
            hovertemplate='<b>Country</b>: %{customdata[0]}<br>' +
                          '<b>Population</b>: %{customdata[1]:,.0f}<br>' +
                          '<b>GDP</b>: %{x:$,.4f}<br>' +
                          '<b>Life Expectancy</b>: %{y:,.2f} Years' +
                          '<extra></extra>',
        )
    )

fig.update_layout(
    xaxis={'title': 'GDP Per Cap', 'type': 'log'},
    yaxis={'title': 'Life Expectancy'},
)

fig.write_html('fig.html', auto_open=True)

enter image description here

Sadden answered 22/9, 2021 at 19:53 Comment(4)
Thank you, I wasn't really understanding Derek O's answer but this helps it make more sense and worked.Ayotte
Is there some way to limit the length of a string in the customdata field? For example values in the pandas array that are 100+ characters and you want to (using hovertemplate) to limit the string printed to only 20?Leisha
@Leisha i don't think there's anyway to do that in plotly natively, but you can create a new column that truncates the existing column, and pass the new column to the customdata fieldLiverish
@DerekO I found a work around by using the hovertext field in the graph object and just creating a function which converts the information into the relevant list for plotting. There might be some speed impairment by doing this but for 2000+ points it is negligible compared to hovertemplate from my observations.Leisha
L
12

For any other variables besides {x} and {y} in the hovertemplate string, you'll want to create a variable called customdata which is a numpy array of the DataFrame columns (df['continent'], df['country'] in your case), and pass customdata=customdata to fig.update_layout. This is suggested by @empet in his Plotly forum answer here.

You can try something like:

import numpy as np
import pandas as pd
import plotly.express as px

df = px.data.gapminder()

customdata = np.stack((df['continent'], df['country']), axis=-1)

fig = px.scatter(df, x="gdpPercap", y="lifeExp")

hovertemplate = ('Continent: %{customdata[0]}<br>' + 
    'Country: %{customdata[1]}<br>' + 
    'gdpPercap: %{x:,.4f} <br>' + 
    'lifeExp: %{y}' + 
    '<extra></extra>')

fig.update_traces(customdata=customdata, hovertemplate=hovertemplate)
fig.show()

enter image description here

Liverish answered 22/9, 2021 at 5:18 Comment(6)
It didn't work for me. I'm getting the comdata text within my graph now.Ayotte
Derek O's answer is correct, your code is not working because you have not added the customdata to the figure traces.Sadden
Thank you! I understand it better now.Ayotte
This code is not working. I am getting KeyError: 'customdata'Newfashioned
@ShaunHan did you copy this code exactly? i just tried it and it still works for me – i'm using the latest version of plotlyLiverish
@DerekO OK I found out that it's due to string formatting. I have something like continent = 'Asia'; hovertemplate = (f'{continent}: %{customdata[0]}<br>') which doesn't work. However, if I do hovertemplate = (f'{continent}:' + '%{customdata[0]}<br>'), it works somehow. Not sure why.Newfashioned
E
1

A variation of the previous answers using just pandas/python:

customdata = list(df[['continent','country']].to_numpy())

Then compose your figure with a template referring to customdata as in the other answers. For variation here's an example with Scatter3D and adding data from two columns of a dataframe:

import plotly.graph_objects as go

customdata_set = list(df[['transaction','type']].to_numpy())

fig = go.Figure(
    data=[go.Scatter3d(x=df.time,
                       y=df.source,
                       z=df.dest,
                       hovertemplate='<i>Source:</i>: %{y:i}<br>' +
                       '<i>Destination:</i>: %{z:i}<br>' +
                       '<i>Amount:</i>: $%{text}<br>' +
                       '<i>Txn #:</i>: %{customdata[0]}<br>' +
                       '<i>Txn Type:</i>: %{customdata[1]}<br>' +
                       '<i>Date:</i>: %{x|%Y-%m-%d}',
                       text=(df.amount).to_numpy(),
                       customdata = customdata_set,
                       mode='markers',
                       marker=dict(
                            color=moat_sql.tx_amount,
                            size=4,
                            opacity=.8,
                            showscale=True,
                            colorscale='Viridis',
                            colorbar=dict(
                                title=dict(text='Log Txn Amount',
                                           side='bottom',
                                           font={'color': 'red'}
                                           )
                            )
    )
    )]
)
Entozoon answered 13/11, 2021 at 0:13 Comment(1)
If you want to access the 'color data' to show in the hovertemplate, you can via %{marker.color}Caltrop
S
1

Instead of using customdata + hovertemplate, you can just pass formatted text to the text parameter directly. I found this simpler, and more powerful - for example if you don't want the exact same formatting for all elements.

So this actually works:

text = your_df.map(
    lambda row: f'<i>Source:</i>: %{row.source:i}<br>' +
                    f'<i>Destination:</i>: %{row.z:i}<br>' +
                    f'<i>Amount:</i>: $%{row.amount}<br>' +
                    f'<i>Txn #:</i>: %{row.txn}<br>' +
                    f'<i>Txn Type:</i>: %{row.txn_type}<br>' +
                    f'<i>Date:</i>: %{row.date|%Y-%m-%d}',
    axis='columns'
)

go.Scatter3d(
   ...,
   text=text,
   ...
)

The text element doesn't support full HTML, but I've seen it support at least the <br> and <b> tags. It does not seem to support <h1>, <nbsp>, <hr> tags.

I believe the same is true for hovertemplate.

Shaunna answered 26/8, 2022 at 17:32 Comment(0)
H
1

here is an example in Javascript using Plotly.js in case anyone is looking for it.:

<!DOCTYPE html>
<html>
<head><script src="https://cdn.plot.ly/plotly-2.14.0.min.js"></script></head>
<body>
    <div id="myDiv" style="width: 100%; height: 100%;"></div>
    <script>
        // Define custom data
        const customData = [
            {
                x: [1, 2, 3],
                y: [4, 5, 6],
                z: ["Potato", "Banana", "Tomato"]
            }
        ];

        // Define custom hovertemplate
        const customHovertemplate = "X: %{x}<br>Y: %{y}<br>Z: %{customdata}";

        // Define trace using custom data and hovertemplate
        const trace = {
            x: customData[0].x,
            y: customData[0].y,
            customdata: customData[0].z,
            mode: "markers",
            marker: { color: "blue", size: 12 },
            type: "scatter",
            hovertemplate: customHovertemplate
        };

        Plotly.newPlot("myDiv", [trace]);
    </script>
</body>
</html>
Hessler answered 16/3, 2023 at 6:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.