I was practicing with polar and came to this, Is it possible to put an image as the background of the graph (only of the graph)? In the example that I put and by which I was guided by the link , the image is put but as the background of the entire plane.
(If you run the code, an image will be downloaded, which is the one I use in the background, if you don't want that, change where it says url_image = '' and put the address of one you have)
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from math import pi
import seaborn as sns
import matplotlib.image as mpimg
import requests
%matplotlib inline
df = pd.DataFrame({
'Cero': ['Uno'],
'Uno': [20],
'Dos': [30],
'Tres': [40],
'Cuatro': [50],
'Cinco': [60],
'Seis': [70],
'Siete': [80],
'Ocho': [90],
'Nueve': [100]
})
url_imagen = "https://store-images.s-
microsoft.com/image/apps.6102.13510798887356280.9398b0dd-2ecf-4973-9380-
576d1d374a25.92d12017-af9a-41ae-b97a-8213710cdb49?
mode=scale&q=90&h=1080&w=1920"
nombre_local_imagen = "go.jpg"
imagen = requests.get(url_imagen).content
with open(nombre_local_imagen, 'wb') as handler:
handler.write(imagen)
def detalle(row, title):
color = '#80cbc4'
img = mpimg.imread('go.jpg')
plt.figure(figsize=(15,8))
categories=list(df)[1:]
N = len(categories)
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
ax = plt.subplot(111, projection='polar')
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
plt.xticks(angles[:-1], categories, color= "black", size=10)
ax.set_rlabel_position(0)
plt.yticks([25,50,75,100], ["25","50","75","100"], color="grey", size=8)
plt.ylim(0,100)
values=df.loc[row].drop('Cero').values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, color= "black", linewidth=1, linestyle='solid')
ax.fill(angles, values, color= color, alpha=0.9)
axes_coords = [0, 0, 1, 1]
ax_image = plt.gcf().add_axes(axes_coords)
ax_image.imshow(img, alpha=.5)
ax_image.axis('off')
plt.title(title, size=50, color= "black", y=1.1)
plt.title(title, size=50, color= "black", y=1.1)
my_palette = plt.cm.get_cmap("Set2", len(df.index))
detalle(row= row, title=df['Cero'][row])
If in the line ax_image = plt.gcf().add_axes(axes_coords) I add zorder= -99 it looks like this:
ax_image = plt.gcf().add_axes(axes_coords, zorder= -99)
I need the opposite, that the image is only visible inside the graph.
It can be done by adding a
clip_path()
, which is a circle placed in the right place, to the image. In this case it would be:Unfortunately the magic numbers
(563, 314)
for the center and215
for the radius I have had to come up with by trial and error. I don't know how to get them automatically. I've tried to make the center half ofim.get_size()
, but it doesn't work. I guess the axes have somehow transformed the coordinates, but I can't figure out how to get these dimensions.The result looks like this:
Update
I found it! Instead of creating a circle "by hand" to do the clipping, I thought I'd better use the one that matplotlib has used to paint its polar coordinate axes.
With
ax.get_children()
you get the list of objects that make up the plot, among which are the traverse line of the data, text labels, etc. One of these objects is of typematplotlib.patches.Wedge
, which is a circular sector (or also a complete circle as in this case). Just extract that patch and use it to make the clip:Bonuses
With a small change you can make the clip over the data polygon:
which results in:
You can even create two
ax_image
, put a different image on each one as well as a different clip_path, and play with their z-order, to get:This is the code of the last figure: