matplotlib: create PDF that does not combine image objects - python

I like to use matplotlib to create a PDF and then I will often go in and tweak things with Adobe Illustrator or Inkscape. Unfortunately, when matplotlib saves the figure as a PDF, it combines multiple images into a single object.
For example, the following code
import matplotlib.pyplot as plt
import numpy as np
im = np.random.rand(10, 10) * 255.0
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.imshow(im, extent = [0,10,0,10])
ax.imshow(im, extent = [12,22,0,10])
ax.set_xlim(-2,24)
fig.savefig('images_get_combined.pdf')
creates the following PDF (after I manually converted to a PNG, so I could post it here)
When I open images_get_combined.pdf in Adobe Illustrator, both images are combined into a single image. I cannot move one image relative to the other.
I tried to get around this problem using BboxImage, but as shown in this bug report, BboxImage doesn't play nice with the PDF backend. Perhaps the PDF backend with BboxImage bug will get resolved, but I wondered if there is another way to make the PDF backend save each image separately.

You can try to save as multiple pages PDF:
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
im = np.random.rand(10, 10) * 255.0
with PdfPages('images_get_combined.pdf') as pdf:
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.imshow(im, extent = [0,10,0,10])
pdf.savefig()
plt.close()
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.imshow(im, extent = [12,22,0,10])
pdf.savefig()
plt.close()
See also Multipage PDF example from the matplotlib doc.

Related

How can I output function results to pdf in Jupyter Notebook

I am working in Jupyter Notebook and I have a function that generates multiple plots upon being called. I want to directly save all plots from this function call under one pdf. Is there ways to do that?
Any help will be much appreciated!
Alison
You can use PDFPages to save all of your plots into a pdf. You can try the following example and implement it similarly in your code:
You can create a plotGraph function:
def plotGraph(X,Y):
fig = plt.figure()
### Plotting code ###
return fig
Then use that to get your and place them in your pdf.
from matplotlib.backends.backend_pdf import PdfPages
plot1 = plotGraph(graph1, label1)
plot2 = plotGraph(graph2, label2)
plot3 = plotGraph(graph3, label3)
pp = PdfPages('foo.pdf')
pp.savefig(plot1)
pp.savefig(plot2)
pp.savefig(plot3)
pp.close()
If you are okay with saving it as a PNG file with all the plots you can try the following:
from matplotlib import pyplot as plt
fig = plt.figure()
axis1 = fig.add_subplot(211)
axis1.plot(range(10))
axis2 = fig.add_subplot(212)
axis2.plot(range(10,20))
fig.savefig('allplots.png')
This basically creates subplots and saves all your plots in 1 png file.

Save multiple figures in one pdf page, matplotlib

I'm trying to get my figures in just one pdf page, but I don't know how to do this. I found out that it's possible to save multiple figures in a pdf file with 'matplotlib.backends.backend_pdf', but it doesn't work for just one page.
Has anyone any ideas ? Convert the figures to just one figure ?
You can use matplotlib gridspec to have multiple plots in 1 window
http://matplotlib.org/users/gridspec.html
from matplotlib.gridspec import GridSpec
import random
import numpy
from matplotlib import pyplot as pl
fig = pl.figure(figsize=(12, 16))
G = GridSpec(2,2)
axes_1 = pl.subplot(G[0, :])
x = [random.gauss(3,1) for _ in range(400)]
bins = numpy.linspace(-10, 10, 100)
axes_1.hist(x, bins, alpha=0.5, label='x')
axes_2 = pl.subplot(G[1, :])
axes_2.plot(x)
pl.tight_layout()
pl.show()
You can change the rows and column values and can subdivide the sections.
The PDF backend makes one page per figure. Use subplots to get multiple plots into one figure and they'll all show up together on one page of the PDF.
Here is a solution provided by matplotlib:
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
with PdfPages('foo.pdf') as pdf:
#As many times as you like, create a figure fig and save it:
fig = plt.figure()
pdf.savefig(fig)
....
fig = plt.figure()
pdf.savefig(fig)
VoilĂ 
Find a full example here: multipage pdf matplotlib
And by the way, for one figure, you don't need matplotlib.backends.backend_pdf just add pdf extension like so:
plt.savefig("foo.pdf")

Image icons in a matplotlib plot? [duplicate]

I would like to utilize customer markers in both scatter and line charts. How can I make custom marker out of a PNG file?
I don't believe matplotlib can customize markers like that. See here for the level of customization, which falls way short of what you need.
As an alternative, I've coded up this kludge which uses matplotlib.image to place images at the line point locations.
import matplotlib.pyplot as plt
from matplotlib import image
# constant
dpi = 72
path = 'smile.png'
# read in our png file
im = image.imread(path)
image_size = im.shape[1], im.shape[0]
fig = plt.figure(dpi=dpi)
ax = fig.add_subplot(111)
# plot our line with transparent markers, and markersize the size of our image
line, = ax.plot((1,2,3,4),(1,2,3,4),"bo",mfc="None",mec="None",markersize=image_size[0] * (dpi/ 96))
# we need to make the frame transparent so the image can be seen
# only in trunk can you put the image on top of the plot, see this link:
# http://www.mail-archive.com/matplotlib-users#lists.sourceforge.net/msg14534.html
ax.patch.set_alpha(0)
ax.set_xlim((0,5))
ax.set_ylim((0,5))
# translate point positions to pixel positions
# figimage needs pixels not points
line._transform_path()
path, affine = line._transformed_path.get_transformed_points_and_affine()
path = affine.transform_path(path)
for pixelPoint in path.vertices:
# place image at point, centering it
fig.figimage(im,pixelPoint[0]-image_size[0]/2,pixelPoint[1]-image_size[1]/2,origin="upper")
plt.show()
Produces:
Following on from Mark's answer. I just thought I would add to this a bit because I tried to run this and it does what I want with the exception of actually displaying the icons on the graph. Maybe something has changed with matplotlib. It has been 4 years.
The line of code that reads:
ax.get_frame().set_alpha(0)
does not seem to work, however
ax.patch.set_alpha(0)
does work.
The other answer may lead to problems when resizing the figure. Here is a different approach, positionning the images inside annotation boxes, which are anchored in data coordinates.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
path = "https://upload.wikimedia.org/wikipedia/commons/b/b5/Tango-example_icons.png"
image = plt.imread(path)[116:116+30, 236:236+30]
x = np.arange(10)
y = np.random.rand(10)
fig, ax = plt.subplots()
ax.plot(x,y)
def plot_images(x, y, image, ax=None):
ax = ax or plt.gca()
for xi, yi in zip(x,y):
im = OffsetImage(image, zoom=72/ax.figure.dpi)
im.image.axes = ax
ab = AnnotationBbox(im, (xi,yi), frameon=False, pad=0.0,)
ax.add_artist(ab)
plot_images(x, y, image, ax=ax)
plt.show()

Putting custom objects as datapoints in python [duplicate]

I would like to utilize customer markers in both scatter and line charts. How can I make custom marker out of a PNG file?
I don't believe matplotlib can customize markers like that. See here for the level of customization, which falls way short of what you need.
As an alternative, I've coded up this kludge which uses matplotlib.image to place images at the line point locations.
import matplotlib.pyplot as plt
from matplotlib import image
# constant
dpi = 72
path = 'smile.png'
# read in our png file
im = image.imread(path)
image_size = im.shape[1], im.shape[0]
fig = plt.figure(dpi=dpi)
ax = fig.add_subplot(111)
# plot our line with transparent markers, and markersize the size of our image
line, = ax.plot((1,2,3,4),(1,2,3,4),"bo",mfc="None",mec="None",markersize=image_size[0] * (dpi/ 96))
# we need to make the frame transparent so the image can be seen
# only in trunk can you put the image on top of the plot, see this link:
# http://www.mail-archive.com/matplotlib-users#lists.sourceforge.net/msg14534.html
ax.patch.set_alpha(0)
ax.set_xlim((0,5))
ax.set_ylim((0,5))
# translate point positions to pixel positions
# figimage needs pixels not points
line._transform_path()
path, affine = line._transformed_path.get_transformed_points_and_affine()
path = affine.transform_path(path)
for pixelPoint in path.vertices:
# place image at point, centering it
fig.figimage(im,pixelPoint[0]-image_size[0]/2,pixelPoint[1]-image_size[1]/2,origin="upper")
plt.show()
Produces:
Following on from Mark's answer. I just thought I would add to this a bit because I tried to run this and it does what I want with the exception of actually displaying the icons on the graph. Maybe something has changed with matplotlib. It has been 4 years.
The line of code that reads:
ax.get_frame().set_alpha(0)
does not seem to work, however
ax.patch.set_alpha(0)
does work.
The other answer may lead to problems when resizing the figure. Here is a different approach, positionning the images inside annotation boxes, which are anchored in data coordinates.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
path = "https://upload.wikimedia.org/wikipedia/commons/b/b5/Tango-example_icons.png"
image = plt.imread(path)[116:116+30, 236:236+30]
x = np.arange(10)
y = np.random.rand(10)
fig, ax = plt.subplots()
ax.plot(x,y)
def plot_images(x, y, image, ax=None):
ax = ax or plt.gca()
for xi, yi in zip(x,y):
im = OffsetImage(image, zoom=72/ax.figure.dpi)
im.image.axes = ax
ab = AnnotationBbox(im, (xi,yi), frameon=False, pad=0.0,)
ax.add_artist(ab)
plot_images(x, y, image, ax=ax)
plt.show()

How to show multiple images in one figure?

I use Python lib matplotlib to plot functions, and I know how to plot several functions in different subplots in one figure, like this one,
And when handling images, I use imshow() to plot images, but how to plot multiple images together in different subplots with one figure?
The documentation provides an example (about three quarters of the way down the page):
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
fig = plt.figure()
a=fig.add_subplot(1,2,1)
img = mpimg.imread('../_static/stinkbug.png')
lum_img = img[:,:,0]
imgplot = plt.imshow(lum_img)
a.set_title('Before')
plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation ='horizontal')
a=fig.add_subplot(1,2,2)
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0.0,0.7)
a.set_title('After')
plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation='horizontal')
# ---------------------------------------
# if needed inside the application logic, uncomment to show the images
# plt.show()
Basically, it's the same as you do normally with creating axes with fig.add_subplot...
Simple python code to plot subplots in a figure;
rows=2
cols=3
fig, axes = plt.subplots(rows,cols,figsize=(30,10))
plt.subplots_adjust(wspace=0.1,hspace=0.2)
features=['INDUS','RM', 'AGE', 'DIS','PTRATIO','MEDV']
plotnum=1
for idx in features:
plt.subplot(rows,cols,plotnum)
sns.distplot(data[idx])
plotnum=plotnum+1
plt.savefig('subplots.png')
go through below link for more detail
https://exploredatalab.com/how-to-plot-multiple-subplots-in-python-with-matplotlib/

Categories

Resources