6

I'm struggling to achieve a simple goal in matplotlib... I want to put a small logo or indicator in the bottom right of my graph, without altering the axis or the real data that is being displayed. Here is my code now:

fig = plt.figure()
plt.rcParams.update({'font.size': 15})

img = plt.imread('./path/to/image.png')
ax1 = fig.add_subplot(111)
ax1.yaxis.tick_left()
ax1.tick_params(axis='y', colors='black', labelsize=15)
ax1.tick_params(axis='x', colors='black', labelsize=15)

plt.grid(b=True, which='major', color='#D3D3D3', linestyle='-')

plt.scatter([1,2,3,4,5],[5,4,3,2,1], alpha=1.0)

plt.autoscale(enable=True, axis=u'both')

fig.savefig('figure.png')

My output from this is below.

This is now laying the photo over the whole graph -- I'd like it scaled to 20% of width & height (if possible) and anchored to the bottom right. This also ruins my axis, because in this output I should be in the 0-100 range on both x & y. Any ideas to solve this, the scaling is the big issue.

Edit1: I've tried the solution below and linked questions here on SO. The problem is relying on the extent variable being passed to imshow() then doesn't work well when introducing new data. For example plotting a scatter plot coming from a data frame, could be from 0..1000 and 50..100 but using extent won't show the label or the position will be off.

Edit2: There seems to be some progress with getting the figure length with fig.get_size_inches() and passing the variable to extent. Apparently all of matplotlib graph calculations are done through inches, so this may be a promising lead.

enter image description here

4 Answers 4

7
import matplotlib.image as image
import matplotlib.pyplot as plt

im = image.imread('debian-swirl.png')
fig, ax = plt.subplots()
ax.imshow(im, aspect='auto', extent=(0.4, 0.6, .5, .7), zorder=-1)
ax.yaxis.tick_left()
ax.tick_params(axis='y', colors='black', labelsize=15)
ax.tick_params(axis='x', colors='black', labelsize=15)
ax.grid(b=True, which='major', color='#D3D3D3', linestyle='-')
ax.scatter([1,2,3,4,5],[5,4,3,2,1], alpha=1.0)
plt.show()

enter image description here

I added a png file to bottom left. Adjust the extent parameter to set the logo position.

Similar to : Scale image in matplotlib without changing the axis

Sign up to request clarification or add additional context in comments.

3 Comments

Is it not possible to contain the image to 20% width and height of the plot, not depending on the data? I'd like to be able to constantly put this image on any plot that I create, and with this code I have to adjust the "extent" factor depending on how my axis scales with new data
Eg. If I change the data being passed in to [100,90,89,70], [55, 23,76,29] this no longer displays an image
I'm also interested in an answer that utilizes fractional coordinates of the axis (not the entire figure).
6

The following is an adaptation of the answer by Kirubaharan J, but adapting the position of the logo to the extent of the graph (but the aspect ratio of the logo itself is not preserved)

import matplotlib.image as image
import matplotlib.pyplot as plt

im =image.imread('debian-swirl.png')
fig, ax = plt.subplots()
ax.yaxis.tick_left()
ax.tick_params(axis='y', colors='black', labelsize=15)
ax.tick_params(axis='x', colors='black', labelsize=15)
ax.grid(b=True, which='major', color='#D3D3D3', linestyle='-')
ax.scatter( [100,90,89,70], [55, 23,76,29], alpha=1.0)

plt.autoscale(enable=True, axis=u'both')

xrng=plt.xlim()
yrng=plt.ylim()
scale=.2 #the image takes this fraction of the graph
ax.imshow(im,aspect='auto',extent=(xrng[0],xrng[0] + scale*(xrng[1]-xrng[0]), yrng[0], yrng[0] + scale*(yrng[1]-yrng[0]) ), zorder=-1)
plt.xlim(xrng)
plt.ylim(yrng)

plt.show()

Comments

2

I've worked on a similar problem to print several pdf with a fix logo on every pages independant of the graph size. The best solution I found was using GridSpec.

fig = plt.figure(figsize = (11,8.5)) # 8.5" x 11" : letter format
G = plt.GridSpec(14,21)

I my case I'v build a grid of 14 square by 21 over an 8.5 x 11 inch template. Then I just have to allocate a section of the grid for the logo and import it using matplotlib.image

ax = fig.add_subplot(G[2:5,5:14])
logo = mpimg.imread("logo.png")
imagebox = OffsetImage(logo, zoom=0.08)
ab = AnnotationBbox(imagebox, (0.4, 0.6), frameon = False)
ax.add_artist(ab)

You can control the scale using the zoom arg in OffsetImage You can find the detail at the following link :

https://www.science-emergence.com/Articles/How-to-insert-an-image-a-picture-or-a-photo-in-a-matplotlib-figure/

1 Comment

I just encountered this problem and using AnnotationBbox as in your link was the best solution I found
2

i think it's best to simply put the image on a new axis... in this way you have full control on where to put it without having to bother with existing axes

import matplotlib.image as image
import matplotlib.pyplot as plt
# create a plot
f, ax = plt.subplots()

im = image.imread("path-to-logo.png")

# put a new axes where you want the image to appear
# (x, y, width, height)
imax = f.add_axes([0.8, 0.75, 0.1, 0.1])
# remove ticks & the box from imax 
imax.set_axis_off()
# print the logo with aspect="equal" to avoid distorting the logo
imax.imshow(im, aspect="equal")

4 Comments

This works quite well and i the simplest solution I've found. Thanks.
This positions relative to the figure. Is there an easy way to position the image relative to the ticks in another axis? It's surely obvious and easy, but I'm not seeing it.
@jma what you are searching for is the transform argument... e.g. use f.add_axes([...], transform=ax.transAxes) to specify the coordinates relative to the position of the axes (for more details see matplotlib.org/stable/tutorials/advanced/…)
This is excellent! Most answers are still relative to the data in the plot and mess with the aspect ratio. This solves both of those issues and is reproducible across many plots.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.