Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add image annotations to bar plots

So, for example, let's say I have some data

countries = ["Norway", "Spain", "Germany", "Canada", "China"]
valuesA = [20, 15, 30, 5, 26]
valuesB = [1, 5, 3, 6, 2] 

and I do wanna plot them like

this.

How do I put those flag pictures in the graph (if it is even possbile)? And secondly, how can I automate this?

like image 914
Mnovdef Avatar asked May 29 '17 16:05

Mnovdef


People also ask

How do you add annotations to a bar plot in Python?

Our steps will be: Iterate over the bars. Get the x-axis position(x) and the width(w) of the bar this will help us to get the x coordinate of the text i.e. get_x()+get_width()/2. The y-coordinate(y) of the text can be found using the height of the bar i.e. get_height()

How do you annotate bars in grouped barplot in Python?

To add annotation, we first need to make grouped barplot before and then use Matplotlib's annotate function to add text for bars in grouped barplot. The “patches” attribute in Seaborn/Matplotlib object gives us access to each bar in barplot.

How do you annotate a bar plot in Seaborn?

To annotate bars in barplot made with Seaborn, we will use Matplotlib's annotate function. Matplotlib's annotate() function is pretty versatile and we can customize various aspects of annotation in a plot.


1 Answers

This solution will work for axes level plots produced with matplotlib, seaborn, and pandas.DataFrame.plot.

The main idea would be to separate the problem into small pieces:

  1. Get the flag as an array into the script. E.g.

     def get_flag(name):
         path = "path/to/flag/{}.png".format(name)
         im = plt.imread(path)
         return im
    
  2. Position an image at a certain position in a plot. This can be accomplished using an OffsetImage. An example can be found on the matplotlib page. Best use a function which takes the name of the country and the position as arguments and generates an AnnotationBbox with the OffsetImage inside.

  3. Drawing the barplot using ax.bar. To set the country names as ticklabels, use ax.set_ticklabels(countries). Then for every country place the OffsetImage from above using a loop.

(coord, 0) and xybox=(0., -16.) can be adjusted to place the image annotations at any location.

The final result may then look something like this:

enter image description here

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage,AnnotationBbox

def get_flag(name):
    path = "data/flags/Flags/flags/flags/24/{}.png".format(name.title())
    im = plt.imread(path)
    return im

def offset_image(coord, name, ax):
    img = get_flag(name)
    im = OffsetImage(img, zoom=0.72)
    im.image.axes = ax

    ab = AnnotationBbox(im, (coord, 0),  xybox=(0., -16.), frameon=False,
                        xycoords='data',  boxcoords="offset points", pad=0)

    ax.add_artist(ab)
    

countries = ["Norway", "Spain", "Germany", "Canada", "China"]
valuesA = [20, 15, 30, 5, 26]
 

fig, ax = plt.subplots()

ax.bar(range(len(countries)), valuesA, width=0.5,align="center")
ax.set_xticks(range(len(countries)))
ax.set_xticklabels(countries)
ax.tick_params(axis='x', which='major', pad=26)

for i, c in enumerate(countries):
    offset_image(i, c, ax)

plt.show()
like image 190
ImportanceOfBeingErnest Avatar answered Sep 30 '22 18:09

ImportanceOfBeingErnest