Multiple PIL images into one single plot - python

I have a n amount of images with a format:
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=64x64 at 0x7F555F6E3898>
all together in a list.
I can visualize each individually but I want to visualize them all together, one beside another until it gets too long and then go to the next row (for instance, n/4 rows with 4 images in each row). Once this is done, I would like to save it as a jgp as well.
I tried using subplot from matplotlib but it says that the values are unhashable.
My code is:
from os import listdir
from os.path import isfile, join
files = [f for f in listdir(mypath) if isfile(join(mypath, f))]
files.sort()
files.sort(key = len)
im = []
for jpg in files:
im.append(Image.open(mypath+'/'+jpg))
for i in im:
image = np.asarray(i)
plt.subplot(3,np.floor(len(image)/3),image)
plt.show()

update your usage for subplot, then it should be good. please see below sample code.
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
# get sample data
from sklearn import datasets
x,y=datasets.load_digits(n_class=10, return_X_y=True)
x = x[0:100,:]
x = np.reshape(x,[100,8,8])
# plot
for i in range(x.shape[0]):
if i >= 9:
break
image = x[i,:].squeeze()
plt.subplot(3,3,i+1)
plt.imshow(image,cmap='gray',interpolation='none')
alternatively:
# https://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html
from mpl_toolkits.axes_grid1 import ImageGrid
fig = plt.figure(1,(10,10))
grid = ImageGrid(fig, 111,
nrows_ncols=(2,7),
axes_pad=0.1,
)
for i in range(14):
image = x[i,:].squeeze()
grid[i].imshow(image,cmap='gray',interpolation='none')

Related

execute .py file, call python function in for loop

I have a function 'plot_rdm', which creates a plot and saves it as 'rdm.png'. I want several of these plots to be formed, each using a different .json file - so I have the function plot_rdm saved in 'plotrdm.py'.
In the saverdm.py file - I defined the filepath of the .json file I want to create a plot from and then called the plot_rdm function, looping over all of the files I want to create a plot from:
#import libraries
import numpy as np
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt
import scipy
import scipy.spatial
import scipy.spatial.distance as sd
from scipy.spatial.distance import squareform
import os
import json
# define fpath
#i.e. fpath[0] will be the first filepath...
path = './RDM_researchproject'
rootdir = path
filepath = []
for subdir, dirs, files in os.walk(rootdir):
for file in files:
if file.startswith('Meadows'):
count=0 # count default
filepath.append(os.path.join(subdir, file))
fpath = filepath[count]
os.system("/home/taran/RDM_researchproject/AVIMA/plotrdm.py")
count +=1
The plotrdm.py file with the plot_rdm function is as follows:
def plot_rdm(fpath):
import numpy as np
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt
import scipy
import scipy.spatial
import scipy.spatial.distance as sd
from scipy.spatial.distance import squareform
import json
with open(fpath) as fhandle:
data = json.load(fhandle)
#inspect rdm stimuli labels
stim = data['stimuli']
#contain all labels for y axis and x axis seperately
y_names = []
for i in stim:
y_names.append(i['name'])
x_names = []
for i in stim:
x_names.append(i['name'])
#create rdm array and squareform
rdm_array = np.array(data['rdm'])
srdm = squareform(rdm_array)
#label x and y axis on rdm
fig, ax = plt.subplots()
rdm = ax.imshow(srdm)
ax.set_xticks(np.arange(len(x_names)))
ax.set_yticks(np.arange(len(y_names)))
ax.set_xticklabels(x_names)
ax.set_yticklabels(y_names)
plt.setp(ax.get_xticklabels(), rotation=90, ha="right", rotation_mode="anchor")
plt.plot(srdm)
plt.imshow(srdm)
plt.colorbar(mappable = None, cax = None, ax = None)
fig.subplots_adjust(bottom=0.23)
import matplotlib.pyplot as plt
plt.savefig('rdm.png')
I am able to create the plots individually (i.e. when I don't call the plot_rdm function and loop over the files but I specify the filepath each time). But when I use the following code, I get an empty plot forming in the AVIMA folder. I'm not sure what's wrong in the saverdm file making this happen?
https://github.com/Taranks7/RDM_researchproject If I haven't explained what's going on well, this is the project I'm working on.
Thank you
When you want to call a python function from another file, you should not try to run another python process by calling os.system. Just import that function:
from plotrdm import plot_rdm
Instead of using os.filewalk and a file.startswith check, we can cleanup the code a lot by using the nice python library glob. I throw in a enumerate for good measure.
Your new rdmsave.py
import glob
from plotrdm import plot_rdm
basedir = "."
if __name__ == "__main__":
count = 0
for count, path in enumerate(sorted(glob.glob(f'{basedir}/**/Meadow*.json', recursive=True)), start=1):
print(f"processing {path}")
output_image = f'rdm_{count - 1:02}.png'
print(f"output image will be {output_image}")
plot_rdm(path, output_image)
print(f"processed {count} files")
Note that you may need to change basedir back to your local path.
And your plotrdm.py becomes:
import numpy as np
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt
import scipy
import scipy.spatial
import scipy.spatial.distance as sd
from scipy.spatial.distance import squareform
import json
import matplotlib.pyplot as plt
def plot_rdm(fpath, output_filename):
with open(fpath) as fhandle:
data = json.load(fhandle)
# inspect rdm stimuli labels
stim = data['stimuli']
# contain all labels for y axis and x axis seperately
y_names = []
for i in stim:
y_names.append(i['name'])
x_names = []
for i in stim:
x_names.append(i['name'])
# create rdm array and squareform
rdm_array = np.array(data['rdm'])
srdm = squareform(rdm_array)
# label x and y axis on rdm
fig, ax = plt.subplots()
rdm = ax.imshow(srdm)
ax.set_xticks(np.arange(len(x_names)))
ax.set_yticks(np.arange(len(y_names)))
ax.set_xticklabels(x_names)
ax.set_yticklabels(y_names)
plt.setp(ax.get_xticklabels(), rotation=90, ha="right", rotation_mode="anchor")
plt.plot(srdm)
plt.imshow(srdm)
plt.colorbar(mappable=None, cax=None, ax=None)
fig.subplots_adjust(bottom=0.23)
plt.savefig(output_filename)
I added the second argument output_filename to the plot_rdm function to make it possible to store each image in a new file.
The output on my machine reads
processing ./5/Meadows_avima-image-version1_v_v2_vital-macaw_2_tree.json
output image will be rdm_00.png
processing ./4/Meadows_avima-image-version1_v_v2_quick-louse_2_tree.json
output image will be rdm_01.png
processing ./1/Meadows_avima-image-version1_v_v2_better-hound_2_tree.json
output image will be rdm_02.png
processing ./3/Meadows_avima-image-version1_v_v2_huge-falcon_2_tree.json
output image will be rdm_03.png
processing ./2/Meadows_avima-image-version1_v_v2_guided-koi_2_tree.json
output image will be rdm_04.png
processed 4 files
And 4 png files are created in the current folder.

How to name graphs in legend based on folder's name

I have plotted a graph for different sub-folders inside of a directory and I want to put a legend of each graph based on the name of the folder. I mean, the plot legend is being to be written according to the folder's name. The code for plotting is below:
from __future__ import division
import sys
import os
import numpy as np
import matplotlib.pyplot as plt
import glob
import seaborn as sns
from scipy import stats
from scipy.stats.kde import gaussian_kde
root = r'C:\Users\Hasan\Desktop\output\new our scenario\beta 15\test'
mean_cu=[]
my_list = os.listdir(root)
my_list = [file for file in my_list if os.path.isdir(os.path.join(root, file))]
for directory in my_list:
CASES = [file for file in os.listdir(os.path.join(root, directory)) if file.startswith('config')]
if len(CASES)==0:
continue
maxnum = np.max([int(os.path.splitext(f)[0].split('_')[1]) for f in CASES])
CASES = ['configuration_%d.out' % i for i in range(maxnum)]
mean_cu=[]
for i, d in enumerate(CASES):
a = np.loadtxt(os.path.join(root, directory,d)).T
num = os.path.splitext(d)[0]
local_cu = np.abs(a[4])
mean_curv.append(np.mean(local_cu))
pdf = stats.norm.pdf(mean_cu)
Time = np.arange(0,len(pdf))
plt.plot(Time,pdf)
From what I understand, you have different graphs, and for each of them you want a different legend based on current folder. You can set legend by adding label=directory in plot method. Maybe you should first extract current folder (using split or different method) if you don't want full directory. That depends on your directory variable.
Consider following example:
import matplotlib.pyplot as plt
import pandas as pd
legend1 = ["1", "2"]
df = pd.DataFrame({"A":[4,5], "B":[6,7]})
for item in legend1:
fig, ax = plt.subplots()
ax.plot(df["A"], df["B"], label=item)
ax.legend(loc='upper left', frameon=False)
will result the following two graphs:
As you can see the only different is the legend, that was set by legend1 list. You can make it your directories.

Python : How to place a shapefile on top of raster file in one plot, and then save the plot in a Jpeg file format

I am posting this question after three days searching the net but no success. Hope can get the answer here. Please do NOT delete the post as I did not find an answer for it here also. Thanks.
I have 2 files:
A raster image file (i.e., Air temperature 2020-01-01.tif)
World countries boundary shapefile ((i.e., World_Countries_base_map.shp)
Goal: I want to plot the shapefile on top of raster file, and then save the plot in a Jpeg file format to get something like this eventually:
I am quite new in Python, and used Spyder to prepare this simple code to do so:
# Import needed packages
import os
import rasterio
import matplotlib.pyplot as plt
import geopandas as gpd
import earthpy as et
from matplotlib import pyplot
## list all raster images in tiff format in the folder:
list_files = [f for f in
os.listdir('C:/Users/Desktop/Question/Raster_Air_temp')
if '.tif' in f]
print(list_files[1]) # checking the 1st file in the list
## reading the first tiff file:
raster_image = rasterio.open(list_files[1])
## plot it
draft_output = pyplot.imshow(raster_image.read(1), cmap='jet')
## importing world shapefile
World_map = gpd.read_file('C:/Users/Desktop/Question/World_shapefile/World_Countries_base_map.shp')
# plot World shapefile
fig, ax = plt.subplots(figsize = (30,30)) # image size and quality can be controled by figsize
ax.set_title('The Glob Map', fontsize=50);
World_map.plot(ax=ax, color='white', edgecolor='black') # colors note at https://matplotlib.org/tutorials/colors/colormaps.html
plt.show()
## Plot both World shapefile and raster image in one graph:
????
However, this code just produces 2 separated plots in the console for me as can be seen above.
Question: How can I type a proper code in ???? section of the code to get to my Goal (mentioned above)?
Thanks to all comments and helps.
Here, I share the two files in order to make it easier for those who want help.
Download the files from my Dropbox
.
since i have no access to your data I am showing the principle with some sample data from geopandas and a random numpy ndarray as a tiff surrogate.
the key point is to show the tiff with rasterios rasterplot and don't forget to set the extent of your DEM!
import rasterio
import numpy as np
from rasterio import plot as rasterplot
import geopandas as gpd
from matplotlib import pyplot as plt
# this is how you'd open the raster dataset if you have one
#tiff = rasterio.open('example.tif')
#tiff_extent = [tiff.bounds[0], tiff.bounds[2], tiff.bounds[1], tiff.bounds[3]]
# i am making this array up
tiff_band_1 = np.random.randint(0, 10, size=(65, 64))
tiff_extent = [4159200.0, 4808100.0, 2828000.0, 3482600.0]
shapefile = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
shapefile = shapefile.to_crs('epsg:3035')
shapefile = shapefile[shapefile.name == 'Germany']
f, ax = plt.subplots()
# plot DEM
rasterplot.show(
tiff_band_1, # use tiff.read(1) with your data
extent=tiff_extent,
ax=ax,
)
# plot shapefiles
shapefile.plot(ax=ax, facecolor='w', edgecolor='k')
plt.savefig('test.jpg')
plt.show()

pie chart label overlap

I am having problems generating a graph which doesn't overlap with text both for percentages and country codes, I am using python3 matplotlib, see image below.
Any ways of fixing this issue even if it changes layout are appreciated.
from collections import Counter
import numpy as np
import matplotlib.pyplot as plt
import json
countries = []
import os
path = 'data_used_for_graph'
entries = os.listdir(path)
for file in entries:
with open(path+"/"+file) as f:
content = json.load(f)
for x in content['personalNames']:
countries.append(x['countryOrigin'])
counts = Counter(countries)
labels, values = zip(*counts.items())
# sort your values in descending order
indSort = np.argsort(values)[::-1]
# rearrange your data
labels = np.array(labels)[indSort]
values = np.array(values)[indSort]
# Data to plot
sizes = values
# Plot
plt.pie(sizes, labels=labels,autopct='%1.1f%%', shadow=True, startangle=140)
plt.show()

Imaging simulation slice and adding a shape

I have been making slice images of a simulation, now I need to add a shape to the image, the slice has a colour map, I add a circle to the slice, I need help with making the circle colour be adjustable by values, and share the same colormap as the slice.The code I use is:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import csv
def readslice(ndim):
shape = (ndim,ndim,ndim)
fd = open("delta_T_v3_no_halos_z013.40_nf0.898994_useTs0_zetaX-1.0e+00_alphaX-1.0_TvirminX-1.0e+00_aveTb027.03_Pop-1_300_200Mpc", 'rb')
data = np.fromfile(file=fd, dtype= np.dtype('f4')).reshape(shape)
fd.close()
print data
return data
ff = readslice(300)
circle1=plt.Circle((150.0,150.0),50.0)
fig = plt.gcf()
fig.gca().add_artist(circle1)
plt.imshow(ff[0,:,:],cmap = cm.jet)
plt.colorbar()
plt.savefig('picwithcircle.png')
plt.show()

Categories