Put images inside bubbles

Is there a way to put images inside bubbles or represent bubbles with images?

For example, if I want to construct a bubble graph or a scatter plot about countries and their populations, can I have the countries’ flags as bubbles?

Ive read the documents about incorporating images, but there does not seem to be an option to use images this way, and I was wondering if someone managed to achieve this.

Thank you all for your time and help.

I don’t think you can do it automatically but you can use the Image interface to get to the expected result.

For instance you could do the following (in the example I put the round flag icons in the folder flags/png/512):

from PIL import Image
import plotly.express as px

df = px.data.gapminder().query("year==2007")

fig = px.scatter(
    df,
    x="lifeExp",
    y="gdpPercap",
    hover_name="country",
    hover_data=["lifeExp", "gdpPercap", "pop"]
)
fig.update_traces(marker_color="rgba(0,0,0,0)")

maxDim = df[["lifeExp", "gdpPercap"]].max().idxmax()
maxi = df[maxDim].max()
for i, row in df.iterrows():
    country = row['country'].replace(" ", "-")
    fig.add_layout_image(
        dict(
            source=Image.open(f"flags/png/512/{country}.png"),
            xref="x",
            yref="y",
            xanchor="center",
            yanchor="middle",
            x=row["lifeExp"],
            y=row["gdpPercap"],
            sizex=np.sqrt(row["pop"] / df["pop"].max()) * maxi * 0.2 + maxi * 0.05,
            sizey=np.sqrt(row["pop"] / df["pop"].max()) * maxi * 0.2 + maxi * 0.05,
            sizing="contain",
            opacity=0.8,
            layer="above"
        )
    )

fig.update_layout(height=600, width=1000, yaxis_range=[-5e3, 55e3], plot_bgcolor="#dfdfdf")

fig.show()

Which would give you the following:

12 Likes

Hey @RenaudLN

Wow what a nice solution… and it looks so darn cool! I think this would be a great example to add to the tutorial.

1 Like

Amazing, thank you so much! That was exactly what I was looking for.

Love this @RenaudLN :smile_cat:

I could add it to the tutorials but the issue is to have the round flag icons available for anyone trying out the tutorial. Maybe if I can find them hosted somewhere I’ll do that.

Well here we go, using a collection of rounded flags available on github (thanks matahombres). You’ll also need the iso-2 country code so here I used pycountry to do the conversion.

import plotly.express as px
import pycountry

iso3_to_iso2 = {c.alpha_3: c.alpha_2 for c in pycountry.countries}

df = px.data.gapminder().query("year==2007")
df["iso_alpha2"] = df["iso_alpha"].map(iso3_to_iso2)

fig = px.scatter(
    df,
    x="lifeExp",
    y="gdpPercap",
    hover_name="country",
    hover_data=["lifeExp", "gdpPercap", "pop"],
)
fig.update_traces(marker_color="rgba(0,0,0,0)")

minDim = df[["lifeExp", "gdpPercap"]].max().idxmax()
maxi = df[minDim].max()
for i, row in df.iterrows():
    country_iso = row["iso_alpha2"]
    fig.add_layout_image(
        dict(
            source=f"https://raw.githubusercontent.com/matahombres/CSS-Country-Flags-Rounded/master/flags/{country_iso}.png",
            xref="x",
            yref="y",
            xanchor="center",
            yanchor="middle",
            x=row["lifeExp"],
            y=row["gdpPercap"],
            sizex=np.sqrt(row["pop"] / df["pop"].max()) * maxi * 0.15 + maxi * 0.03,
            sizey=np.sqrt(row["pop"] / df["pop"].max()) * maxi * 0.15+ maxi * 0.03,
            sizing="contain",
            opacity=0.8,
            layer="above"
        )
    )

fig.update_layout(height=600, width=1000, plot_bgcolor="#dfdfdf", yaxis_range=[-5e3, 55e3])

fig.show()
2 Likes

just came here to say this really should find its way into the tutorials/docs. thanks for this solution!

1 Like

Is there a way to assign the image as a marker, without looping through each point in the df? This seems to slow things way down if you have a big df. Thanks!

This is really neat. Thank you.