How to save a series of matplotlib plots as an image file? - python

I'm trying to save a series of matplotlib figures as one single image file with many slices. To put things in perspective, the following is the code I'm using:
for n in range(len(image.shape[0])): #this image here is a timelapse image
plt.imshow(image[n, :, :], cmap='gray')
ax = plt.gca()
for acontour in contour_list:
ax.add_patch(patches.Polygon(acontour[:, [1, 0]],linewidth=1,edgecolor='r',facecolor='none'))
plt.show()
I'm trying to overlay the corresponding contour on the original image for every slice and save all the images.
Thanks in advance.

Will this help:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2,len(image.shape[0])//2, figsize=(15, 6))
fig.subplots_adjust(hspace = .5, wspace=.001)
axs = axs.ravel()
for n in range(len(image.shape[0])):
# Your plot code
plt.savefig('image.png')

Related

How to remove padding in matplotlib subplots when using make_axes_locatable

I'm trying to create a 4x2 plot on a slightly non-rectangular dataset (x-axis range is smaller than y-axis range) using plt.subplots and assign colorbars using make_axes_locatable to have the colorbars nice and flush wih the subplots. I always end up with huge paddings/margins between the two subplot columns which I suspect originate from the colorbars... I've tried multiple things from many stackoverflow questions (e.g. using fig.subplots_adjust(), constrained_layout=True etc.) but to no avail. The margins between the two columns stay really large (see img below) and make the image unreadable...
Any input would be much appreciated!
Code used to reproduce the issue:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
data = np.random.random((10, 6))
fig, axs = plt.subplots(nrows=4, ncols=2, figsize=(16, 8), sharex=True, sharey=False, constrained_layout=True)
for idx in range(4):
# plot image
im1 = axs[idx, 0].imshow(data, cmap=cm.coolwarm)
im2 = axs[idx, 1].imshow(data, cmap=cm.viridis)
# make colorbars
ax1_divider = make_axes_locatable(axs[idx, 0])
cax1 = ax1_divider.append_axes("right", size="2%", pad=0.05)
cb1 = fig.colorbar(im1, cax=cax1, orientation="vertical")
ax2_divider = make_axes_locatable(axs[idx, 1])
cax2 = ax2_divider.append_axes("right", size="2%", pad=0.05)
cb2 = fig.colorbar(im2, cax=cax2, orientation="vertical")
You are plotting multiple images (which by default it tries to keep an equal aspect ratio), in which the height is greater than the width. Therefore, total height of the images > total width of the images.
It follows that one way to reduce the white spacing between columns is to reduce the width of the figure.
Try setting this:
fig, axs = plt.subplots(nrows=4, ncols=2, figsize=(4, 8), sharex=True, sharey=False, constrained_layout=True)

plotting a grid of png with matplotlib

I have found multiple similar questions with this subject but so far I couldn't adapt any solution to my needs, so I'm sorry for reposting.
I'm trying to plot a grid of png images using matplotlib, the closest I've got to what I want is using the code below, which can be found here https://matplotlib.org/stable/gallery/axes_grid1/simple_axesgrid.html .
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import numpy as np
im1 = np.arange(100).reshape((10, 10))
im2 = im1.T
im3 = np.flipud(im1)
im4 = np.fliplr(im2)
fig = plt.figure(figsize=(4., 4.))
grid = ImageGrid(fig, 111, # similar to subplot(111)
nrows_ncols=(2, 2), # creates 2x2 grid of axes
axes_pad=0.1, # pad between axes in inch.
)
for ax, im in zip(grid, [im1, im2, im3, im4]):
# Iterating over the grid returns the Axes.
ax.imshow(im)
plt.show()
My question is, how do I get rid of the x and y ticks/labels and also give each image a title?
Again, I'm sorry for repeating the question.
This code
import matplotlib.pyplot as plt
image = plt.imread("sample.png")
fig, axes = plt.subplots(2, 3)
for row in [0, 1]:
for column in [0, 1, 2]:
ax = axes[row, column]
ax.set_title(f"Image ({row}, {column})")
ax.axis('off')
ax.imshow(image)
plt.show()
is going to produce

Plotting two images in Matplotlib on the same axes

I'm trying to plot two images on the same axes. Here is the code I'm experimenting with (I'm new to MatplotLib - so apologies in advance)...
import matplotlib.pyplot as plt
from matplotlib import transforms
img = plt.imread('image1.gif')
fig = plt.figure()
ax = fig.add_subplot(111)
rotation_in_degrees = 60
tr = transforms.Affine2D().rotate_deg(rotation_in_degrees)
ax.imshow(img)
ax.imshow(img, transform=tr)
plt.show()
There are two issues. Firstly, only the first image appears in the display; the second is only partially shown. Is there a way to show the two images in the same plot? That is, the axes are automatically scaled.
Secondly, as you can see, I'm trying to rotate the image but I'm sure that I'm not doing correctly in the sense I don't know if I'm rotating it around the origin of the plot etc. Any advice or links for other posts would be great!
Thanks for you help in advance.
To solve your firs problem - you need to display each image in separate subplot, now - you are plotting in the same subplot. See example of plotting in separate plots:
import matplotlib.pyplot as plt
from matplotlib import transforms
img = plt.imread('image.gif')
fig = plt.figure()
rotation_in_degrees = 60
tr = transforms.Affine2D().rotate_deg(rotation_in_degrees)
ax = fig.add_subplot(121)
ax.imshow(img)
ax = fig.add_subplot(122)
ax.imshow(img)
plt.show()
For the second issue with rotation - I would use PIL:
from PIL import Image
import matplotlib.pyplot as plt
img = Image.open('image.gif')
fig = plt.figure()
rotation_in_degrees = 60
ax = fig.add_subplot(121)
ax.imshow(img)
img2 = img.rotate(rotation_in_degrees)
ax = fig.add_subplot(122)
ax.imshow(img2)
plt.show()

Put images produced by another function into subplot

So I was provided a function show_image that takes an array, and basically calls
plt.imshow(img, cmap='gray')
plt.axis('off')
in its body. It correctly shows the image, that's no problem.
I was asked to create four images with this function, and show them in one figure, each as a subplot. I think I have to use the function and am not supposed to change things inside that function (so I can't add a new return or anything)
I'm not sure how to get the images to show/arrange as subplots of a larger image. I tried
fig, ([ax1, ax2], [ax3, ax4]) = plt.subplots(2, 2,figsize=(12,16))
ax1 = show_image(image)
ax2 = show_image(log)
...
but that didn't work. Specifically, it seems that only the last image was created, and that image always shows on the bottom right subplot. What else could I do?
You can have the plotting functionality in your show_image function
import matplotlib.pyplot as plt
import numpy as np
def show_image(*images):
# get the 4 subplots
fig, ax = plt.subplots(2, 2,figsize=(12,16))
# now assign each images to each subplot
ax[0][0].imshow(images[0], cmap='gray')
ax[0][1].imshow(images[1], cmap='gray')
ax[1][0].imshow(images[2], cmap='gray')
ax[1][1].imshow(images[3], cmap='gray')
plt.axis('off')
arr1 = np.random.randint(255, size=(28,28))
arr2 = np.random.randint(255, size=(28,28))
arr3 = np.random.randint(255, size=(28,28))
arr4 = np.random.randint(255, size=(28,28))
show_image(arr1, arr2, arr3, arr4)

How to make the size of subplot equally?

I am using matplotlib and GridSpec to plot 9 images in 3x3 subplots.
fig = plt.figure(figsize=(30,40))
fig.patch.set_facecolor('white')
gs1 = gridspec.GridSpec(3,3)
gs1.update(wspace=0.05, hspace=0.05)
ax1 = plt.subplot(gs1[0])
ax2 = plt.subplot(gs1[1])
ax3 = plt.subplot(gs1[2])
ax4 = plt.subplot(gs1[3])
ax5 = plt.subplot(gs1[4])
ax6 = plt.subplot(gs1[5])
ax7 = plt.subplot(gs1[6])
ax8 = plt.subplot(gs1[7])
ax9 = plt.subplot(gs1[8])
ax1.imshow(img1,cmap='gray')
ax2.imshow(img2,cmap='gray')
...
ax9.imshow(img9,cmap='gray')
However, the images have a different size from each row. For example, the first-row images size is 256x256, the images in the second row have a size of 200x200 and the third row has a size of 128x128
I want to plot the images in the subplot with same size. How should I use it in python? Thanks
This is an example of 4x3 subplot
Don't use matplotlib.gridspec, but use figure.add_subplot as demonstrated with the runnable code below. However, when doing some plotting, you need to set_autoscale_on(False) to suppress its behavior of size adjusting.
import numpy as np
import matplotlib.pyplot as plt
# a function that creates image array for `imshow()`
def make_img(h):
return np.random.randint(16, size=(h,h))
fig = plt.figure(figsize=(8, 12))
columns = 3
rows = 4
axs = []
for i in range(columns*rows):
axs.append( fig.add_subplot(rows, columns, i+1) )
# axs[-1] is the new axes, write its title as `axs[number]`
axs[-1].set_title("axs[%d]" % (i))
# plot raster image on this axes
plt.imshow(make_img(i+1), cmap='viridis', alpha=(i+1.)/(rows*columns))
# maniputate axs[-1] here, plot something on it
axs[-1].set_autoscale_on(False) # suppress auto sizing
axs[-1].plot(np.random.randint(2*(i+1), size=(i+1)), color="red", linewidth=2.5)
fig.subplots_adjust(wspace=0.3, hspace=0.4)
plt.show()
The resulting plot:
I suppose you want to show the images in different sizes, such that all pixels of the different images are equally sized.
This is in general hard, but for the case where all images in a row (or column) of the subplot grid are of the same size, it becomes easy. The idea can be to use the gridspec's height_ratios (or width_ratios in case of columns) argument and set it to the image's pixel height (width).
import matplotlib.pyplot as plt
import numpy as np
images = [np.random.rand(r,r) for r in [25,20,12] for _ in range(3)]
r = [im.shape[0] for im in images[::3]]
fig, axes = plt.subplots(3,3, gridspec_kw=dict(height_ratios=r, hspace=0.3))
for ax, im in zip(axes.flat, images):
ax.imshow(im)
plt.show()

Categories