简体   繁体   中英

Matplotlib Pyplot logo/image in Plot

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.

在此处输入图片说明

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()

在此处输入图片说明

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

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()

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/

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")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM