How to customize hover-template on with what information to show
Asked Answered
X

4

39

Here is my dataset:

my demo dataset

After locking my dataframe by year and grouping by month, I proceed with calculating percentage increase/decrease as a new column; it ends up looking like this:

printing 3 dfs

Now for my Plotly plot I use this to display traces and add some hover info:

fig.add_trace(go.Scatter(x=group_dfff.Months, y=group_dfff.Amount, name=i,
                        hovertemplate='Price: $%{y:.2f}'+'<br>Week: %{x}'))

Now as you can see there is an argument hovertemplate where I can pass my x and y... However, I can't figure out how to include my PERC_CHANGE values in it too.

Question: How to include other wanted columns' values inside the hovertemplate? Specifically, How do I include PERC_CHANGE values as I shown desired output below:

desired hover template output

I solved my specific problem, check pic below (adding 3rd element it is, please see comments), however question remains the same as I do not see how to do this for 4th, 5th and so on elements. enter image description here

Xanthic answered 26/11, 2019 at 19:10 Comment(1)
So I figured my problem out for this specific scenraio... I had to add '<br>%Change: %{text}' and specifying in the brackets text=group_dfff.PERC_CHANGE - this worked as I wanted. However, text var is a builtin thingie so I am still not sure how would I go about adding let's say forth, fifth and more labels that I would want to have upon hovering the datapoint...Xanthic
D
104

For Plotly Express, you need to use the custom_data argument when you create the figure. For example:

fig = px.scatter(
    data_frame=df, 
    x='ColX', 
    y='ColY', 
    custom_data=['Col1', 'Col2', 'Col3']
)

and then modify it using update_traces and hovertemplate, referencing it as customdata. For example:

fig.update_traces(
    hovertemplate="<br>".join([
        "ColX: %{x}",
        "ColY: %{y}",
        "Col1: %{customdata[0]}",
        "Col2: %{customdata[1]}",
        "Col3: %{customdata[2]}",
    ])
)

This took a lot of trial and error to figure out, as it isn't well-documented, and the inconsistency between the custom_data and customdata is confusing.

Dusky answered 31/7, 2020 at 4:47 Comment(2)
When I was trying just now, I don't know why custom_data argument will remove all of the columns involved (in your case is Col1, Col2, Col3) to be displayed on the chart.Antilogy
Man plotly is cool, I just wish they designed documented the API a bit more carefully. Thanks a lot for sharing this!Undervest
B
16

I've actually had the similar problem, and trust me it took me 2 and a half hour to figure out. Let's understand with an example.

fig = make_subplots(rows=1,cols=2,subplot_titles=('First plot','Second plot'),
                   specs=[[{'type': 'scene'}, {'type': 'scene'}]])

fig.add_trace(go.Scatter3d(x=[0,1,2,3],y=[0,1,2,3],z=[0,1,2,3]), row=1,col=1)
fig.add_trace(go.Scatter3d(x=[0,1,2,3],y=[0,1,2,3], z=[0,1,2,3]), row=1,col=2)

fig.update_layout(title='Add Custom Data')

fig.show()

This will create simple two scatter3d plots, where hoverdata is x,y and z axis. Now you want to add the data m=[9,8,7,6,5] to first plot. you can parse m in text argument and add hovertemplate as well.

fig.add_trace(go.Scatter3d(x=[0,1,2,3],y=[0,1,2,3],z=[0,1,2,3],
                          text=[9,8,7,6], hovertemplate='<br>x:%{x}<br>y:%{y}<br>z:%{z}<br>m:%{text}'), row=1,col=1)

This should work just fine. But now we want to add one more list say n=[5,6,7,8] to the first plot (or any). We will use customdata argument this time.

fig.add_trace(go.Scatter3d(x=[0,1,2,3],y=[0,1,2,3],z=[0,1,2,3],
                          text=[9,8,7,6],customdata=[5,6,7,8],
                          hovertemplate='<br>x:%{x}<br>y:%{y}<br>z:%{z}<br>m:%{text}<br>n:%{customdata}'), row=1,col=1)

Now what if we want to add our 3rd list of custom data. Here comes the tricky part. You cannot parse the list of two lists in the custom data, and then call customdata[0] and customdata[1], it's not that simple. our 3rd list is k=[2,4,6,8].

We need customdata=[[[5],[2]],[[6],[4]],[[7],[6]],[[8],[8]]] like this and it should work fine. Basically we need to give plotly a single list (or array) where in each element it's the list of all points you want to show.

fig.add_trace(go.Scatter3d(x=[0,1,2,3],y=[0,1,2,3],z=[0,1,2,3],
                          text=[9,8,7,6],customdata=[[[5],[2]],
                                                     [[6],[4]],
                                                     [[7],[6]],
                                                     [[8],[8]]],
                          hovertemplate='<br>x:%{x}<br>y:%{y}<br>z:%{z}<br>m:%{text}<br>n:%{customdata[0]}<br>k:%{customdata[1]}'), row=1,col=1)

We almost done, but there is one thing left. It's lots of work to manually create list like we given in customdata, therefore we'll automate it using powerful library import numpy as np

n = [5,6,7,8]
k = [2,4,6,8]

nk = np.empty(shape=(4,2,1), dtype='object')
nk[:,0] = np.array(n).reshape(-1,1)
nk[:,1] = np.array(k).reshape(-1,1)
fig.add_trace(go.Scatter3d(x=[0,1,2,3],y=[0,1,2,3],z=[0,1,2,3],
                          text=[9,8,7,6],customdata=nk,
                          hovertemplate='<br>x:%{x}<br>y:%{y}<br>z:%{z}<br>m:%{text}<br>n:%{customdata[0]}<br>k:%{customdata[1]}'), row=1,col=1)

BOOM ! You can parse df['Column name'] in place of np.array(n) if you want to add data directly from dataframe.

Bolyard answered 13/9, 2021 at 5:20 Comment(0)
M
10

Similar to the above, but I prefer to do the command all in one go, to use DataFrames all the way through, and to stick with Plotly rather than Plotly Express:

fig.add_trace(
    go.Scatter(
        x=group_dfff.Months,
        y=group_dfff.Amount,
        customdata=group_dfff.PERC_CHANGE,
        name=i,
        hovertemplate='<br>'.join([
            'Price: $%{y:.2f}',
            'Week: %{x}',
            'Percent Change: %{customdata}',
        ]),
    )
)

Note also that if you have multiple "custom data" fields (e.g. "A" and "B") in your DataFrame you'd like to include in the hoverdata, you can slightly modify the above to include as much data as you'd like:

fig.add_trace(
    go.Scatter(
        x=group_dfff.Months,
        y=group_dfff.Amount,
        customdata=group_dfff[['A', 'B']],
        name=i,
        hovertemplate='<br>'.join([
            'Price: $%{y:.2f}',
            'Week: %{x}',
            'Field A: %{customdata[0]}',
            'Field B: %{customdata[1]}',
        ]),
    )
)
Merkle answered 13/4, 2022 at 19:9 Comment(3)
Any way to use proper dict keys and not some dangerous int ordering thing? js version allows this properly in the plotly.graph_objects stuff so it must be possibleRowley
@mathtick Kinda. JS arrays are ordered but Python dicts are not, and AFAIK the interface layer only accepts HTML. You'd have to do a bit of work to make it happen, and it would end up being a bit clunkier than I prefer for what is essentially a static string - especially if you want to distinguish between DF columns and human-friendly labels, potentially-different formatting for each field in the hovertemplate, etc. If you anticipate doing this on a regular basis with different dataframes, traces, format options, etc... write a custom function which builds the go.Scatter() instance.Merkle
I had a similar problem - thanks for the solution! And just as an addition - this code shows all selected columns and their values in a hover: hovertemplate="<br>".join([f"{col}: %{{customdata[{idx}]}}" for idx, col in enumerate(selected.columns)]) where selected is a selection of the original pd.DataFrameRivi
K
5

You can add custom data to hovertemplate as :

hovertemplate = 'Price: $%{customdata[0]:.2f}'+'<br>Week: %{customdata[1]} ' 
+ '<br>Change: %{customdata[2]}'

where customdata can either be your group_dfff or even some other totally different data frame from which you want to fetch data for your hover info.

Here is the link to the documentation on plotly.

Killough answered 23/6, 2020 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.