Python saving multiple figures into one PDF file - python

In python (for one figure created in a GUI) I was able to save the figure under .jpg and also .pdf by either using:
plt.savefig(filename1 + '.pdf')
or
plt.savefig(filename1 + '.jpg')
Using one file I would like to save multiple figures in either .pdf or .jpg (just like its done in math lab). Can anybody please help with this?

Use PdfPages to solve your problem. Pass your figure object to the savefig method.
For example, if you have a whole pile of figure objects open and you want to save them into a multi-page PDF, you might do:
import matplotlib.backends.backend_pdf
pdf = matplotlib.backends.backend_pdf.PdfPages("output.pdf")
for fig in xrange(1, figure().number): ## will open an empty extra figure :(
pdf.savefig( fig )
pdf.close()

Do you mean save multiple figures into one file, or save multiple figures using one script?
Here's how you can save two different figures using one script.
>>> from matplotlib import pyplot as plt
>>> fig1 = plt.figure()
>>> plt.plot(range(10))
[<matplotlib.lines.Line2D object at 0x10261bd90>]
>>> fig2 = plt.figure()
>>> plt.plot(range(10,20))
[<matplotlib.lines.Line2D object at 0x10263b890>]
>>> fig1.savefig('fig1.png')
>>> fig2.savefig('fig2.png')
...which produces these two plots into their own ".png" files:
To save them to the same file, use subplots:
>>> 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('multipleplots.png')
The above script produces this single ".png" file:

I struggled with the same issue. I was trying to put 2,000 scatter plots into a single .pdf. I was able to start the procedure, but it aborted after a few hundred.
Even when I created six scatter charts into one .pdf, the .pdf file was enormous (like 7mb) for just six .jpg's that were 30kb each. When I opened the .pdf, it appeared that the .pdf was painting every point on the chart (each chart had thousands of points) instead of displaying an image. Some day, I will figure out the correct options, but here is a quick and dirty work-around. I printed the scatter plots to individual .jpg files in a local directory.

Related

matplotlib.pyplot show() without clearing the figure

I'm using matplotlib.pyplot in interactive mode. I want to check that I've formatted the figure correctly using plt.show(), but every time I do the figure is cleared and I have to plot it again. I'd like to be able to view the plot in interactive mode without the figure clearing.
What happens:
>>> plt.plot(np.arange(5))
>>> plt.show()
<figure-displays>
>>> plt.show()
<nothing-happens>
>>> plt.savefig('my_figure.png')
<empty-file-is-saved>
What I want:
>>> plt.plot(np.arange(5))
>>> plt.show()
<figure-displays>
>>> plt.show()
<figure-displays>
>>> plt.savefig('my_figure.png')
<figure-is-saved>
If what you want is to be able to see the changes every time, you can save multiple files, and as long as you don't call plt.close(), the plots will just keep adding.
import matplotlib.pyplot as plt
plt.plot([5,1,4],[3,2,1])
plt.savefig('1.png')
plt.plot([3,2,1],[1,2,3])
plt.savefig('2.png')
There might be many files, so it is best to do this in a New folder. If you are programming with the python shell only, this is what you can do to change directories:
>>> import os
>>> path = 'C:\\Users\\Caitlin\\Desktop\\New folder'
>>> os.chdir(path)
>>>
If you are using a python file, simply place the file into the New folder. Or, you can simply add the path into savefig():
plt.savefig('C:\\Users\\Caitlin\\Desktop\\New folder\\1.png')

Image not updating in python plot during animation

The Problem:
I'm trying to simulate a live video by cycling through a series of still images I have saved in a directory, but when I add the animation and update functions my plot is displayed empty.
Background on why I'm doing this:
I believe its important for me to do it this way rather than a complete change of approach, say turning the images into a video first then displaying that, because what I really want to test is the image analysis I will be adding and then overlaying on each frame. The final application will be receiving frames one by one from a camera and will need to do some processing, display the image + annotations + output the data as .csv etc... I'm simulating this for now because I do not have any of the hardware to generate the images and will not have it for several months during which time I need to get the image processing set up, but I do have access to some sets of stills that are approximately what will be produced. In case its relevant my simulation images are 1680x1220 and are 1.88 Mb TIFFs, though I could covert and compress them if needed, and in the final form the resolution will be a bit higher and probably the image format could be adjusted if needed.
What I have tried:
I followed an example to list all files in a folder, and an example
to update a plot. However, the plot displays blank when I run the
code.
I added a line to print the current file name, and I can see this
cycling as expected.
I also made sure the images will display in the plot if I just create
a plot and add one image, and they do. But, when combined with the
animation function the plot is blank and I'm not sure what I've done
wrong/failed to include.
I also tried adding a plt.pause() in the update, but again this
didn't work.
I increased the interval up to 2000 to give it more time, but that didn't work. I believe 2000 is extreme, I'm expecting it should work with more like 20-30fps. Going to 0.5fps tells me the code is wrong or incomplete, rather than it just being a question of needing time to read the image file.
I appreciate no one else has my images, but they are nothing special. I'm using 60 images but I guess it could be tested with any 2 random images and setting range(60) to range(2) instead?
The example I copied originally demonstrated the animation function by making a random array, and if I do that it will show a plot that updates with random squares as expected.
Replacing:
A = np.random.randn(10,10)
im.set_array(A)
...with my image instead...
im = cv2.imread(files[i],0)
...and the plot remains empty/blank. I get a window shown called "Figure1" (like when using the random array), but unlike with the array there is nothing in this window.
Full code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import os
import cv2
def update(i):
im = cv2.imread(files[i],0)
print(files[i])
#plt.pause(0.1)
return im
path = 'C:\\Test Images\\'
files = []
# r=root, d=directories, f = files
for r, d, f in os.walk(path):
for file in f:
if '.TIFF' in file:
files.append(os.path.join(r, file))
ani = FuncAnimation(plt.gcf(), update, frames=range(60), interval=50, blit=False)
plt.show()
I'm a python and a programming novice so have relied on adjusting examples others have given online but I have only a simplistic understanding of how they are working and end up with a lot of trial and error on the syntax. I just can't figure out anything to make this one work though.
Cheers for any help!
The main reason nothing is showing up is because you never add the images to the plot. I've provided some code below to do what you want, be sure to look up anything you are curious about or don't understand!
import glob
import os
from matplotlib import animation
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
IMG_DIRPATH = 'C:\\Test Images\\' # the folder with your images (be careful about
# putting spaces in directory names!)
IMG_EXT = '.TIFF' # the file extension of your images
# Create a figure, and set to the desired size.
fig = plt.figure(figsize=[5, 5])
# Create axes for the current figure so that images can be sized appropriately.
# Passing in [0, 0, 1, 1] makes the axes fill the whole figure.
# frame_on=False means we won't have a bounding box, and setting xticks=[] and
# yticks=[] means that we won't have pesky tick marks along our image.
ax_props = {'frame_on': False, 'xticks': [], 'yticks': []}
ax = plt.axes([0, 0, 1, 1], **ax_props)
# Get all image filenames.
img_filepaths = glob.glob(os.path.join(IMG_DIRPATH, '*' + IMG_EXT))
def update_image(img_filepath):
# Remove all existing images on the axes, and restore our settings.
ax.clear()
ax.update(ax_props)
# Read the current image.
img = mpimg.imread(img_filepath)
# Add the current image to the plot axes.
ax.imshow(img)
anim = animation.FuncAnimation(fig, update_image, frames=img_filepaths, interval=250)
plt.show()

Plot all the graph and save it in pdf file in python [duplicate]

In python (for one figure created in a GUI) I was able to save the figure under .jpg and also .pdf by either using:
plt.savefig(filename1 + '.pdf')
or
plt.savefig(filename1 + '.jpg')
Using one file I would like to save multiple figures in either .pdf or .jpg (just like its done in math lab). Can anybody please help with this?
Use PdfPages to solve your problem. Pass your figure object to the savefig method.
For example, if you have a whole pile of figure objects open and you want to save them into a multi-page PDF, you might do:
import matplotlib.backends.backend_pdf
pdf = matplotlib.backends.backend_pdf.PdfPages("output.pdf")
for fig in xrange(1, figure().number): ## will open an empty extra figure :(
pdf.savefig( fig )
pdf.close()
Do you mean save multiple figures into one file, or save multiple figures using one script?
Here's how you can save two different figures using one script.
>>> from matplotlib import pyplot as plt
>>> fig1 = plt.figure()
>>> plt.plot(range(10))
[<matplotlib.lines.Line2D object at 0x10261bd90>]
>>> fig2 = plt.figure()
>>> plt.plot(range(10,20))
[<matplotlib.lines.Line2D object at 0x10263b890>]
>>> fig1.savefig('fig1.png')
>>> fig2.savefig('fig2.png')
...which produces these two plots into their own ".png" files:
To save them to the same file, use subplots:
>>> 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('multipleplots.png')
The above script produces this single ".png" file:
I struggled with the same issue. I was trying to put 2,000 scatter plots into a single .pdf. I was able to start the procedure, but it aborted after a few hundred.
Even when I created six scatter charts into one .pdf, the .pdf file was enormous (like 7mb) for just six .jpg's that were 30kb each. When I opened the .pdf, it appeared that the .pdf was painting every point on the chart (each chart had thousands of points) instead of displaying an image. Some day, I will figure out the correct options, but here is a quick and dirty work-around. I printed the scatter plots to individual .jpg files in a local directory.

Writing pandas/matplotlib image directly into XLSX file

I am generating plots in pandas/matplotlib and wish to write them to an XLSX file. I am not looking to create native Excel charts; I am merely writing the plots as non-interactive images. I am using the XlsxWriter library/engine.
The closest solution I have found is the answer to this SO question, which suggests using the XlsxWriter.write_image() method. However, this method appears to take a filename as its input. I am trying to programmatically pass the direct output from a pandas/matplotlib plot() call, e.g. something like this:
h = results.resid.hist()
worksheet.insert_image(row, 0, h) # doesn't work
or this:
s = df.plot(kind="scatter", x="some_x_variable", y="resid")
worksheet.insert_image(row, 0, s) # doesn't work
Is there any way to accomplish this, short of the workaround of writing the image to a disk file first?
Update
Answer below got me on the right track and am accepting. I needed to make a few changes, mainly (I think) because I am using Python 3 and perhaps some API changes. Here is the solution:
from io import BytesIO
import matplotlib.pyplot as plt
imgdata = BytesIO()
fig, ax = plt.subplots()
results.resid.hist(ax=ax)
fig.savefig(imgdata, format="png")
imgdata.seek(0)
worksheet.insert_image(
row, 0, "",
{'image_data': imgdata}
)
The "" in the insert_image() code is to trick Excel, which is still expecting a filename/URL/etc.
You can save the image to memory as a file object (not to disk) and then use that when inserting to Excel file:
import matplotlib.pyplot as plt
from cStringIO import StringIO
imgdata = StringIO()
fig, ax = plt.subplots()
# Make your plot here referencing ax created before
results.resid.hist(ax=ax)
fig.savefig(imgdata)
worksheet.insert_image(row, 0, imgdata)

Change figure size and figure format in matplotlib [duplicate]

This question already has answers here:
How do I change the size of figures drawn with Matplotlib?
(14 answers)
Closed 1 year ago.
I want to obtain fig1 exactly of 4 by 3 inch sized, and in tiff format correcting the program below:
import matplotlib.pyplot as plt
list1 = [3,4,5,6,9,12]
list2 = [8,12,14,15,17,20]
plt.plot(list1, list2)
plt.savefig('fig1.png', dpi = 300)
plt.close()
You can set the figure size if you explicitly create the figure with
plt.figure(figsize=(3,4))
You need to set figure size before calling plt.plot()
To change the format of the saved figure just change the extension in the file name. However, I don't know if any of matplotlib backends support tiff
You can change the size of the plot by adding this before you create the figure.
plt.rcParams["figure.figsize"] = [16,9]
The first part (setting the output size explictly) isn't too hard:
import matplotlib.pyplot as plt
list1 = [3,4,5,6,9,12]
list2 = [8,12,14,15,17,20]
fig = plt.figure(figsize=(4,3))
ax = fig.add_subplot(111)
ax.plot(list1, list2)
fig.savefig('fig1.png', dpi = 300)
fig.close()
But after a quick google search on matplotlib + tiff, I'm not convinced that matplotlib can make tiff plots. There is some mention of the GDK backend being able to do it.
One option would be to convert the output with a tool like imagemagick's convert.
(Another option is to wait around here until a real matplotlib expert shows up and proves me wrong ;-)
If you need to change the figure size after you have created it, use the methods
fig = plt.figure()
fig.set_figheight(value_height)
fig.set_figwidth(value_width)
where value_height and value_width are in inches. For me this is the most practical way.

Categories

Resources