Adding a flag to the end of a bar chart in python
Asked Answered
I

1

2

I was trying to follow an example outlined here https://stackoverflow.com/a/61973946

The code, after small adjustments looks like this:

def pos_image(x, y, pays, haut):
    pays = countries.get(pays).alpha2.lower()
    fichier = "iso-flag-png"
    fichier += f"/{pays}.png"
    im = mpimg.imread(fichier)
    ratio = 4 / 3
    w = ratio * haut
    print(w)
    ax.imshow(im,
              extent=(x - w, x, y, y + haut),
              zorder=2)


plt.style.use('seaborn')
fig, ax = plt.subplots()

liste_pays = [('France', 10), ('USA', 9), ('Spain', 5), ('Italy', 5)]

X = [p[1] for p in liste_pays]
Y = [p[0] for p in liste_pays]

haut = .8
r = ax.barh(y=Y, width=X, height=haut, zorder=1)
y_bar = [rectangle.get_y() for rectangle in r]
for pays, y in zip(liste_pays, y_bar):
    pos_image(pays[1], y, pays[0], haut)


plt.show()

However, the resulting plot looks like this enter image description here

Showing only the last value of the list. What am i doing wrong?

Thank you

Isahella answered 26/7, 2024 at 10:40 Comment(2)
Did you note the part of the answer that reads "Afterwards, the plt.xlim and plt.ylim need to be set explicitly (also because imshow messes with them.)"?Paranoiac
@Paranoiac indeed I did not see this when I wrote my answer here. I will add it for reference.Feu
F
1

I can reproduce your result. I am not exactly sure what's going wrong here: Either the answer that you refer to never worked in the first place or some matplotlib internals have changed since it was posted.

That said, here is the problem:

Once you call pos_image(), the internal call to ax.imshow() has the effect that the x and y limits are adjusted to the region where the flag is placed. The accepted answer to the same question actually also mentions this:

Afterwards, the plt.xlim and plt.ylim need to be set explicitly (also because imshow messes with them.)

And here is a solution (or workaround):

Remember the x and y limits before calling pos_image(), and adjust them again afterwards:

x_lim, y_lim = ax.get_xlim(), ax.get_ylim()
for pays, y in zip(liste_pays, y_bar):
    pos_image(pays[1], y, pays[0], haut)
ax.set_xlim(x_lim)
ax.set_ylim(y_lim)

Produces (I used the default style rather than 'seaborn'): barchart with correct(ed) limits

Feu answered 26/7, 2024 at 11:42 Comment(2)
Thank you @simon, a small followup question, how would dill with data that is larger then 10? so let's say we multiply the liste_pays by 10,000?Isahella
@NavotNaor I am not sure. The answer uses some scaling factors that are adjusted to the range of the order of 10 rather than 10,000. You would need to find the right values for these scaling factors, but I don't know which ones are the right ones.Feu

© 2022 - 2025 — McMap. All rights reserved.