plot several image files in matplotlib subplots - matplotlib

I would like to create a matrix subplot and display each BMP files, from a directory, in a different subplot, but I cannot find the appropriate solution for my problem, could somebody helping me?.
This the code that I have:
import os, sys
from PIL import Image
import matplotlib.pyplot as plt
from glob import glob
bmps = glob('*trace*.bmp')
fig, axes = plt.subplots(3, 3)
for arch in bmps:
i = Image.open(arch)
iar = np.array(i)
for i in range(3):
for j in range(3):
axes[i, j].plot(iar)
plt.subplots_adjust(wspace=0, hspace=0)
plt.show()
I am having the following error after executing:

natively matplotlib only supports PNG images, see http://matplotlib.org/users/image_tutorial.html
then the way is always read the image - plot the image
read image
img1 = mpimg.imread('stinkbug1.png')
img2 = mpimg.imread('stinkbug2.png')
plot image (2 subplots)
plt.figure(1)
plt.subplot(211)
plt.imshow(img1)
plt.subplot(212)
plt.imshow(img2)
plt.show()
follow the tutorial on http://matplotlib.org/users/image_tutorial.html (because of the import libraries)
here is a thread on plotting bmps with matplotlib: Why bmp image displayed as wrong color with plt.imshow of matplotlib on IPython-notebook?

The bmp has three color channels, plus the height and width, giving it a shape of (h,w,3). I believe plotting the image gives you an error because the plot only accepts two dimensions. You could grayscale the image, which would produce a matrix of only two dimensions (h,w).
Without knowing the dimensions of the images, you could do something like this:
for idx, arch in enumerate(bmps):
i = idx % 3 # Get subplot row
j = idx // 3 # Get subplot column
image = Image.open(arch)
iar_shp = np.array(image).shape # Get h,w dimensions
image = image.convert('L') # convert to grayscale
# Load grayscale matrix, reshape to dimensions of color bmp
iar = np.array(image.getdata()).reshape(iar_shp[0], iar_shp[1])
axes[i, j].plot(iar)
plt.subplots_adjust(wspace=0, hspace=0)
plt.show()

Related

Trying to overplot TESS and 2MASS images using WCSaxes and Astroquery

I'm trying to plot a 2MASS image on the same projection as a TESS image. I used to do this with pywcsgrid2, but I can't seem to install it anymore. So I'm trying with Astropy WCSAxes.
Both the TESS image and 2MASS image are retrieved using Astroquery functions (TESScut and SkyView, respectively). I can create a plot of each image individually on its appropriate WCS axes. But when I try to plot the 2MASS image onto an axis with the TESS WCS (either as a contour or an image itself), it shrinks the image down into the lower left corner. Can somebody tell me what I'm doing wrong, or whether something might be off about the WCS.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
from astroquery.skyview import SkyView
from astropy.wcs import WCS
import astropy.io.fits as fits
import astropy.units as u
from astropy.coordinates import SkyCoord
from astroquery.mast import Tesscut
test_tic = 113449635
cutout_coord = SkyCoord(113.29538299104,-35.48102008076,unit=u.degree)
dir_ffi = "./temp/"
tess_data = Tesscut.download_cutouts(cutout_coord, size=20, path=dir_ffi)
tess_file = tess_data[2][0]
def extract_wcs(dataheader):
"""
Generate WCS for a TESS or K2 TPF. dataheader is the header of extension #1
"""
w5 = WCS(naxis=2)
w5.wcs.crpix = [dataheader["1CRPX5"],dataheader["2CRPX5"]]
w5.wcs.cdelt = np.array([dataheader["1CDLT5"],dataheader["2CDLT5"]])
w5.wcs.crval = [dataheader["1CRVL5"],dataheader["2CRVL5"]]
w5.wcs.ctype = [dataheader["1CTYP5"],dataheader["2CTYP5"]]
w5.wcs.pc = [[dataheader["11PC5"],dataheader["12PC5"]],
[dataheader["21PC5"],dataheader["22PC5"]]]
return w5
with fits.open(tess_file) as hdu:
# not a coadd, but reducing code for the sake of the MWE
coadd = hdu[1].data["FLUX"][100]
dataheader = hdu[1].header
w3 = extract_wcs(dataheader)
# This works just fine
plt.subplot(projection=w3)
plt.imshow(coadd,origin="lower", norm=colors.LogNorm())
plt.xlabel('RA')
plt.ylabel('Dec')
plt.show()
# Get 2MASS K image
twomass_images = SkyView.get_images(position=cutout_coord, survey=['2MASS-K'],pixels=500)
pix_2mass = twomass_images[0][0].data
hdr_2mass = twomass_images[0][0].header
wcs_2mass = WCS(hdr_2mass)
print(w3)
print(wcs_2mass)
# Try to plot the TESS image in the background, with 2MASS overlaid as a contour
# This yields oversized axes with the image in the lower left corner
ax = plt.subplot(projection=w3)
ax.imshow(coadd,origin="lower", norm=colors.LogNorm(),zorder=-10)
ax.contour(pix_2mass, transform=ax.get_transform(wcs_2mass),
colors='k',zorder=5)
plt.xlabel('RA')
plt.ylabel('Dec')
plt.show()
# Try to plot the 2MASS image in the background, on the TESS WCS
# This yields oversized axes with the image in the lower left corner
ax = plt.subplot(projection=w3)
ax.imshow(pix_2mass, origin="lower", norm=colors.LogNorm(), zorder=-10,
transform=ax.get_transform(wcs_2mass))
plt.xlabel('RA')
plt.ylabel('Dec')
plt.show()

Wrote a code in python to edit an image's background and the output i am getting is totally off

I edited it to view the foreground image on a white background but now, none of the images are visible.
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('91_photo.jpg')
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (10,10,360,480)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,255).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
Expecting the result to be a visible image on a white background
This is what i'm getting
There are a number of small issues with your code that are adding up to that weird result.
OpenCV uses BGR ordering of the channels of an image, where matplotlib uses RGB. That means if you read an image with OpenCV but want to display with matplotlib, you need to convert the image from BGR to RGB before displaying (that's the reason the colors are weird). Also, not that important, but color images are not displayed with a colormap, so showing the colormap does not do anything for you.
In numpy, it's best to keep masks boolean whenever you can, because you can use them to index your arrays. Your current code converts a boolean mask to a uint8 image with 0 and 255 values and then you multiply that with your image. That means your image will be set to zero wherever the mask is zero---and your image values will explode (or do weird stuff with overflow). Instead, keep the mask boolean and use it to index your array. That way anywhere the mask is True you can just set the value in your image to something specific (like 255 for white).
This should fix you up:
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('91_photo.jpg')
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (10, 10, 360, 480)
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
mask2 = (mask==2) | (mask==0)
img[mask2] = 255
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()

how to overlay a shapefile in matplotlib

In matplotlib how to overlay the shapefile (available in folder) as attached below at the top right position outside the plot.
The code referenced by banderkat:
import matplotlib.pyplot as plt
import Image
import numpy as np
im = Image.open('Jbc4j.jpg')
width = im.size[0]
height = im.size[1]
# We need a float array between 0-1, rather than
# a uint8 array between 0-255
im = np.array(im).astype(np.float) / 255
a = np.random.randint(0,100,100)
b = range(100)
fig = plt.figure(1,figsize=(5, 7), dpi=80, facecolor='w')
ax = fig.add_subplot(111)
ax.scatter(a,b)
fig.canvas.draw()
# With newer (1.0) versions of matplotlib, you can
# use the "zorder" kwarg to make the image overlay
# the plot, rather than hide behind it... (e.g. zorder=10)
fig.figimage(im, fig.bbox.xmax - width, fig.bbox.ymax - height, zorder=0)
# (Saving with the same dpi as the screen default to
# avoid displacing the logo image)
fig.savefig('temp.png', dpi=80)
plt.show()
Produces the following result (imaged cropped to save space).
Changing the zorder=1 will place the image on top.
Other helpful references:
How to change background color for scatter plot in matplotlib
How do you change the size of figures drawn with matplotlib?
Python/Matplotlib - Change the relative size of a subplot
In Matplotlib, what does the argument mean in fig.add_subplot(111)?
Customizing Location of Subplot Using GridSpec
You can use basemap toolkit to load and plot shapefile. Here I've plotted shapeFile in a separate axes and aligned it to top-right of other axes plot using 'subplot2grid'.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import matplotlib.gridspec as gridspec
def plotShapeFile():
# Lambert Conformal Conic map.
m = Basemap(llcrnrlon=-100.,llcrnrlat=0.,urcrnrlon=-20.,urcrnrlat=57.,
projection='lcc',lat_1=20.,lat_2=40.,lon_0=-60.,
resolution ='l',area_thresh=1000.)
# read shapefile.
shp_info = m.readshapefile('C:/basemap-1.0.6/basemap-1.0.6/examples/huralll020','hurrtracks',drawbounds=False)
# find names of storms that reached Cat 4.
names = []
for shapedict in m.hurrtracks_info:
cat = shapedict['CATEGORY']
name = shapedict['NAME']
if cat in ['H4','H5'] and name not in names:
# only use named storms.
if name != 'NOT NAMED': names.append(name)
# plot tracks of those storms.
for shapedict,shape in zip(m.hurrtracks_info,m.hurrtracks):
name = shapedict['NAME']
cat = shapedict['CATEGORY']
if name in names:
xx,yy = zip(*shape)
# show part of track where storm > Cat 4 as thick red.
if cat in ['H4','H5']:
m.plot(xx,yy,linewidth=1.5,color='r')
elif cat in ['H1','H2','H3']:
m.plot(xx,yy,color='k')
# draw coastlines, meridians and parallels.
m.drawcoastlines()
m.drawcountries()
m.drawmapboundary(fill_color='#99ffff')
m.fillcontinents(color='#cc9966',lake_color='#99ffff')
m.drawparallels(np.arange(10,70,20),labels=[1,1,0,0])
m.drawmeridians(np.arange(-100,0,20),labels=[0,0,0,1])
if __name__ == '__main__':
fig=plt.figure()
plt.subplots_adjust(wspace=0.001, hspace=0.001)
ax1=plt.subplot2grid((5,5), (0,0), colspan=4, rowspan=4)
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
fracs = [15,30,45, 10]
explode=(0, 0.05, 0, 0)
p1,t1,at1 = plt.pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True)
plt.title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5})
ax2=plt.subplot2grid((5,5), (0,4), colspan=1, rowspan=1)
#draw shapeFile on the current active axes, i.e. ax2
plotShapeFile()
plt.tight_layout()
plt.show()
Below are links to references I've used:
http://sourceforge.net/projects/matplotlib/files/matplotlib-toolkits/basemap-1.0.6/
http://matplotlib.org/basemap/users/examples.html
Output:

Stretching axis ticks to fit compressed image

I have a PyQt4 Application in which I am representing a 16bit grayscale image using matplotlib. The image I'm representing are quite large. Due to memory limitations I'm unfortunately not able to represent the bigger images, so I'm slicing them in this way:
ImageDataArray[::ratio, ::ratio]
When showing the plots, the axis are compressed depending on the ratio. Hence the coordinates of the image is of importance to know where the information of interest is loacated, I want to stretch the axis again by the factor of ratio.
How can I manage this, so the correct coordinates are shown even if I use the zoom function from the matplotlib toolbar?
Thanks in advance.
Code:
from numpy import fromfile, uint16, shape
import matplotlib.pyplot as plt
data = fromfile('D:\\ImageData.raw', dtype=uint16)
data.resize((ysize,xsize))
xmin = 0
ymin = 0
xmax = shape(data)[1]
ymax = shape(data)[0]
ratio = max(max(shape(data)[0], shape(data)[1])/2000, 1)
data_slice = data[ymin:ymax:ratio, xmin:xmax:ratio]
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.imshow(data_slice, cmap='gray', interpolation='nearest')
plt.show()
You want to use the extent keyword argument of imshow (doc)
ax.imshow(...,extent=[xmin,xmax,ymin,ymax])

Adding a grid on top of a tif image in python

Hi I was wondering how to add a grid on top of my image then display it in python.
Here is a picture of what I want to do. NOTE: I also want to specify the line type and color for some of the blocks in the image just like the image below.
Thanks a lot.
The example below shows how to display a .tif file, create a grid, but also how to put the grid below the other plot elements so that you can draw boxes and lines on top of the image and the grid.
import matplotlib.pyplot as plt
from PIL import Image
import matplotlib.patches as mpatches
im = Image.open('stinkbug.tif')
# Flip the .tif file so it plots upright
im1 = im.transpose(Image.FLIP_TOP_BOTTOM)
# Plot the image
plt.imshow(im1)
ax = plt.gca()
# create a grid
ax.grid(True, color='r', linestyle='--', linewidth=2)
# put the grid below other plot elements
ax.set_axisbelow(True)
# Draw a box
xy = 200, 200,
width, height = 100, 100
ax.add_patch(mpatches.Rectangle(xy, width, height, facecolor="none",
edgecolor="blue", linewidth=2))
plt.draw()
plt.show()
You can use matplotlib.patches to draw all types of shapes over your image. To draw individual lines, I like to use the following line, but you can also use matplotlib.lines.Line2D.
plt.axvline(x=0.069, ymin=0, ymax=40, linewidth=4, color='r')
There's imshow function for displaying the image. Displaying the grid on top of the axes is as simple as grid(True).