Add image at the background of a plot in Plotly

Viewed 74

I'm trying to plot a set of boxes on top of an image to express a characteristic of each of these boxes (colourfulness, to be precise).

My idea is to get something like this:

colourfulness_data

And, on hover, to get the colourfulness value of that specific box. Now, these boxes and the colourfulness of the part of the image contained inside of them are already calculated and stored in a DataFrame which looks like this:

"colourfulness_test (1).jpeg": [
    {
        "img_rect": [
            0.0,
            0.0,
            256.0,
            192.0
        ],
        "M": 40.86526507358546
    },
    {
        "img_rect": [
            256.0,
            0.0,
            512.0,
            192.0
        ],
        "M": 43.13601554186694
    },
    ... ]
}

The name of the column is the name of the file, and M is the colourfulness specified by the square (x0, y0, x1, y1). I'm trying to add the image on the background following the docs but there is a strange behaviour regarding the size. This is the snippet of code I'm using.

import plotly.graph_objects as go
from PIL import Image
fig = go.Figure()

# Add trace
# Instead of the whole dictionary of boxes, I'm using this tailored
# arrays with just two boxes to do small tests.
fig.add_trace(
    go.Scatter(
        x=[0, 200, 200, 0, 0, None, 500, 700, 700, 500, 500], 
        y=[0, 0, 200, 200, 0, None, 500, 500, 700, 700, 500], 
        customdata=[10,10,10,10,10,20,20,20,20,20,20],
        hovertemplate="%{customdata}")
)

fig.add_layout_image(
    dict(
        source=Image.open("./colourfulness_test (1).jpeg"),
        xref="x",
        yref="y",
        x=0,
        y=1536, 
        sizex=2048,
        sizey=1536,
        sizing="fill",
        opacity=0.5,
        layer="below"
    )
)

The image in the background is 2048 x 1536 (width x height). The width is set correctly, but somehow the height is not, and the image gets cut. I have to specify some random big height in sizey and y to get the picture in the right place.

This is how it looks if I set the height and width properly. The width of the picture is right, but height isn't.

enter image description here

This is the image I get if I set y to 4000 and sizey to 4000 as well (the image renders perfectly, respecting proportions, etc.).

enter image description here

1 Answers

It looks like sizex and sizey of the image are drawn relative to the x and y coordinates of the scatter plot, and since the scatter plot itself doesn't have equal scales on the x and y axes (notice that by default the yaxis is pretty compressed compared to the xaxis), this will also cause the background image to be compressed.

One thing you could try to fix this issue is hardcode the width and height of your plot to be the same number of pixels, and set the ranges of your x and y axes to match the dimensions of your image.

For example:

im = Image.open("./colourfulness_test (1).jpeg")
w, h = im.size

fig.update_layout(
    width=800, height=800,
    xaxis_range=[0, w],
    yaxis_range=[0, h],
)
Related