I just started to program (with Python) because I needed to develop a kind of executable that allows me to perform diameter distributions. I managed to get to something that works (code below):
# Put here all modules you would need in order to represent your data
import matplotlib.pylab as plt
import numpy as np
import collections as c
from collections import Counter
from PIL import Image
import matplotlib.mlab as mlab
from scipy.optimize import curve_fit
import Tkinter as tk
from tkFileDialog import askopenfilename
# This prints the plot containing the diameter distribution of our sample
root = tk.Tk() ; root.withdraw()
filename = askopenfilename(parent=root)
f = open(filename)
with f as input: #Change the Results.txt file for your own .txt file
a = zip(*(line.strip().split('\t') for i,line in enumerate(input) if i != 0))
areas = a[1]
diam = []
for area in areas:
diam.append(round((np.sqrt(float(area)/ np.pi) * 2), 3)) # The number 3 tells us how many decimals will be shown
hist, bins = np.histogram(diam, 50)
diam.sort()
counts = c.Counter(diam)
'''This prints the table which includes all diameter values
and how many of them we can find on our sample# '''
table = sorted(counts.items())
col_labels = ['Diameter (nm)', 'Counts'] # In Diameter column you can add the units inside the empty parenthesis
table_vals = table
q = diam
mu = sum(q)/float(len(q))
variance = np.var(q)
sigma = np.sqrt(variance)
# In the plt.suptitle part --> change the default name to your sample name
plt.subplot(121)
plt.bar(counts.keys(), counts.values(), 0.01, color="black")
plt.tick_params(direction = 'out', labeltop='off', labelright='off')
plt.xlabel('Diameter (nm)', fontsize=16, fontweight='bold')
plt.ylabel('Count (a.u.)', fontsize=16, fontweight='bold')
plt.title(r'$\mathregular{Diameter \ distribution\ of \ the\ sample:}\ \mu=%.3f,\ \sigma=%.3f$' % (mu, sigma), fontsize=18, fontweight='bold')
plt.suptitle('Silicon nanopillars grown epitaxially', fontsize=22, fontweight='bold')
plt.autoscale(enable=True, axis='x', tight=None)
the_table = plt.table(cellText = table_vals, colLabels = col_labels, loc = 'bottom', cellLoc = 'center', bbox = [0.67, 0.18, 0.30, 0.8])
the_table.auto_set_font_size(False)
the_table.set_fontsize(12)
# This adds a gaussian fit to our histogram
plt.plot()
x = diam
yhist, xhist = np.histogram(x, bins=np.arange(4096))
xh = np.where(yhist > 0)[0]
yh = yhist[xh]
def gaussian(x, a, mu, sigma):
return a * np.exp(-((x - mu)**2 / (2 * sigma**2)))
popt, pcov = curve_fit(gaussian, xh, yh, [1, mu, sigma])
i = np.linspace(min(diam)-20, max(diam), 1000)
plt.plot(i, gaussian(i, *popt), lw=3, ls=':', c='r')
plt.xlim(min(diam)-10, max(diam)+10)
# This adds the image from where the data is extracted (always use .png images otherwise this won't work)
im = Image.open('Dosi05.png') # Put here the original image
im2 = Image.open('Dosi05_Analyzed.png') # Put here the thresholded and analysed image
plt.subplot(222)
plt.imshow(im, cmap='gray')
plt.axis('off')
plt.title('Original Image', fontsize=14, fontweight='bold')
plt.subplot(224)
plt.imshow(im2, cmap='gray')
plt.axis('off')
plt.title('Processed Image', fontsize=14, fontweight='bold')
plt.show()
But I was asked to do the same that is done with the .txt file but with the images ploted using plt.subplot(222) and plt.subplot(224) in order to avoid touching the code.
I tried by doing something similar also using Tkinter (see code below):
# Put here all modules you would need in order to represent your data
import matplotlib.pylab as plt
import numpy as np
import collections as c
from collections import Counter
from PIL import Image
import matplotlib.mlab as mlab
from scipy.optimize import curve_fit
import Tkinter as tk
from tkFileDialog import askopenfilename, askopenfile
from skimage import data
# This prints the plot containing the diameter distribution of our sample
root = tk.Tk() ; root.withdraw()
filename = askopenfilename(parent=root)
f = open(filename)
with f as input: #Change the Results.txt file for your own .txt file
a = zip(*(line.strip().split('\t') for i,line in enumerate(input) if i != 0))
areas = a[1]
diam = []
for area in areas:
diam.append(round((np.sqrt(float(area)/ np.pi) * 2), 3)) # The number 3 tells us how many decimals will be shown
hist, bins = np.histogram(diam, 50)
diam.sort()
counts = c.Counter(diam)
'''This prints the table which includes all diameter values
and how many of them we can find on our sample# '''
table = sorted(counts.items())
col_labels = ['Diameter (nm)', 'Counts'] # In Diameter column you can add the units inside the empty parenthesis
table_vals = table
q = diam
mu = sum(q)/float(len(q))
variance = np.var(q)
sigma = np.sqrt(variance)
# In the plt.suptitle part --> change the default name to your sample name
plt.subplot(121)
plt.bar(counts.keys(), counts.values(), 0.01, color="black")
plt.tick_params(direction = 'out', labeltop='off', labelright='off')
plt.xlabel('Diameter (nm)', fontsize=16, fontweight='bold')
plt.ylabel('Count (a.u.)', fontsize=16, fontweight='bold')
plt.title(r'$\mathregular{Diameter \ distribution\ of \ the\ sample:}\ \mu=%.3f,\ \sigma=%.3f$' % (mu, sigma), fontsize=18, fontweight='bold')
plt.suptitle('Silicon nanopillars grown epitaxially', fontsize=22, fontweight='bold')
plt.autoscale(enable=True, axis='x', tight=None)
the_table = plt.table(cellText = table_vals, colLabels = col_labels, loc = 'bottom', cellLoc = 'center', bbox = [0.67, 0.18, 0.30, 0.8])
the_table.auto_set_font_size(False)
the_table.set_fontsize(12)
# This adds a gaussian fit to our histogram
plt.plot()
x = diam
yhist, xhist = np.histogram(x, bins=np.arange(4096))
xh = np.where(yhist > 0)[0]
yh = yhist[xh]
def gaussian(x, a, mu, sigma):
return a * np.exp(-((x - mu)**2 / (2 * sigma**2)))
popt, pcov = curve_fit(gaussian, xh, yh, [1, mu, sigma])
i = np.linspace(min(diam)-20, max(diam), 1000)
plt.plot(i, gaussian(i, *popt), lw=3, ls=':', c='r')
plt.xlim(min(diam)-10, max(diam)+10)
# This adds the image from where the data is extracted (always use .png images otherwise this won't work)
image_formats = [('PNG','*.png')]
file_path_list = askopenfilename(filetypes=image_formats, initialdir='/', title='Please select a picture to analyze')
for file_path in file_path_list:
image = data.imread(file_path)
image2 = data.imread(file_path)
plt.subplot(222)
plt.imshow(image, cmap='gray')
plt.axis('off')
plt.title('Original Image', fontsize=14, fontweight='bold')
plt.subplot(224)
plt.imshow(image2, cmap='gray')
plt.axis('off')
plt.title('Processed Image', fontsize=14, fontweight='bold')
plt.show()
But after selecting the first image file, Python throws me the following:
[IOError: [Errno 22] invalid mode ('rb') or filename: '\x89PNG\n' 1
Can someone tell me what I can do to solve this or if there are other ways to display the images by picking the from the file browser instead of changing them in the code itself?
Hope the question is enough clear, thanks for your help in advance!
Y
The retrun value of askopenfilename
is a string. As you were traversing over a string (Probabily a path like C:\Somepath\someimage.png
) you got the following error.
Errno2: No such file or directory: u'C'
You need to use the askopenfilenames
module to get multiple files.
image_formats = [('PNG','*.png')]
file_path_list = askopenfilenames(filetypes=image_formats, initialdir='/', title='Please select a picture to analyze')
for file_path in file_path_list:
file_path = os.path.normpath(file_path) # To normalize path
image = data.imread(file_path)
image2 = data.imread(file_path)
Use for file_path in file_path_list.split()
for python<2.7.7, as the return value was a string instead of tuple.
https://docs.python.org/2/library/os.path.html#os.path.normpath
Orignal Question
Op had pasted code with askopenfile
instead of askopenfilename
tkFileDialog.askopenfile
returns selected file opened in r
mode if mode
is not specified.
def askopenfile(mode = "r", **options):
"Ask for a filename to open, and returned the opened file"
filename = Open(**options).show()
if filename:
return open(filename, mode)
return None
While the input to imread
is image file path.
You need to use askopenfilenames
which returns selected files path.