How to use hovertemplate with Plotly Python via Pycall

I’d like to create this plotly example in Julia by using PyCall to access python plotly. Below is the code from the example converted to julia:

using PyCall
go = pyimport("plotly.graph_objects")
subplots = pyimport("plotly.subplots")

z1, z2, z3 = rand(7,7),rand(7,7),rand(7,7)
customdata = [z2; z3]
fig = subplots.make_subplots(1, 2, subplot_titles=["z1", "z2"])
fig.add_trace(go.Heatmap(
    z=z1,
    customdata=[z2; z3],
    hovertemplate="<b>z1:%{z:.3f}</b><br>z2:%{customdata[0]:.3f} <br>z3: %{customdata[1]:.3f} ",
    coloraxis="coloraxis1", name=""),
    1, 1)
fig.add_trace(go.Heatmap(
    z=z2,
    customdata=[z1; z3],
    hovertemplate="z1:%{customdata[0]:.3f} <br><b>z2:%{z:.3f}</b><br>z3: %{customdata[1]:.3f} ",
    coloraxis="coloraxis1", name=""),
    1, 2)
fig.update_layout(title_text="Hover to see the value of z1, z2 and z3 together")
fig.show()

When I hover over a point rather than looking like z2: 0.243 as desired I get z2:%{customdata[0]:.3f}. How can I get this example to work using PyCall?

I have tried hovertemplate=raw"<b>z1:%{z:.3f}</b>... in case something unusual was happening with the %, but this also doesn’t work.

Why are are you using Pycall as long as you can use PlotlyJS.jl?
I don’t know how are json serialized the arrays from a plotly code, via Pycall.
Julia arrays are column major, while Python ones are row major.
If they are serialized like those passed via PlotlyJS.jl, then for the subplot
in row=1, col=1, customdata should be defined as:

customdata=permutedims(cat(z2', z3', dims=3), (3,1,2))

and similarly for the subplot in row=1, col=2.
But if they are serialized in a pythonic way, i.e. with customdata defined
as:

customdata=np.stack((z2, z3), axis=-1)

you should adapt the code correspondingly.

I have run both cases (PlotlyJS.jl and plotly.py)
and this is the plot.

1 Like

This is a good question, I’ve tried numerous Julia plotting solutions but not found any to be as intuitive as the OOP approach of Plotly Python.

I cannot get the permutedims to work using PyCall. Perhaps this is simply a limitation of my unconventional workflow.

Try permutedims(cat(z2,z3; dims=3), (3,1,2)),
I.e. don’t transpose the matrices. If it doesn’t work, then try to save your fig as the json, and post here how the customdata is displayed.

1 Like

Unfortunately this hasn’t worked:

The code used
using PyCall
go = pyimport("plotly.graph_objects")
subplots = pyimport("plotly.subplots")

z1, z2, z3 = rand(7,7),rand(7,7),rand(7,7)
customdata = [z2; z3]
fig = subplots.make_subplots(1, 2, subplot_titles=["z1", "z2"])
fig.add_trace(go.Heatmap(
    z=z1,
    customdata=permutedims(cat(z2,z3; dims=3), (3,1,2)), 
    hovertemplate="<b>z1:%{z:.3f}</b><br>z2:%{customdata[0]:.3f} <br>z3: %{customdata[1]:.3f}",
    coloraxis="coloraxis1", name=""),
    1, 1)
fig.add_trace(go.Heatmap(
    z=z2,
    customdata=permutedims(cat(z1,z3; dims=3), (3,1,2)),
    hovertemplate="z1:%{customdata[0]:.3f} <br><b>z2:%{z:.3f}</b><br>z3: %{customdata[1]:.3f}",
    coloraxis="coloraxis1", name=""),
    1, 2)
fig.update_layout(title_text="Hover to see the value of z1, z2 and z3 together")
fig.show()

fig.write_json("test.json")

The json is rather long so I’ve put it in full as a gist, the customdata looks like

"customdata": [
    [
        [
            0.5805209079366938,
            0.4145465488645458,
            0.7488916153892086,
            0.23225747447580458,
            0.6264770747342089,
            0.7567610330366803,
            0.32916084714253446
        ],
        [
            0.2015062562850568,
            0.4135917837269064,
            0.16930646082906786,
            0.1745881009548762,
            0.1325398212462695,
            0.04406350966260275,
            0.5616925298962588
        ],
        [
            0.8159110467216402,
            0.13576374155942017,
            0.08083760578811439,
            0.5201333656078831,
            0.7837785097008303,
            0.14915796393952874,
            0.9400291375195705
        ],
        [
            0.1378231436577635,
            0.5929942496246132,
            0.9473896719538369,
            0.4616840811243895,
            0.5333473566594279,
            0.06172995592070063,
            0.4809335827073493
        ],
        [
            0.37780028857922965,
            0.43308987729445736,
            0.5064184440474073,
            0.725470956444381,
            0.9597526932511722,
            0.6513085078531982,
            0.1340930269426409
        ],
        [
            0.6937839132382566,
            0.5685646057999124,
            0.6104956285971378,
            0.621414306260652,
            0.002360146666188445,
            0.7656254673886753,
            0.26572661925095953
        ],
        [
            0.6409087183731356,
            0.9563299099457475,
            0.5259971837934101,
            0.6615364738436338,
            0.3509257897587722,
            0.3490037963147291,
            0.6629716335118017
        ]
    ],
    [
        [
            0.9649201218864953,
            0.21916662349844673,
            0.5531899995203727,
            0.7448071017070875,
            0.1785674632912978,
            0.10113844840419617,
            0.646186825244371
        ],
        [
            0.5477659883367494,
            0.697919975519172,
            0.16474136212455603,
            0.5012896772774581,
            0.7421155909730657,
            0.2546483235688095,
            0.12312792255812643
        ],
        [
            0.05966905638846021,
            0.27289011490395176,
            0.6990969896823758,
            0.2385454245547438,
            0.40163082837193265,
            0.7756651010814232,
            0.049250699800071684
        ],
        [
            0.7450827999984058,
            0.4845774560680899,
            0.14248259269902008,
            0.9872782254338011,
            0.20457442522269187,
            0.28431787691554167,
            0.02056202670215379
        ],
        [
            0.07378521255490389,
            0.0013557371016771347,
            0.459154954303597,
            0.2871300415587916,
            0.5683161887752379,
            0.25049146125235866,
            0.11849448778617544
        ],
        [
            0.08423470866345806,
            0.9999795922545266,
            0.8910123710017198,
            0.9415311112476029,
            0.822896594704122,
            0.7202498051568375,
            0.05499178822187689
        ],
        [
            0.3359137070920404,
            0.575472993955267,
            0.2270050158557153,
            0.09613539197838517,
            0.2835117001116986,
            0.1177908924733897,
            0.8270291410302797
        ]
    ]
],

Hopefully this is what you meant :slight_smile:

Yes, it is what I required, but due to the matrix size, (7,7), and its randomly generated elements, it is difficult to compare how 3d Julia and Python matrices are serialized.
Instead I took the simplest case

z1=z2=z3 = [1 2 3; 4 5 6]

respectively

z1=z2=z3=np.array([[1, 2, 3], [4, 5, 6]])

and ran both PlotlyJS https://gist.github.com/empet/c41a8b131687cc2584485ab47ca6ddf4, and plotly.py https://gist.github.com/empet/ba5a8d0678cd75cd2119f3b74077425c versions of the code generating a single heatmap, with the same customdata. Then I displayed the json serialization of each figure. Based on the notebooks with my experiments, you should compare further your json version with the two listed in notebooks, and decide how customdata must be defined when you are using Pycall.
Moreover, take into account that the PlotlyJS’s author added automatically in the json file the transpose, z’, of the matrix that defines a heatmap. That’s why I took now an example of matrix of size (2,3) to notice when there is a discordance between the size of z and the sizes o matrices involved in customdata.
It’s mind-blowing!!!

1 Like

Thank you for your analysis. I’ll have a look into how the matrices are passed, however, as you’ve demonstrated this is non-trivial. If it is excessively complex/brittle I might just do something like text = ["z: $z" for z in z1] removing the need for a hover template.