First committing

This commit is contained in:
2022-04-08 17:39:57 +02:00
commit 6b9d1f4a61
71 changed files with 10349 additions and 0 deletions

3120
AFM_thumbs.py Executable file

File diff suppressed because it is too large Load Diff

BIN
AFM_thumbs.pyc Executable file

Binary file not shown.

425
AFM_thumbs/Channel.py Executable file
View File

@@ -0,0 +1,425 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import re
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import ID_list
from AFM_thumbs.Variables import globvar_color_dict
from AFM_thumbs.Variables import globvar_spaces
def rename_channel(name):
if re.search(ID_list[0],name):
globvar_AFMdata.channel.append("Topography")
elif re.search(ID_list[4],name):
if re.search(ID_list[5],name):
globvar_AFMdata.channel.append("filtered df")
else:
globvar_AFMdata.channel.append("df")
elif re.search(ID_list[1],name):
globvar_AFMdata.channel.append("Amplitude")
elif re.search(ID_list[6],name):
globvar_AFMdata.channel.append("Dissipation")
elif re.search(ID_list[2],name):
if re.search(ID_list[3],name):
globvar_AFMdata.channel.append("Kelvin Error")
else:
globvar_AFMdata.channel.append("Kelvin")
elif re.search(ID_list[8],name):
globvar_AFMdata.channel.append("Ext 1")
elif re.search(ID_list[9],name):
globvar_AFMdata.channel.append("Ext 2")
elif re.search(ID_list[7],name):
globvar_AFMdata.channel.append("Excitation")
elif re.search(ID_list[10],name):
globvar_AFMdata.channel.append("Phase")
else:
found = False
for chan in globvar_ThumbPara.channel_names:
if not chan == "":
if re.search(chan,name):
found = True
globvar_AFMdata.channel.append(name)
if not found:
print(globvar_spaces + " Channel not found: " + name)
return False
return True
def proceed_with(image_nr,direction):
if globvar_AFMdata.channel[image_nr] == "Topography":
if direction == "forward" and globvar_ThumbPara.thumbs[0]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[1]:
return True
elif globvar_AFMdata.channel[image_nr] == "df":
if not globvar_AFMdata.channel[image_nr] == "filtered":
if direction == "forward" and globvar_ThumbPara.thumbs[2]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[3]:
return True
elif globvar_AFMdata.channel[image_nr] == "Dissipation":
if direction == "forward" and globvar_ThumbPara.thumbs[4]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[5]:
return True
elif globvar_AFMdata.channel[image_nr] == "Amplitude":
if direction == "forward" and globvar_ThumbPara.thumbs[6]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[7]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin":
if not globvar_AFMdata.channel[image_nr] == "Error":
if direction == "forward" and globvar_ThumbPara.thumbs[8]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[9]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin Error":
if direction == "forward" and globvar_ThumbPara.thumbs[10]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[11]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 1":
if direction == "forward" and globvar_ThumbPara.thumbs[12]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[13]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 2":
if direction == "forward" and globvar_ThumbPara.thumbs[14]:
return True
elif direction == "backward" and globvar_ThumbPara.thumbs[15]:
return True
else:
for i, chan in enumerate(globvar_ThumbPara.channel_names):
if not chan == "":
if re.search(chan,globvar_AFMdata.channel[image_nr]):
if direction == "forward" and \
globvar_ThumbPara.thumbs[2*i+16]:
return True
elif direction == "backward" and \
globvar_ThumbPara.thumbs[2*i+17]:
return True
return False
def line_fit(image_nr,direction):
if globvar_AFMdata.channel[image_nr] == "Topography":
if direction == "forward" and globvar_ThumbPara.line_fit[0]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[1]:
return True
elif globvar_AFMdata.channel[image_nr] == "df":
if direction == "forward" and globvar_ThumbPara.line_fit[2]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[3]:
return True
elif globvar_AFMdata.channel[image_nr] == "Dissipation":
if direction == "forward" and globvar_ThumbPara.line_fit[4]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[5]:
return True
elif globvar_AFMdata.channel[image_nr] == "Amplitude":
if direction == "forward" and globvar_ThumbPara.line_fit[6]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[7]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin":
if direction == "forward" and globvar_ThumbPara.line_fit[8]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[9]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin Error":
if direction == "forward" and globvar_ThumbPara.line_fit[10]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[11]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 1":
if direction == "forward" and globvar_ThumbPara.line_fit[12]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[13]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 2":
if direction == "forward" and globvar_ThumbPara.line_fit[14]:
return True
elif direction == "backward" and globvar_ThumbPara.line_fit[15]:
return True
else:
for i, chan in enumerate(globvar_ThumbPara.channel_names):
if not chan == "":
if re.search(chan,globvar_AFMdata.channel[image_nr]):
if direction == "forward" and \
globvar_ThumbPara.line_fit[2*i+16]:
return True
elif direction == "backward" and \
globvar_ThumbPara.line_fit[2*i+17]:
return True
return False
def plane_fit(image_nr,direction):
if globvar_AFMdata.channel[image_nr] == "Topography":
if direction == "forward" and globvar_ThumbPara.plane_fit[0]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[1]:
return True
elif globvar_AFMdata.channel[image_nr] == "df":
if direction == "forward" and globvar_ThumbPara.plane_fit[2]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[3]:
return True
elif globvar_AFMdata.channel[image_nr] == "Dissipation":
if direction == "forward" and globvar_ThumbPara.plane_fit[4]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[5]:
return True
elif globvar_AFMdata.channel[image_nr] == "Amplitude":
if direction == "forward" and globvar_ThumbPara.plane_fit[6]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[7]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin":
if direction == "forward" and globvar_ThumbPara.plane_fit[8]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[9]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin Error":
if direction == "forward" and globvar_ThumbPara.plane_fit[10]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[11]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 1":
if direction == "forward" and globvar_ThumbPara.plane_fit[12]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[13]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 2":
if direction == "forward" and globvar_ThumbPara.plane_fit[14]:
return True
if direction == "backward" and globvar_ThumbPara.plane_fit[15]:
return True
else:
for i, chan in enumerate(globvar_ThumbPara.channel_names):
if not chan == "":
if re.search(chan,globvar_AFMdata.channel[image_nr]):
if direction == "forward" and \
globvar_ThumbPara.plane_fit[2*i+16]:
return True
elif direction == "backward" and \
globvar_ThumbPara.plane_fit[2*i+17]:
return True
return False
def invert(image_nr,direction):
if not (direction == "forward" or direction == "backward"):
if image_nr%2 == 0:
direction = "forward"
elif image_nr%2 != 0:
direction = "backward"
if globvar_AFMdata.channel[image_nr] == "Topography":
if direction == "forward" and globvar_ThumbPara.invert[0]:
return True
if direction == "backward" and globvar_ThumbPara.invert[1]:
return True
elif globvar_AFMdata.channel[image_nr] == "df":
if direction == "forward" and globvar_ThumbPara.invert[2]:
return True
if direction == "backward" and globvar_ThumbPara.invert[3]:
return True
elif globvar_AFMdata.channel[image_nr] == "Dissipation":
if direction == "forward" and globvar_ThumbPara.invert[4]:
return True
if direction == "backward" and globvar_ThumbPara.invert[5]:
return True
elif globvar_AFMdata.channel[image_nr] == "Amplitude":
if direction == "forward" and globvar_ThumbPara.invert[6]:
return True
if direction == "backward" and globvar_ThumbPara.invert[7]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin":
if direction == "forward" and globvar_ThumbPara.invert[8]:
return True
if direction == "backward" and globvar_ThumbPara.invert[9]:
return True
elif globvar_AFMdata.channel[image_nr] == "Kelvin Error":
if direction == "forward" and globvar_ThumbPara.invert[10]:
return True
if direction == "backward" and globvar_ThumbPara.invert[11]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 1":
if direction == "forward" and globvar_ThumbPara.invert[12]:
return True
if direction == "backward" and globvar_ThumbPara.invert[13]:
return True
elif globvar_AFMdata.channel[image_nr] == "Ext 2":
if direction == "forward" and globvar_ThumbPara.invert[14]:
return True
if direction == "backward" and globvar_ThumbPara.invert[15]:
return True
else:
for i, chan in enumerate(globvar_ThumbPara.channel_names):
if not chan == "":
if re.search(chan,globvar_AFMdata.channel[image_nr]):
if direction == "forward" and \
globvar_ThumbPara.invert[2*i+16]:
return True
elif direction == "backward" and \
globvar_ThumbPara.invert[2*i+17]:
return True
return False
def define_color(color):
if color in globvar_color_dict:
return globvar_color_dict[color]
else:
return globvar_color_dict["Grey"]
def select_color(image_nr,direction):
if not (direction == "forward" or direction == "backward"):
if image_nr%2 == 0:
direction = "forward"
elif image_nr%2 != 0:
direction = "backward"
if globvar_AFMdata.channel[image_nr] == "Topography":
if direction == "forward":
return globvar_ThumbPara.colors[0]
if direction == "backward":
return globvar_ThumbPara.colors[1]
elif globvar_AFMdata.channel[image_nr] == "df":
if direction == "forward":
return globvar_ThumbPara.colors[2]
if direction == "backward":
return globvar_ThumbPara.colors[3]
elif globvar_AFMdata.channel[image_nr] == "Dissipation":
if direction == "forward":
return globvar_ThumbPara.colors[4]
if direction == "backward":
return globvar_ThumbPara.colors[5]
elif globvar_AFMdata.channel[image_nr] == "Amplitude":
if direction == "forward":
return globvar_ThumbPara.colors[6]
if direction == "backward":
return globvar_ThumbPara.colors[7]
elif globvar_AFMdata.channel[image_nr] == "Kelvin":
if direction == "forward":
return globvar_ThumbPara.colors[8]
if direction == "backward":
return globvar_ThumbPara.colors[9]
elif globvar_AFMdata.channel[image_nr] == "Kelvin Error":
if direction == "forward":
return globvar_ThumbPara.colors[10]
if direction == "backward":
return globvar_ThumbPara.colors[11]
elif globvar_AFMdata.channel[image_nr] == "Ext 1":
if direction == "forward":
return globvar_ThumbPara.colors[12]
if direction == "backward":
return globvar_ThumbPara.colors[13]
elif globvar_AFMdata.channel[image_nr] == "Ext 2":
if direction == "forward":
return globvar_ThumbPara.colors[14]
if direction == "backward":
return globvar_ThumbPara.colors[15]
else:
for i, chan in enumerate(globvar_ThumbPara.channel_names):
if not chan == "":
if re.search(chan,globvar_AFMdata.channel[image_nr]):
if direction == "forward":
return globvar_ThumbPara.colors[2*i+16]
elif direction == "backward":
return globvar_ThumbPara.colors[2*i+17]
return False

BIN
AFM_thumbs/Channel.pyc Executable file

Binary file not shown.

145
AFM_thumbs/Colour.py Executable file
View File

@@ -0,0 +1,145 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import sys
import os
import numpy as np
# The following is a bit confusing but needed for crontab and ssh under Linux:
# Matplotlib needs an X-Server, which does not exist when doing, e.g., ssh.
# In the following we ask if the DISPLAY variable of the Linux system is set.
# If this is not the case then we tell Python to do something special for
# matplotlib (use of 'Agg')
#
# From: "http://stackoverflow.com/questions/4931376/
# generating-matplotlib-graphs-without-a-running-x-server"
# Other solution: matplotlib API, see "http://www.dalkescientific.com/writings/
# diary/archive/2005/04/23/matplotlib_without_gui.html"
if sys.platform == "linux2":
environ = os.environ
if "DISPLAY" not in environ:
import matplotlib as mpl
mpl.use('Agg')
# This is a one time message, which is not included in thumbs.py
# Otherwise it is reproduced 2 times.
print("\n\n**** ATTENTION!\n" +
"**** No X-Server is detected under Linux. It seems that\n" +
"**** AFM_thumbs is executed via ssh or crontab ... no problem.\n\n")
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from AFM_thumbs.Variables import Color_list
from AFM_thumbs.Variables import globvar_color_options
def plot_color_gradients():
# Get the lenght of the colour list
nrows = len(Color_list)
# Gradients
gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))
fig, axes = plt.subplots(nrows=nrows)
fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99)
axes[0].set_title("Color maps", fontsize=14)
# Go through all colours.
for ax, colour, colourname in zip(axes, Color_list, globvar_color_options):
# What kind of color scale do we have?
# Is it a pre-definied color from matplotlib, then it must be a string.
if type(colour) is str:
colormap = colour
# If it is not a string, then it must be a color definied by ourselves,
# so go to here and transform this linear segment into a colormap.
else:
colormap = LinearSegmentedColormap("Colormap",colour)
# Prepare the plot
ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(colormap))
pos = list(ax.get_position().bounds)
x_text = pos[0] - 0.01
y_text = pos[1] + pos[3]/2.
fig.text(x_text, y_text, colourname,
va='center', ha='right', fontsize=10)
# Turn off *all* ticks & spines, not just the ones with colormaps.
for ax in axes:
ax.set_axis_off()
# Show the plot.
plt.show()
# This definition was taken from
# http://stackoverflow.com/questions/3279560/invert-colormap-in-matplotlib
# User Mattijn
def reverse_colourmap(ctype, cmap, name = 'my_cmap_r'):
"""
In:
cmap, name
Out:
my_cmap_r
Explanation:
t[0] goes from 0 to 1
row i: x y0 y1 -> t[0] t[1] t[2]
/
/
row i+1: x y0 y1 -> t[n] t[1] t[2]
so the inverse should do the same:
row i+1: x y1 y0 -> 1-t[0] t[2] t[1]
/
/
row i: x y1 y0 -> 1-t[n] t[2] t[1]
"""
if ctype == "LinearSegmentedColormap":
reverse = []
k = []
for key in cmap._segmentdata:
k.append(key)
channel = cmap._segmentdata[key]
data = []
for t in channel:
data.append((1-t[0],t[2],t[1]))
reverse.append(sorted(data))
LinearL = dict(zip(k,reverse))
my_cmap_r = LinearSegmentedColormap(name, LinearL)
elif ctype == "ListedColormap":
if cmap[-2:] == "_r":
my_cmap_r = cmap[:-2]
else:
my_cmap_r = cmap + "_r"
return my_cmap_r

BIN
AFM_thumbs/Colour.pyc Executable file

Binary file not shown.

308
AFM_thumbs/Command_line.py Executable file
View File

@@ -0,0 +1,308 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import os
import matplotlib
from optparse import OptionParser
from AFM_thumbs.Variables import RHK_special
from AFM_thumbs.Variables import globvar_fonts
from AFM_thumbs.Variables import globvar_bad_fonts
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_thumb_size_x
from AFM_thumbs.Variables import globvar_thumb_size_y
from AFM_thumbs.Variables import globvar_spaces
from AFM_thumbs.Initialize import initialize_check_config
from AFM_thumbs.Channel import define_color
def command_line():
print("\n\n")
parser = OptionParser(usage="usage: %prog [options]", version="%prog 1.6")
parser.add_option("-d", "--directory",
action="store",
type="string",
dest="directory",
help="the working directory, from which all other " \
"sub-directories are eventually considered " \
"(see config file of AFM_thumb).")
parser.add_option("-c", "--configfile",
action="store",
type="string",
dest="configfile",
help="the file path of the config file." \
" - This option only acts if the " \
"-d option is choosen.")
parser.add_option("-p", "--pdf",
action="store",
dest="pdf",
help="the path of the directory, in which the " \
"PDF files shall be stored into." \
" - This option only acts if the " \
"-d option is choosen.")
(options, args) = parser.parse_args()
# If the working directory (-d option) is set => command line, no GUI
if options.directory is not None:
# Does the working directory exist? If not => exit!
if not os.path.isdir(options.directory):
print("Usage: AFM_thumbs.py [options]\n\n" \
"AFM_thumbs.py: error: working directory does not exist!")
exit(-1)
# ............. Start without GUI
config_file = initialize_check_config(options.configfile)
read_configfile(config_file)
# Does a special pdf path exist?
if options.pdf is not None:
if os.path.isdir(options.pdf):
globvar_AFMdir.pdf_path = options.pdf
# Strange, the directory does not exist! Error and exit.
else:
print("Usage: AFM_thumbs.py [options]\n\n" \
"AFM_thumbs.py: error: The pdf directory " +
"'" + options.pdf + "' does not exist !")
exit(-1)
return (False, options.directory, config_file)
# If no options are set and there is nothing in args: start the GUI
elif options.directory == None and \
options.pdf == None and \
options.configfile == None and \
args == []:
return (True, None, None)
# -p option but where is the -d option?
elif options.pdf is not None:
print("Usage: AFM_thumbs.py [options]\n\n" \
"AFM_thumbs.py: error: working directory ?")
exit(-1)
# -c option but where is the -d option?
elif options.configfile is not None:
print("Usage: AFM_thumbs.py [options]\n\n" \
"AFM_thumbs.py: error: working directory ?")
exit(-1)
# All other: exit.
else:
print("Usage: AFM_thumbs.py [options]\n\n" \
"AFM_thumbs.py: error: options ?")
exit(-1)
def read_configfile(filepath_config):
# From here on, the parameters from the config file are stored into
# the variables.
# filepath_config = os.path.join(globvar_configfile_path,
# globvar_configfile)
config_file_p = open(filepath_config, "r")
# This has to be modified ...
for line in config_file_p:
if "PDF Path:" in line:
globvar_AFMdir.pdf_path = ""
break
# Go to parameters.
for line in config_file_p:
if "Parameters" in line:
break
# The whole config file is read
for line in config_file_p:
if "Channelname " in line:
break
if "Rows" in line:
globvar_ThumbPara.row = int(line[25:-1])
if "Columns" in line:
globvar_ThumbPara.col = int(line[25:-1])
if "Rms" in line:
globvar_ThumbPara.rms = line[25:-1]
if "Image resolution" in line:
globvar_ThumbPara.res = line[25:-1]
if "Jpeg quality" in line:
globvar_ThumbPara.jpeg = line[25:-1]
if "X text position" in line:
globvar_ThumbPara.text_x = line[25:-1]
if "Y text position" in line:
globvar_ThumbPara.text_y = line[25:-1]
if "Text size" in line:
globvar_ThumbPara.text_size = line[25:-1]
if "Dx of text" in line:
globvar_ThumbPara.text_block = line[25:-1]
if "Font" in line:
font_list = get_fonts()
if line[25:-1] in font_list:
globvar_ThumbPara.font = line[25:-1]
else:
# If the font is not available then take the first of the
# list of available preferred fonts.
globvar_ThumbPara.font = font_list[0]
if "Deleting thumbs before" in line:
globvar_ThumbPara.thumbs_before = bool(int(line[25:-1]))
if "Deleting thumbs after" in line:
globvar_ThumbPara.thumbs_after = bool(int(line[25:-1]))
if "Spektral Options" in line:
globvar_ThumbPara.spektra = bool(int(line[25:-1]))
if "Peek Options" in line:
globvar_ThumbPara.peek = bool(int(line[25:-1]))
if "Format Options" in line:
globvar_ThumbPara.png = bool(int(line[25:-1]))
if "Date" in line:
globvar_ThumbPara.date = bool(int(line[25:-1]))
if "Size in nm" in line:
globvar_ThumbPara.sizenm = bool(int(line[25:-1]))
if "Size in px" in line:
globvar_ThumbPara.sizepx = bool(int(line[25:-1]))
if "Offset" in line:
globvar_ThumbPara.offset = bool(int(line[25:-1]))
if "Voltage" in line:
globvar_ThumbPara.voltage = bool(int(line[25:-1]))
if "Feedback" in line:
globvar_ThumbPara.feedback = bool(int(line[25:-1]))
if "Gain" in line:
globvar_ThumbPara.gain = bool(int(line[25:-1]))
if "Speed" in line:
globvar_ThumbPara.speed = bool(int(line[25:-1]))
if "Amplitude" in line:
globvar_ThumbPara.ampl = bool(int(line[25:-1]))
if "Angle" in line:
globvar_ThumbPara.angle = bool(int(line[25:-1]))
if "Extra directories" in line:
globvar_ThumbPara.extra_direct = bool(int(line[25:-1]))
if "Subdirs" in line:
globvar_ThumbPara.subdirs = bool(int(line[25:-1]))
if "File extension" in line:
globvar_ThumbPara.extension = line[25:-1]
if "Master directory" in line:
globvar_ThumbPara.masterdir = line[25:-1]
if "Filename" in line:
globvar_ThumbPara.filename = line[25:-1]
if "Replace pdfs" in line:
globvar_ThumbPara.pdfs = bool(int(line[25:-1]))
if "RHK Special Options" in line:
RHK_special.true = bool(int(line[25:-1]))
# Read now the channels:
config_file_p.seek(0, 0)
for line in config_file_p:
if "Tooltips" in line:
break
for line in config_file_p:
if "Channelname " in line:
globvar_ThumbPara.channel_names.append(line[25:-1])
# Read now the thumb bools:
config_file_p.seek(0, 0)
for line in config_file_p:
if "Tooltips" in line:
break
for line in config_file_p:
if "Thumb " in line:
globvar_ThumbPara.thumbs.append(bool(int(line[25:-1])))
# Read now the line_fit bools:
config_file_p.seek(0, 0)
for line in config_file_p:
if "Tooltips" in line:
break
for line in config_file_p:
if "LineFit " in line:
globvar_ThumbPara.line_fit.append(bool(int(line[25:-1])))
# Read now the plane_fit bools:
config_file_p.seek(0, 0)
for line in config_file_p:
if "Tooltips" in line:
break
for line in config_file_p:
if "PlaneFit " in line:
globvar_ThumbPara.plane_fit.append(bool(int(line[25:-1])))
# Read now the inverted bools:
config_file_p.seek(0, 0)
for line in config_file_p:
if "Tooltips" in line:
break
for line in config_file_p:
if "Inverted " in line:
globvar_ThumbPara.invert.append(bool(int(line[25:-1])))
# Read now the colors:
config_file_p.seek(0, 0)
for line in config_file_p:
if "Tooltips" in line:
break
for line in config_file_p:
if "Color " in line:
globvar_ThumbPara.colors.append(define_color(line[25:-1]))
globvar_ThumbPara.geometry_x.append(globvar_thumb_size_x * \
float(globvar_ThumbPara.res))
globvar_ThumbPara.geometry_y.append(globvar_thumb_size_y * \
float(globvar_ThumbPara.res))
config_file_p.close()
# This definition clarifies, which fonts are available on the system and which
# of the preferred fonts in 'globvar_fonts' is in the list of available_fonts.
# Return the list of available preferred fonts.
# In the variable 'globvar_bad_fonts' one finds the bad fonts (e.g., NotoColorEmoji),
# which are excluded here!
def get_fonts():
font_list = []
all_fonts_with_path = matplotlib.font_manager.get_fontconfig_fonts()
all_fonts = []
for fname in all_fonts_with_path:
if str(os.path.basename(fname)) in globvar_bad_fonts:
continue
tmp = matplotlib.font_manager.FontProperties(fname=fname).get_name()
all_fonts.append(tmp)
for font in globvar_fonts:
if font in all_fonts:
font_list.append(font)
return font_list

BIN
AFM_thumbs/Command_line.pyc Executable file

Binary file not shown.

View File

@@ -0,0 +1,166 @@
#
#
# This is the config file of the 'Advanced SCALA contact sheets' tool
#
# Don't make any changes
#
Last directory: /media/cle/Daten/Data/X -- 2022/Programming/Python_AFM_thumbs/AFM_thumbs/Aktuelle_version_python3/TESTS
PDF Path:
Parameters
==========
Rows : 6
Columns : 4
Rms : 2.5
Image resolution : 100
Jpeg quality : 40
X text position : 0
Y text position : 0
Text size : 13
Dx of text : 0
Font : Arial
Date : 1
Size in nm : 1
Size in px : 1
Offset : 1
Voltage : 1
Feedback : 1
Gain : 1
Speed : 1
Amplitude : 1
Angle : 1
Deleting thumbs before : 0
Deleting thumbs after : 0
Extra directories : 0
Replace pdfs : 0
Subdirs : 1
Spektral Options : 1
Format Options : 1
Peek Options : 0
Minimum on zero Options: 0
Master directory :
Filename :
Color : ReiGreen
File extension :
Direction : 0
Linefit : 0
Planefit : 3
AddChannel : 17
ChannelNumber : 3
Tooltips : 0
Channelname 1 : FN
Channelname 2 : FL
Channelname 3 : I
Thumb 1 : 1
Thumb 2 : 1
Thumb 3 : 1
Thumb 4 : 1
Thumb 5 : 1
Thumb 6 : 1
Thumb 7 : 1
Thumb 8 : 1
Thumb 9 : 1
Thumb 10 : 1
Thumb 11 : 1
Thumb 12 : 1
Thumb 13 : 1
Thumb 14 : 1
Thumb 15 : 1
Thumb 16 : 1
Thumb 17 : 1
Thumb 18 : 1
Thumb 19 : 1
Thumb 20 : 1
Thumb 21 : 1
Thumb 22 : 1
LineFit 1 : 1
LineFit 2 : 1
LineFit 3 : 1
LineFit 4 : 1
LineFit 5 : 1
LineFit 6 : 1
LineFit 7 : 1
LineFit 8 : 1
LineFit 9 : 1
LineFit 10 : 1
LineFit 11 : 1
LineFit 12 : 1
LineFit 13 : 1
LineFit 14 : 1
LineFit 15 : 1
LineFit 16 : 1
LineFit 17 : 1
LineFit 18 : 1
LineFit 19 : 1
LineFit 20 : 1
LineFit 21 : 1
LineFit 22 : 1
PlaneFit 1 : 0
PlaneFit 2 : 0
PlaneFit 3 : 0
PlaneFit 4 : 0
PlaneFit 5 : 0
PlaneFit 6 : 0
PlaneFit 7 : 0
PlaneFit 8 : 0
PlaneFit 9 : 0
PlaneFit 10 : 0
PlaneFit 11 : 0
PlaneFit 12 : 0
PlaneFit 13 : 0
PlaneFit 14 : 0
PlaneFit 15 : 0
PlaneFit 16 : 0
PlaneFit 17 : 0
PlaneFit 18 : 0
PlaneFit 19 : 0
PlaneFit 20 : 0
PlaneFit 21 : 0
PlaneFit 22 : 0
Inverted 1 : 0
Inverted 2 : 0
Inverted 3 : 1
Inverted 4 : 1
Inverted 5 : 0
Inverted 6 : 0
Inverted 7 : 0
Inverted 8 : 0
Inverted 9 : 0
Inverted 10 : 0
Inverted 11 : 0
Inverted 12 : 0
Inverted 13 : 1
Inverted 14 : 1
Inverted 15 : 0
Inverted 16 : 0
Inverted 17 : 0
Inverted 18 : 0
Inverted 19 : 0
Inverted 20 : 0
Inverted 21 : 0
Inverted 22 : 0
Color 1 : AFMhot
Color 2 : AFMhot
Color 3 : Grey
Color 4 : Grey
Color 5 : Yellow
Color 6 : Yellow
Color 7 : Grey
Color 8 : Grey
Color 9 : ReiGreen
Color 10 : ReiGreen
Color 11 : Red
Color 12 : Red
Color 13 : Blue2
Color 14 : Blue2
Color 15 : ReiGreen
Color 16 : ReiGreen
Color 17 : Blue2
Color 18 : Blue2
Color 19 : Blue
Color 20 : Blue
Color 21 : Ocean
Color 22 : Ocean

View File

@@ -0,0 +1,166 @@
#
#
# This is the config file of the 'Advanced SCALA contact sheets' tool
#
# Don't make any changes
#
Last directory: /media/cle/Daten/Data/X -- 2012/rawdata/sample_Brice/NaCl_C60_01june2012p2
PDF Path:
Parameters
==========
Rows : 6
Columns : 4
Rms : 1.3
Image resolution : 100
Jpeg quality : 40
X text position : 0
Y text position : 0
Text size : 13
Dx of text : 0
Font : FreeSans
Date : 1
Size in nm : 1
Size in px : 1
Offset : 1
Voltage : 1
Feedback : 1
Gain : 1
Speed : 1
Amplitude : 1
Angle : 1
Deleting thumbs before : 0
Deleting thumbs after : 0
Extra directories : 0
Replace pdfs : 1
Subdirs : 1
Spektral Options : 1
Format Options : 0
Peek Options : 0
Minimum on zero Options: 0
Master directory :
Filename :
Color : ReiGreen
File extension : _noline
Direction : 0
Linefit : 3
Planefit : 3
AddChannel : 17
ChannelNumber : 3
Tooltips : 0
Channelname 1 : FN
Channelname 2 : FL
Channelname 3 : I
Thumb 1 : 1
Thumb 2 : 1
Thumb 3 : 1
Thumb 4 : 1
Thumb 5 : 1
Thumb 6 : 1
Thumb 7 : 1
Thumb 8 : 1
Thumb 9 : 1
Thumb 10 : 1
Thumb 11 : 1
Thumb 12 : 1
Thumb 13 : 1
Thumb 14 : 1
Thumb 15 : 1
Thumb 16 : 1
Thumb 17 : 1
Thumb 18 : 1
Thumb 19 : 1
Thumb 20 : 1
Thumb 21 : 1
Thumb 22 : 1
LineFit 1 : 0
LineFit 2 : 0
LineFit 3 : 0
LineFit 4 : 0
LineFit 5 : 0
LineFit 6 : 0
LineFit 7 : 0
LineFit 8 : 0
LineFit 9 : 0
LineFit 10 : 0
LineFit 11 : 0
LineFit 12 : 0
LineFit 13 : 0
LineFit 14 : 0
LineFit 15 : 0
LineFit 16 : 0
LineFit 17 : 0
LineFit 18 : 0
LineFit 19 : 0
LineFit 20 : 0
LineFit 21 : 0
LineFit 22 : 0
PlaneFit 1 : 0
PlaneFit 2 : 0
PlaneFit 3 : 0
PlaneFit 4 : 0
PlaneFit 5 : 0
PlaneFit 6 : 0
PlaneFit 7 : 0
PlaneFit 8 : 0
PlaneFit 9 : 0
PlaneFit 10 : 0
PlaneFit 11 : 0
PlaneFit 12 : 0
PlaneFit 13 : 0
PlaneFit 14 : 0
PlaneFit 15 : 0
PlaneFit 16 : 0
PlaneFit 17 : 0
PlaneFit 18 : 0
PlaneFit 19 : 0
PlaneFit 20 : 0
PlaneFit 21 : 0
PlaneFit 22 : 0
Inverted 1 : 1
Inverted 2 : 1
Inverted 3 : 1
Inverted 4 : 1
Inverted 5 : 1
Inverted 6 : 1
Inverted 7 : 1
Inverted 8 : 1
Inverted 9 : 1
Inverted 10 : 1
Inverted 11 : 1
Inverted 12 : 1
Inverted 13 : 1
Inverted 14 : 1
Inverted 15 : 1
Inverted 16 : 1
Inverted 17 : 1
Inverted 18 : 1
Inverted 19 : 1
Inverted 20 : 1
Inverted 21 : 1
Inverted 22 : 1
Color 1 : BluePurple
Color 2 : PurpleBlue
Color 3 : Grey
Color 4 : Grey
Color 5 : PupleRed
Color 6 : RedPurple
Color 7 : Grey
Color 8 : Grey
Color 9 : OrangeRed
Color 10 : PurpleBlueGreen
Color 11 : Red
Color 12 : Red
Color 13 : Gnuplot
Color 14 : Gnuplot2
Color 15 : ReiGreen
Color 16 : ReiGreen
Color 17 : Blue2
Color 18 : Blue2
Color 19 : Blue
Color 20 : Blue
Color 21 : Ocean
Color 22 : Ocean

View File

@@ -0,0 +1,177 @@
#
#
# This is the config file of the 'Advanced SCALA contact sheets' tool
#
# Don't make any changes
#
Last directory: /media/cle/Daten/Data/X -- 2021/rawdata/NANONIS
PDF Path:
Parameters
==========
Rows : 6
Columns : 4
Rms : 1.3
Image resolution : 100
Jpeg quality : 40
X text position : 0
Y text position : 0
Text size : 13
Dx of text : 0
Font : FreeSans
Date : 1
Size in nm : 1
Size in px : 1
Offset : 1
Voltage : 1
Feedback : 1
Gain : 1
Speed : 1
Amplitude : 1
Angle : 1
Deleting thumbs before : 0
Deleting thumbs after : 0
Extra directories : 0
Replace pdfs : 0
Subdirs : 1
Spektral Options : 1
Format Options : 0
Peek Options : 0
Minimum on zero Options: 0
Master directory :
Filename :
Color : ReiGreen
File extension :
Direction : 0
Linefit : 3
Planefit : 3
AddChannel : 20
ChannelNumber : 4
Tooltips : 0
Channelname 1 : FN
Channelname 2 : FL
Channelname 3 : I
Channelname 4 : Phase
Thumb 1 : 1
Thumb 2 : 1
Thumb 3 : 1
Thumb 4 : 1
Thumb 5 : 1
Thumb 6 : 1
Thumb 7 : 1
Thumb 8 : 1
Thumb 9 : 1
Thumb 10 : 1
Thumb 11 : 1
Thumb 12 : 1
Thumb 13 : 1
Thumb 14 : 1
Thumb 15 : 1
Thumb 16 : 1
Thumb 17 : 1
Thumb 18 : 1
Thumb 19 : 1
Thumb 20 : 1
Thumb 21 : 1
Thumb 22 : 1
Thumb 23 : 1
Thumb 24 : 1
LineFit 1 : 1
LineFit 2 : 1
LineFit 3 : 1
LineFit 4 : 1
LineFit 5 : 1
LineFit 6 : 1
LineFit 7 : 1
LineFit 8 : 1
LineFit 9 : 1
LineFit 10 : 1
LineFit 11 : 1
LineFit 12 : 1
LineFit 13 : 1
LineFit 14 : 1
LineFit 15 : 1
LineFit 16 : 1
LineFit 17 : 1
LineFit 18 : 1
LineFit 19 : 1
LineFit 20 : 1
LineFit 21 : 1
LineFit 22 : 1
LineFit 23 : 1
LineFit 24 : 1
PlaneFit 1 : 0
PlaneFit 2 : 0
PlaneFit 3 : 0
PlaneFit 4 : 0
PlaneFit 5 : 0
PlaneFit 6 : 0
PlaneFit 7 : 0
PlaneFit 8 : 0
PlaneFit 9 : 0
PlaneFit 10 : 0
PlaneFit 11 : 0
PlaneFit 12 : 0
PlaneFit 13 : 0
PlaneFit 14 : 0
PlaneFit 15 : 0
PlaneFit 16 : 0
PlaneFit 17 : 0
PlaneFit 18 : 0
PlaneFit 19 : 0
PlaneFit 20 : 0
PlaneFit 21 : 0
PlaneFit 22 : 0
PlaneFit 23 : 0
PlaneFit 24 : 0
Inverted 1 : 0
Inverted 2 : 0
Inverted 3 : 1
Inverted 4 : 1
Inverted 5 : 0
Inverted 6 : 0
Inverted 7 : 0
Inverted 8 : 0
Inverted 9 : 0
Inverted 10 : 0
Inverted 11 : 0
Inverted 12 : 0
Inverted 13 : 1
Inverted 14 : 1
Inverted 15 : 0
Inverted 16 : 0
Inverted 17 : 0
Inverted 18 : 0
Inverted 19 : 0
Inverted 20 : 0
Inverted 21 : 0
Inverted 22 : 0
Inverted 23 : 0
Inverted 24 : 0
Color 1 : Gist_heat
Color 2 : Gist_heat
Color 3 : Grey
Color 4 : Grey
Color 5 : AFMhot
Color 6 : AFMhot
Color 7 : Grey
Color 8 : Grey
Color 9 : Grey
Color 10 : Grey
Color 11 : Red
Color 12 : Red
Color 13 : Blue2
Color 14 : Blue2
Color 15 : ReiGreen
Color 16 : ReiGreen
Color 17 : Blue2
Color 18 : Blue2
Color 19 : Blue
Color 20 : Blue
Color 21 : Ocean
Color 22 : Ocean
Color 23 : Grey
Color 24 : Grey

166
AFM_thumbs/Config_default.conf~ Executable file
View File

@@ -0,0 +1,166 @@
#
#
# This is the config file of the 'Advanced SCALA contact sheets' tool
#
# Don't make any changes
#
Last directory: /media/cle/Daten/Data/X -- 2016/rawdata/sample_Pd-HOPG/Ceria_10ML_Pd_annealed_Ethylene_2016-01-03
PDF Path: /media/cle/Daten/Data/X -- 2016/rawdata/sample_Pd-HOPG/Ficken
Parameters
==========
Rows : 6
Columns : 4
Rms : 1.3
Image resolution : 100
Jpeg quality : 40
X text position : 0
Y text position : 0
Text size : 13
Dx of text : 0
Font : Arial
Date : 1
Size in nm : 1
Size in px : 1
Offset : 1
Voltage : 1
Feedback : 1
Gain : 1
Speed : 1
Amplitude : 1
Angle : 1
Deleting thumbs before : 0
Deleting thumbs after : 0
Extra directories : 0
Replace pdfs : 1
Subdirs : 0
Spektral Options : 1
Format Options : 0
Peek Options : 0
Minimum on zero Options: 0
Master directory :
Filename :
Color : ReiGreen
File extension : _noline
Direction : 0
Linefit : 3
Planefit : 3
AddChannel : 17
ChannelNumber : 3
Tooltips : 0
Channelname 1 : FN
Channelname 2 : FL
Channelname 3 : I
Thumb 1 : 1
Thumb 2 : 1
Thumb 3 : 1
Thumb 4 : 1
Thumb 5 : 1
Thumb 6 : 1
Thumb 7 : 1
Thumb 8 : 1
Thumb 9 : 1
Thumb 10 : 1
Thumb 11 : 1
Thumb 12 : 1
Thumb 13 : 1
Thumb 14 : 1
Thumb 15 : 1
Thumb 16 : 1
Thumb 17 : 1
Thumb 18 : 1
Thumb 19 : 1
Thumb 20 : 1
Thumb 21 : 1
Thumb 22 : 1
LineFit 1 : 0
LineFit 2 : 0
LineFit 3 : 0
LineFit 4 : 0
LineFit 5 : 0
LineFit 6 : 0
LineFit 7 : 0
LineFit 8 : 0
LineFit 9 : 0
LineFit 10 : 0
LineFit 11 : 0
LineFit 12 : 0
LineFit 13 : 0
LineFit 14 : 0
LineFit 15 : 0
LineFit 16 : 0
LineFit 17 : 0
LineFit 18 : 0
LineFit 19 : 0
LineFit 20 : 0
LineFit 21 : 0
LineFit 22 : 0
PlaneFit 1 : 1
PlaneFit 2 : 1
PlaneFit 3 : 0
PlaneFit 4 : 0
PlaneFit 5 : 0
PlaneFit 6 : 0
PlaneFit 7 : 0
PlaneFit 8 : 0
PlaneFit 9 : 0
PlaneFit 10 : 0
PlaneFit 11 : 0
PlaneFit 12 : 0
PlaneFit 13 : 1
PlaneFit 14 : 1
PlaneFit 15 : 0
PlaneFit 16 : 0
PlaneFit 17 : 0
PlaneFit 18 : 0
PlaneFit 19 : 0
PlaneFit 20 : 0
PlaneFit 21 : 0
PlaneFit 22 : 0
Inverted 1 : 0
Inverted 2 : 0
Inverted 3 : 1
Inverted 4 : 1
Inverted 5 : 0
Inverted 6 : 0
Inverted 7 : 0
Inverted 8 : 0
Inverted 9 : 0
Inverted 10 : 0
Inverted 11 : 0
Inverted 12 : 0
Inverted 13 : 1
Inverted 14 : 1
Inverted 15 : 0
Inverted 16 : 0
Inverted 17 : 0
Inverted 18 : 0
Inverted 19 : 0
Inverted 20 : 0
Inverted 21 : 0
Inverted 22 : 0
Color 1 : Gist_heat
Color 2 : Gist_heat
Color 3 : Grey
Color 4 : Grey
Color 5 : AFMhot
Color 6 : AFMhot
Color 7 : Grey
Color 8 : Grey
Color 9 : Grey
Color 10 : Grey
Color 11 : Red
Color 12 : Red
Color 13 : Blue2
Color 14 : Blue2
Color 15 : ReiGreen
Color 16 : ReiGreen
Color 17 : Blue2
Color 18 : Blue2
Color 19 : Blue
Color 20 : Blue
Color 21 : Ocean
Color 22 : Ocean

223
AFM_thumbs/Initialize.py Executable file
View File

@@ -0,0 +1,223 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import os
import shutil
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_spaces
from AFM_thumbs.Variables import globvar_configfile_path
from AFM_thumbs.Variables import globvar_configfile
from AFM_thumbs.Variables import globvar_python_directory
from AFM_thumbs.Variables import globvar_default_config
from AFM_thumbs.Variables import RHK_PositionCounter
def initialize_position_counter():
RHK_PositionCounter.position = 0
def initialize_AFM_data():
globvar_AFMdata.date = ""
globvar_AFMdata.x_size = ""
globvar_AFMdata.y_size = ""
globvar_AFMdata.x_pixel = ""
globvar_AFMdata.y_pixel = ""
globvar_AFMdata.x_off = ""
globvar_AFMdata.y_off = ""
globvar_AFMdata.voltage = ""
globvar_AFMdata.measurement_type = ""
globvar_AFMdata.feedback = ""
globvar_AFMdata.gain = ""
globvar_AFMdata.gain_prop = ""
globvar_AFMdata.gain_int = ""
globvar_AFMdata.gain_xy = ""
globvar_AFMdata.gain_signal = ""
globvar_AFMdata.gain_z = ""
globvar_AFMdata.speed = ""
globvar_AFMdata.res_freq = ""
globvar_AFMdata.amplitude = ""
globvar_AFMdata.angle = ""
globvar_AFMdata.scan_updown = ""
globvar_AFMdata.sweep_f0 = ""
globvar_AFMdata.sweep_phase = ""
globvar_AFMdata.sweep_A_exec = ""
globvar_AFMdata.sweep_Q = ""
globvar_AFMdata.NONE = ""
globvar_AFMdata.datfile[:] = []
globvar_AFMdata.channel[:] = []
globvar_AFMdata.unit[:] = []
globvar_AFMdata.z_average = 0.0
globvar_AFMdata.z_factor[:] = []
globvar_AFMdata.z_offset[:] = []
globvar_AFMdata.z_calibration[:] = []
globvar_AFMdata.z_amplitude[:] = []
globvar_AFMdata.z_min[:] = []
globvar_AFMdata.z_max[:] = []
globvar_AFMdata.scandir[:] = []
globvar_AFMdata.spec_x_unit[:] = []
globvar_AFMdata.spec_x_label[:] = []
globvar_AFMdata.spec_y_unit[:] = []
globvar_AFMdata.spec_y_label[:] = []
globvar_AFMdata.spec_y_factor[:] = []
globvar_AFMdata.spec_points[:] = []
globvar_AFMdata.spec_feedback[:] = []
globvar_AFMdata.spec_acquisition[:] = []
globvar_AFMdata.spec_delay[:] = []
globvar_AFMdata.spec_time[:] = []
globvar_AFMdata.spec_position[:] = []
globvar_AFMdata.spec_files[:] = []
def initialize_dir():
# If the user chooses 'Cancel' -> exit
if not globvar_AFMdir.working_directory:
return False
# The pdfs shall not be replaced if 0
if globvar_ThumbPara.pdfs == 0:
# There is no special path for the pdfs ...
if globvar_AFMdir.pdf_path == "":
# The name of the pdf that may exist
file_pdf = os.path.abspath(globvar_AFMdir.working_directory) + \
globvar_ThumbPara.extension+".pdf"
# ... there is a special path for the pdfs!
else:
# The name of the pdf that may exist
file_pdf = os.path.basename(globvar_AFMdir.working_directory) + \
globvar_ThumbPara.extension + \
".pdf"
file_pdf = os.path.join(globvar_AFMdir.pdf_path, file_pdf)
# If the pdf does exist, then simply do nothing => return False!
if os.path.isfile(file_pdf):
print(globvar_spaces + "The pdf file\n" +
globvar_spaces +
"'" + file_pdf + "'\n" +
globvar_spaces +
"does already exist !\n")
return False
# Name of directory
globvar_AFMdir.data_directory_name = \
os.path.basename(globvar_AFMdir.working_directory)
# Thumbnail directory will be created in the working directory
globvar_AFMdir.thumbnail_directory = \
os.path.join(globvar_AFMdir.working_directory,
"thumbnails" + globvar_ThumbPara.extension)
# If some thumbnails are already existing but shall be deleted, then do ...
if globvar_ThumbPara.thumbs_before == True:
if os.path.isdir(globvar_AFMdir.thumbnail_directory):
delete_string = globvar_AFMdir.thumbnail_directory
shutil.rmtree(delete_string)
#==============================================================================
# delete_string = "rm -rf \""+globvar_AFMdir.thumbnail_directory+"\""
# os.system(delete_string)
#==============================================================================
# Name of superior directory
superior_directory = os.path.dirname(globvar_AFMdir.working_directory)
# Name of directory even above
if (len(superior_directory)-superior_directory.rfind(os.pathsep))>0:
superior_2_times_directory = os.path.dirname(superior_directory)
if globvar_ThumbPara.extra_direct == True:
# Create, if it doesn't exist, a directory 'WSxM' and 'Gwyddion', which
# are on the same level as 'sample'.
# This is for future work, where treated WSxM and Gwyddion files can
# hutil be stored in these directories and ...
directory_WSxM = os.path.join(superior_2_times_directory,"WSxM")
if not os.path.isdir(directory_WSxM):
os.mkdir(directory_WSxM)
directory_Gwyddion = os.path.join(superior_2_times_directory,
"Gwyddion")
if not os.path.isdir(directory_Gwyddion):
os.mkdir(directory_Gwyddion)
# ... in the respective sub directories
directory_WSxM_data = os.path.join(directory_WSxM,
globvar_AFMdir.data_directory_name)
if not os.path.isdir(directory_WSxM_data):
os.mkdir(directory_WSxM_data)
directory_Gwyddion_data = os.path.join(directory_Gwyddion,
globvar_AFMdir.data_directory_name)
if not os.path.isdir(directory_Gwyddion_data):
os.mkdir(directory_Gwyddion_data)
# Thumbnail directory in working directory
if not os.path.isdir(globvar_AFMdir.thumbnail_directory):
os.mkdir(globvar_AFMdir.thumbnail_directory)
return True
# Determine the config file.
def initialize_check_config(file_config):
if file_config == None:
file_config = os.path.join(globvar_configfile_path,globvar_configfile)
path_rel_default_config = os.path.join(globvar_python_directory,
globvar_default_config)
if not os.path.isfile(file_config):
print(globvar_spaces + "Attention: The config file\n" +
globvar_spaces + file_config + "\n" + globvar_spaces +
"does not exist!\n" + globvar_spaces +
"The default config file '" +
path_rel_default_config +
"' " +
"is now used!\n" + globvar_spaces +
"If you have your own config file, put in the correct " +
"file name and path\n" + globvar_spaces +
"in 'AFM_thumbs/Variables.py' => " +
"'globvar_configfile' and 'globvar_configfile_path'\n")
filepath_program = os.path.realpath(__file__)
path_program = os.path.dirname(filepath_program)
file_config = os.path.join(path_program,globvar_default_config)
if not os.path.isfile(file_config):
print(globvar_spaces +
"Attention, MAJOR ERROR !!! The default config file\n" +
globvar_spaces + file_config + "\n" + globvar_spaces +
"does not exist! Re-install the whole program.\n" +
globvar_spaces + "Exit!\n")
exit(-1)
return file_config

BIN
AFM_thumbs/Initialize.pyc Executable file

Binary file not shown.

251
AFM_thumbs/Linalg.py Executable file
View File

@@ -0,0 +1,251 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import scipy
from scipy import linalg
import numpy as np
from AFM_thumbs.Variables import globvar_spaces
from AFM_thumbs.Variables import globvar_LINALG
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_ThumbPara
def linalg_plane_fit(size_x, size_y, data):
size_x_float = float(size_x)
size_y_float = float(size_y)
if size_x == 512 and size_y == 512:
M = globvar_LINALG.plane_M512
x_vec = globvar_LINALG.plane_x_vec512
y_vec = globvar_LINALG.plane_y_vec512
elif size_x == 1024 and size_y == 1024:
M = globvar_LINALG.plane_M1024
x_vec = globvar_LINALG.plane_x_vec1024
y_vec = globvar_LINALG.plane_y_vec1024
else:
x_vec = np.arange(size_x_float)
y_vec = np.arange(size_y_float)
x = x_vec.sum() * size_x_float
y = y_vec.sum() * size_y_float
xx = (x_vec * x_vec).sum() * size_x_float
yy = (y_vec * y_vec).sum() * size_y_float
xy = (y_vec * (x / size_x_float)).sum()
M = scipy.mat([[xx,xy,x],
[xy,yy,y],
[x,y,size_x_float*size_y_float]])
z = data.sum()
xz = (data * x_vec).sum()
yz = (data * y_vec.reshape(size_y,1)).sum()
B = scipy.mat([[xz], [yz], [z]])
c,resid,rank,sigma = linalg.lstsq(M,B)
array_one = np.array([[1 for i in range(size_x)] for j in range(size_y)])
plane_const = array_one * c[2][0]
plane_x = array_one * x_vec * c[0][0]
plane_y = array_one * y_vec.reshape(size_y,1) * c[1][0]
plane = plane_const + plane_x + plane_y
# The plane substraction
data = data - plane
# Put zero onto lowest value
# min_value = min(data)
# data = data - float(min_value)
return data
def linalg_line_fit(size_x, size_y, data):
size_x_float = float(size_x)
size_y_float = float(size_y)
if size_x == 512 and size_y == 512:
M = globvar_LINALG.line_M512
x_vec = globvar_LINALG.line_x_vec512
elif size_x == 1024 and size_y == 1024:
M = globvar_LINALG.line_M1024
x_vec = globvar_LINALG.line_x_vec1024
else:
x_vec = np.arange(size_x_float)
x = x_vec.sum()
xx = (x_vec * x_vec).sum()
M = scipy.mat([[xx,x],
[x,size_x_float]])
plane = []
for line in data:
y = sum(line)
xy = sum(line*x_vec)
B = scipy.mat([[xy],[y]])
c,resid,rank,sigma = linalg.lstsq(M,B)
plane.append([i * c[0][0] + c[1][0] for i in range(size_x)])
# The plane substraction
data = data - plane
# Put zero onto lowest value
# min_value = min(data)
# data = data - float(min_value)
return data
def initialize_linalg():
# Plane
x_vec = np.arange(512)
y_vec = np.arange(512)
x = x_vec.sum() * 512.0
y = y_vec.sum() * 512.0
xx = (x_vec * x_vec).sum() * 512.0
yy = (y_vec * y_vec).sum() * 512.0
xy = (y_vec * (x / 512.0)).sum()
globvar_LINALG.plane_M512 = scipy.mat([[xx,xy,x],
[xy,yy,y],
[x,y,512.0*512.0]])
globvar_LINALG.plane_x_vec512 = x_vec
globvar_LINALG.plane_y_vec512 = y_vec
x_vec = np.arange(1024)
y_vec = np.arange(1024)
x = x_vec.sum() * 1024.0
y = y_vec.sum() * 1024.0
xx = (x_vec * x_vec).sum() * 1024.0
yy = (y_vec * y_vec).sum() * 1024.0
xy = (y_vec * (x / 1024.0)).sum()
globvar_LINALG.plane_M1024 = scipy.mat([[xx,xy,x],
[xy,yy,y],
[x,y,1024.0*1024.0]])
globvar_LINALG.plane_x_vec1024 = x_vec
globvar_LINALG.plane_y_vec1024 = y_vec
# Line
x_vec = np.arange(512)
x = x_vec.sum()
xx = (x_vec * x_vec).sum()
globvar_LINALG.line_M512 = scipy.mat([[xx,x],
[x,512.0]])
globvar_LINALG.line_x_vec512 = x_vec
x_vec = np.arange(1024)
x = x_vec.sum()
xx = (x_vec * x_vec).sum()
globvar_LINALG.line_M1024 = scipy.mat([[xx,x],
[x,1024.0]])
globvar_LINALG.line_x_vec1024 = x_vec
def check_image_properties(data, data_file):
size_x = int(globvar_AFMdata.x_pixel)
size_y = int(globvar_AFMdata.y_pixel)
size = size_x * size_y
old_y_size = ""
old_y_pixel = ""
# Part 1
# ======
#
# We first put all NaNs onto the mean value! This is important for, e.g.,
# Nanonis files.
if np.isnan(data.min()) or np.isnan(data.max()):
list_nans = np.where(np.isnan(data))[0]
data_clean = np.delete(data, list_nans)
data_mean = np.mean(data_clean)
for nan in list_nans:
data[nan] = data_mean
# Part 2
# ======
#
# Check now the lenght of the array, and send the true size, if the image
# is not complete (important for Omicron SCALA images that were stored
# before the complete image was finished).
if len(data) != size:
size_diff = len(data) - size
print
print(globvar_spaces + "Attention, error in data file!")
print(globvar_spaces + "Length of data is not equal to size_x * size_y")
print(globvar_spaces + "Size x,y : "+str(size_x) + "x" + \
str(size_y) + ", " + str(size_x*size_y))
print(globvar_spaces + "Data : "+str(len(data)))
print(globvar_spaces + "Data-Size : "+str(size_diff))
print(globvar_spaces + "File : " + data_file)
# This is for ONE line:
if abs(size_diff) < size_x:
data = data[ : -(size_x + size_diff) ]
size_y -= 1
print(globvar_spaces + "Error has been fixed by removing one"
+ " line from the data.")
# This is for several lines.
elif abs(size_diff) > size_x:
remove_lines = int(size_diff / size_x)
remove_data = size_diff % size_x
size_y -= abs(remove_lines)
if remove_data != 0:
data = data[ : -remove_data ]
print(globvar_spaces + "Error has been fixed by removing "
+ str(abs(remove_lines)) + " lines from the data.")
old_y_size = globvar_AFMdata.y_size
old_y_pixel = globvar_AFMdata.y_pixel
globvar_AFMdata.y_pixel = str(size_y)
globvar_AFMdata.y_size = str(float(globvar_AFMdata.x_size) * \
(float(size_y)/float(size_x)))
# Two digits after the .dot. .
globvar_AFMdata.y_size = globvar_AFMdata.y_size[: \
globvar_AFMdata.y_size.find(".")+2]
return data, old_y_size, old_y_pixel

BIN
AFM_thumbs/Linalg.pyc Executable file

Binary file not shown.

452
AFM_thumbs/Nanotec_DULCINEA.py Executable file
View File

@@ -0,0 +1,452 @@
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import os
import numpy as np
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import Nanotec_DULCINEA_suffix
from AFM_thumbs.Variables import Nanotec_DULCINEA_forward
from AFM_thumbs.Variables import Nanotec_DULCINEA_backward
from AFM_thumbs.Variables import Nanotec_DULCINEA_must_exist
from AFM_thumbs.Linalg import linalg_plane_fit
from AFM_thumbs.Linalg import linalg_line_fit
from AFM_thumbs.Linalg import check_image_properties
from AFM_thumbs.Thumbs import create_thumb_images
from AFM_thumbs.Initialize import initialize_AFM_data
from AFM_thumbs.Channel import proceed_with
from AFM_thumbs.Channel import line_fit
from AFM_thumbs.Channel import plane_fit
from AFM_thumbs.Channel import rename_channel
def is_Nanotec_DULCINEA_file(directory, files):
list_directories_par = []
# A directroy is only interesting if there is at least
# one par and tf0 file.
FLAG = False
for filename in files:
file_name = os.path.join(directory, filename)
if FLAG == True:
if os.path.isdir(directory):
list_directories_par.append(directory)
break
if file_name[-6:] == Nanotec_DULCINEA_must_exist:
FLAG = True
return list_directories_par
def prepare_Nanotec_DULCINEA_images(AFMfile):
file_basis = AFMfile[:-5]
read_Nanotec_DULCINEA_data(file_basis + Nanotec_DULCINEA_suffix[0])
for (image_nr, data_file) in enumerate(globvar_AFMdata.datfile):
if proceed_with(image_nr,globvar_AFMdata.scandir[image_nr]):
# Now, we determine only the file name without path.
# The way to do it is a bit complicated but does not depend
# on the system.
# Cut everything til the first appereabce of "." from the left ...
position = data_file.find(".")
# and note the suffix.
data_file_only_suffix = data_file[position+1:]
# Cat the basis of the file name and the suffix
data_file_name = file_basis + data_file_only_suffix
# If the file doesn't exist continue. But this would be strange, so
# output an error message.
if not os.path.isfile(data_file):
print(globvar_spaces + "The AFM data file ...\n<" + \
+ ">\n... does not exist (?).\n\n")
print
continue
# If the thumb image exists continue with next one ... .
# (Don't calculate a second time.)
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
data_file_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
data_file_name) + ".jpeg"
if os.path.isfile(image_path):
continue
datafile = open(data_file, 'rb')
data = datafile.read()
datafile.close()
# Read the position of the binary data.
pos = data.find(b"[Header end]") + 12
# data[pos:pos+12].decode("utf-8")
data = data[pos:-2]
size_x = int(globvar_AFMdata.x_pixel)
size_y = int(globvar_AFMdata.y_pixel)
# Reopen the file
datafile = open(data_file, 'rb')
# Move to position in file
datafile.seek(pos,0)
# Straight to numpy data (no buffering)
data = np.fromfile(datafile,dtype = np.int16,count = size_x*size_y)
datafile.close()
# old_y_size and old_y_pixel are needed to temporarily store
# the original size in y (nm and pixel). This is then used
# at the end to put back the original values for
# globvar_AFMdata.y_size and globvar_AFMdata.y_pixel, for the
# text in the thumbs.
data, old_y_size, old_y_pixel = check_image_properties(data, data_file)
# If there is some corrupt image the y value, which has been
# changed in check_image_properties, needs to be updated.
size_y = int(globvar_AFMdata.y_pixel)
# First, transform the integers into floats. This is needed for all
# mathematical operations.
data = data.astype(float)
# Average value
average = np.average(data)
# Put the lowest point onto ZERO.
data = data - data.min()
# Scale the image with the values found in the file.
z_diff_unit = float(globvar_AFMdata.z_amplitude[image_nr])
z_diff = float(data.max()) - float(data.min())
factor = z_diff_unit / z_diff
data = data * factor
# Calibrate the average value and write it into the
# globvar_AFMdata structure.
globvar_AFMdata.z_average = average * factor
# Make now a 2D array.
data.shape = np.array([size_y, size_x])
# Mirror the data along x and y
data = np.fliplr(data)
data = np.flipud(data)
# Line fit
if line_fit(image_nr,globvar_AFMdata.scandir[image_nr]):
data = linalg_line_fit(size_x, size_y, data)
# Plane fit
if plane_fit(image_nr,globvar_AFMdata.scandir[image_nr]):
data = linalg_plane_fit(size_x, size_y, data)
create_thumb_images(data,image_nr,data_file_name,data_file_name)
if old_y_size != "" and old_y_pixel != "":
globvar_AFMdata.y_size = old_y_size
globvar_AFMdata.y_pixel = old_y_pixel
else:
continue
return True
def read_Nanotec_DULCINEA_data(AFM_file):
initialize_AFM_data()
# Go through the directory and find all files of ONE measurement.
AFMfiles = filter(lambda x: x.startswith(AFM_file[:-5]),
os.listdir(globvar_AFMdir.working_directory))
AFMfiles = sorted(AFMfiles)
# For all those files, do ...
for AFMfile in AFMfiles:
AFMfile_split = AFMfile.split(".")
# Check the AFM file:
if AFMfile_split[-2] == "b" or AFMfile_split[-2] == "f":
# So, there is a ".f." or ".b.". If now the last suffix is NOT
# in the list of known 'channels', continue with the loop. In other
# words an unknown channel has been found, which is not supported.
if AFMfile[-5:] not in Nanotec_DULCINEA_suffix:
continue
# No second suffix ".f." or ".b." could be found. For some channels have
# something like ".b.2nd.Auxfeed". So, check the 3rd suffix:
else:
if AFMfile_split[-3] == "b" or AFMfile_split[-3] == "f":
# Reconstruct all the 3 suffix
AFMfile_2suffix = "." + \
AFMfile_split[-3] + "." + \
AFMfile_split[-2] + "." + \
AFMfile_split[-1]
# As above, an unknown channel has been found, which is not
# supported.
if AFMfile_2suffix not in Nanotec_DULCINEA_suffix:
continue
# Strange, not found. It seems to be a completely different file!
else:
continue
# ... open the file and ...
file_path = os.path.join(globvar_AFMdir.working_directory,AFMfile)
file_p = open(file_path, "rb")
globvar_AFMdata.datfile.append(file_path)
if Nanotec_DULCINEA_backward in AFMfile:
globvar_AFMdata.scandir.append("backward")
if Nanotec_DULCINEA_forward in AFMfile:
globvar_AFMdata.scandir.append("forward")
# ... find the data for the lists from above.
for line in file_p:
line = line.decode("utf-8")
if "[Head Settings]" in line:
break
if "Acquisition channel:" in line:
position1 = str.find(line, ":")+2
rename_channel(line[position1:])
if "Acquisition primary channel:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Conversion Factor 00:" in line:
globvar_AFMdata.unit.append(line.rsplit(" ")[-1].rstrip())
globvar_AFMdata.z_factor.append(line.rsplit(" ")[-2].rstrip())
if "Z Calibration:" in line:
list_split = line.split(" ")
globvar_AFMdata.z_calibration.append(list_split[-2])
if "Maximum: " in line:
list_split = line.split(" ")
globvar_AFMdata.z_max.append(list_split[-1])
if "Minimum: " in line:
list_split = line.split(" ")
globvar_AFMdata.z_min.append(list_split[-1])
if "Z Amplitude: " in line:
list_split = line.split(" ")
globvar_AFMdata.z_amplitude.append(list_split[-2])
file_p.close()
file_path = os.path.join(globvar_AFMdir.working_directory,AFM_file)
file_p = open(file_path, "rb")
for line in file_p:
line = line.decode("utf-8")
if "[Head Settings]" in line:
break
if "Angle: " in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.angle = line[position1:].rstrip()
if "Set Point: " in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.feedback = line[position1:].rstrip()
if "Signal Gain:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.gain_signal = line[position1:].rstrip()
if "Topography Bias:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.voltage = line[position1:].rstrip()
if "X Amplitude:" in line:
position1 = str.find(line, ":")+2
position2 = str.find(line, "nm")-1
globvar_AFMdata.x_size = line[position1:position2]
if "X Offset:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.x_off = line[position1:].rstrip()
if "X-Frequency:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.speed = line[position1:].rstrip()
if "XY Gain:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.gain_xy = line[position1:].rstrip()
if "Y Amplitude:" in line:
position1 = str.find(line, ":")+2
position2 = str.find(line, "nm")-1
globvar_AFMdata.y_size = line[position1:position2]
if "Y Offset:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.y_off = line[position1:].rstrip()
if "Z Gain:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.gain_z = line[position1:].rstrip()
if "Z Offset:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Integral:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.gain_int = line[position1:].rstrip()
if "Proportional:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.gain_prop = line[position1:].rstrip()
if "Tilt X:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Tilt Y:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Acquisition time:" in line:
position1 = str.find(line, ":")+2
position2 = str.rfind(line, ":")
globvar_AFMdata.date = line[position1:position2].rstrip()
if "Conversion Factor 01:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Conversion Offset 00:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Conversion Offset 01:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Force constant:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Head type:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Image Data Type:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Number of columns:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.x_pixel = line[position1:].rstrip()
if "Number of rows:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.y_pixel = line[position1:].rstrip()
if "X scanning direction:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Y scanning direction:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Head Name:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "X Calibration:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Y Calibration:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Acquired with version:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "CH 12:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "CH 13:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "CH 14:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Comments:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "DSP voltage range:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Dulcinea serial number:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Sampling frequency:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Saved with version:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Version:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Z Scale Factor:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
if "Z Scale Offset:" in line:
position1 = str.find(line, ":")+2
globvar_AFMdata.NONE = None
# Close the Omicron par file ...
file_p.close()
return True

BIN
AFM_thumbs/Nanotec_DULCINEA.pyc Executable file

Binary file not shown.

417
AFM_thumbs/Omicron_SCALA.py Executable file
View File

@@ -0,0 +1,417 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import sys
import os
import numpy as np
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_thumb_size_x
from AFM_thumbs.Variables import globvar_thumb_size_y
from AFM_thumbs.Variables import Omicron_SCALA_forward
from AFM_thumbs.Variables import Omicron_SCALA_backward
from AFM_thumbs.Linalg import linalg_plane_fit
from AFM_thumbs.Linalg import linalg_line_fit
from AFM_thumbs.Linalg import check_image_properties
from AFM_thumbs.Thumbs import create_thumb_images
from AFM_thumbs.Thumbs import create_thumb_spectra
from AFM_thumbs.Initialize import initialize_AFM_data
from AFM_thumbs.Channel import proceed_with
from AFM_thumbs.Channel import line_fit
from AFM_thumbs.Channel import plane_fit
from AFM_thumbs.Channel import rename_channel
def is_omicron_SCALA_file(directory, files):
list_directories_par = []
# A directroy is only interesting if there is at least
# one par and tf0 file.
FLAG_par = False
FLAG_tf0 = False
for filename in files:
file_name = os.path.join(directory, filename)
if FLAG_par == True and FLAG_tf0 == True:
if os.path.isdir(directory):
list_directories_par.append(directory)
break
if file_name[-4:] == ".par":
FLAG_par = True
if file_name[-4:] == ".tf0":
FLAG_tf0 = True
return list_directories_par
def read_Omicron_SCALA_data(par_file):
initialize_AFM_data()
par_file_path = os.path.join(globvar_AFMdir.working_directory,par_file)
par_file_p = open(par_file_path, "r")
# The spectroscopy parameters are read ................................. .
for line in par_file_p:
if "; Spectroscopic Channels." in line:
break
for line in par_file_p:
if ";Parameter" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_x_label.append(split_list[0])
if split_list[0] == "Z":
globvar_AFMdata.spec_x_unit.append("nm")
elif split_list[0] == "V":
globvar_AFMdata.spec_x_unit.append("V")
elif split_list[0] == "U":
globvar_AFMdata.spec_x_unit.append("V")
elif split_list[0] == "Macro":
globvar_AFMdata.spec_x_unit.append("a.u.")
else:
globvar_AFMdata.spec_x_unit.append("a.u.")
if ";Display name" in line:
pos = line.find(";")
line = line[34:pos]
line = line.replace(" ", "")
globvar_AFMdata.spec_y_label.append(line)
if ";Physical unit" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_y_unit.append(split_list[0])
if ";Maximum value in physical unit" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_y_factor.append(float(split_list[0]))
if ";Number of spectroscopy points" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_points.append(split_list[0])
if ";Feedback On/Off" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_feedback.append(split_list[0])
if ";Acquisition time per spectroscopy point" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_acquisition.append(split_list[0])
if ";Delay time per spectroscopy point" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_delay.append(split_list[0])
# Added on 2017-07-28
if ";Filename" in line:
split_list = line.rsplit()
globvar_AFMdata.spec_files.append(split_list[0])
# Go to the beginning of the file.
par_file_p.seek(0, 0)
# The image parameters are read ................................. .
for line in par_file_p:
# Jump over the spectroscopy part
if "; Spectroscopic Channels." in line:
for line in par_file_p:
if "; Measurement parameters." in line:
break
if "Date" in line:
position1 = str.find(line, ":")
globvar_AFMdata.date = line[position1+2:-7]+", "+line[-7:-1]
if "Field X Size" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.x_size = line[position1:position2]
if "Field Y Size" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.y_size = line[position1:position2]
if "Image Size in X" in line:
position1 = str.find(line, ":")
globvar_AFMdata.x_pixel = line[position1+2:-1]
if "Image Size in Y" in line:
position1 = str.find(line, ":")
globvar_AFMdata.y_pixel = line[position1+2:-1]
if "X Offset" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.x_off = line[position1:position2]
if "Y Offset" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.y_off = line[position1:position2]
if "Measured Gap Voltage" not in line:
if "Gap Voltage" in line:
position1 = str.find(line, ":")+2
# Change 2017-06-25
# From '+2' to + '4' => two digits more for Ugap
position2 = -(len(line)-str.rfind(line, "."))+4
globvar_AFMdata.voltage = line[position1:position2]
if "Feedback Set" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+4
globvar_AFMdata.feedback = line[position1:position2]
if "Loop Gain" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.gain = line[position1:position2]
if "Scan Speed" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.speed = line[position1:position2]
if "Amplitude" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.amplitude = line[position1:position2]
if "Scan Angle" in line:
position1 = str.find(line, ":")+2
position2 = -(len(line)-str.rfind(line, "."))+2
globvar_AFMdata.angle = line[position1:position2]
if "Topographic Channel :" in line:
position1 = str.find(line[34:], " ") + 34
if line[position1+1] is not " ":
position1 = position1 + 2
# 'rename_channel': see in Channel.py
rename_channel(line[34:position1])
if ";Physical unit" in line:
split_list = line.rsplit()
globvar_AFMdata.unit.append(split_list[0])
if ";Filename" in line:
split_list = line.rsplit()
globvar_AFMdata.datfile.append(split_list[0])
if Omicron_SCALA_backward in split_list[0]:
globvar_AFMdata.scandir.append("backward")
if Omicron_SCALA_forward in split_list[0]:
globvar_AFMdata.scandir.append("forward")
if "Maximum value in physical unit" in line:
split_list = line.rsplit()
globvar_AFMdata.z_factor.append(float(split_list[0]))
# We calculate now the total time of the spectroscopy in ms.
for tau, delay, points in zip(globvar_AFMdata.spec_acquisition,
globvar_AFMdata.spec_delay,
globvar_AFMdata.spec_points):
time = float(points) * ( float(tau) + float(delay) ) * 1000.0
globvar_AFMdata.spec_time.append("%.1f" % time)
# Close the Omicron par file ...
par_file_p.close()
return True
def prepare_Omicron_SCALA_images(par_file):
# Loop over all channels. The channels are stored in the list
# 'globvar_AFMdata.datfile', which contains the file names (without path)
# as values.
for (image_nr, data_file) in enumerate(globvar_AFMdata.datfile):
# The definition 'proceed_with' is very important! It is 'connected'
# with the GUI of AFM_thumbs where one can choose if a channel in a
# specific scanning direction shall be represented in a pdf file or not.
if proceed_with(image_nr,globvar_AFMdata.scandir[image_nr]):
# Path to the image
data_file_name = data_file
data_file = os.path.join(globvar_AFMdir.working_directory,
data_file)
# Very strange 'if' but anyway ... if yes then simply continue.
if not os.path.isfile(data_file):
continue
# Image file name
image_name = data_file_name[:-4]
if image_name[2] == "_":
image_name = image_name[0:1]+"00"+image_name[1:]
if image_name[3] == "_":
image_name = image_name[0:1]+"0"+image_name[1:]
image_name = image_name + "_" + str(image_nr)
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".jpeg"
# If the thumb image exists continue with next one ... .
# (Don't calculate a second time.)
if os.path.isfile(image_path):
continue
data = np.fromfile(file=data_file,dtype=np.int16)
size_x = int(globvar_AFMdata.x_pixel)
size_y = int(globvar_AFMdata.y_pixel)
# Data is cut by the definition check_image_properties.
#
# Note
# ====
# old_y_size and old_y_pixel are needed to temporarily store
# the original size in y (nm and pixel). This is then used
# at the end to put back the original values for
# globvar_AFMdata.y_size and globvar_AFMdata.y_pixel, for the
# text in the thumbs.
data, old_y_size, old_y_pixel = check_image_properties(data, data_file)
# If there is some corrupt image the y value, which has been
# changed in 'check_image_properties', needs to be updated.
size_y = int(globvar_AFMdata.y_pixel)
data = data.byteswap()
data = (globvar_AFMdata.z_factor[image_nr] * data) / 32767.0
globvar_AFMdata.z_average = np.average(data)
if globvar_ThumbPara.minimum_on_zero:
data = data - float(min(data))
data.shape = np.array([size_y, size_x])
# Mirror the data along y
data = np.flipud(data)
# Line fit
if line_fit(image_nr,globvar_AFMdata.scandir[image_nr]):
data = linalg_line_fit(size_x, size_y, data)
# Plane fit
if plane_fit(image_nr,globvar_AFMdata.scandir[image_nr]):
data = linalg_plane_fit(size_x, size_y, data)
create_thumb_images(data, image_nr, image_name, data_file_name)
if old_y_size != "" and old_y_pixel != "":
globvar_AFMdata.y_size = old_y_size
globvar_AFMdata.y_pixel = old_y_pixel
else:
continue
return True
def prepare_Omicron_SCALA_spectra_curves(par_file):
"""
print(par_file)
print(globvar_AFMdata.spec_files,
globvar_AFMdata.spec_x_unit,
globvar_AFMdata.spec_x_label,
globvar_AFMdata.spec_y_unit,
globvar_AFMdata.spec_y_label,
globvar_AFMdata.spec_y_factor,
globvar_AFMdata.spec_points,
globvar_AFMdata.spec_feedback,
globvar_AFMdata.spec_acquisition,
globvar_AFMdata.spec_delay)
"""
i = 0
for data_file in globvar_AFMdata.spec_files:
data_file_name = data_file
data_file = os.path.join(globvar_AFMdir.working_directory,data_file)
# If the file does not exist continue loop
if not os.path.isfile(data_file):
continue
# If the file is 0Byte large (empty) continue loop (Do not consider
# the file)
if os.stat(data_file)[6] == 0:
continue
Channel = int(data_file[-1:])
# Image name - Cut the suffix.
image_name = data_file_name[:-4]
# Put in some zeros after the 'm'.
if image_name[2] == "_":
image_name = image_name[0:1]+"00"+image_name[1:]
if image_name[3] == "_":
image_name = image_name[0:1]+"0"+image_name[1:]
# Suffix. New since 2017-07-28.
image_name = image_name + "_s0" + str(Channel)
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".jpeg"
if os.path.isfile(image_path):
continue
data_file_p = open(data_file, "r")
for line in data_file_p:
if "END COORD" in line:
break
for line in data_file_p:
if "BEGIN" in line:
break
x_data_list = []
y_data_list = []
for line in data_file_p:
if "BEGIN" in line:
continue
x_data = []
y_data = []
for line in data_file_p:
if "END" in line:
break
split_list = line.rsplit()
x_data.append(split_list[0])
y_data.append(globvar_AFMdata.spec_y_factor[i]
* (float(split_list[1])/32767.0 ))
if x_data != [] and y_data != []:
x_data_list.append(x_data)
y_data_list.append(y_data)
# Close the Omicron file
data_file_p.close()
create_thumb_spectra(x_data_list,
y_data_list,
i,
image_name,
image_path,
globvar_AFMdata.spec_y_label[i])
i += 1
return True

BIN
AFM_thumbs/Omicron_SCALA.pyc Executable file

Binary file not shown.

267
AFM_thumbs/PDF.py Executable file
View File

@@ -0,0 +1,267 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import os
import shutil
import re
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_spaces
# This is the definiton which produces the pdf. We will make use of
# graphicsmagic's 'gm montage' to realize the montage of thumbnail images in a
# x/y pattern into png/jpeg sheets. After, imagemagick's 'convert' will be used
# to create pdfs from the pngs/jpegs. Last, it is pdftk that puts together all
# pdfs.
#
# May be, all this can be changed such that we either have only graphicsmagic
# or imagemagick. Can we avoid also pdftk? Let's see in future.
def prepare_PDFs():
# Decide over the image ending
if globvar_ThumbPara.png:
end = '.png'
else:
end = '.jpeg'
# Get the list of images in the thumbnail directory.
image_file_list = filter(lambda x: x.endswith(end),
os.listdir(globvar_AFMdir.thumbnail_directory))
image_file_list = list(image_file_list)
if image_file_list == []:
print(globvar_spaces + "There are no images in the directory\n" +
globvar_spaces + globvar_AFMdir.thumbnail_directory + " !\n" +
globvar_spaces + "We leave this out ... .\n")
return False
# The list is well ordered thanks to the 001, 002, etc. order (see
# definitions in Omicron_SCALA.py, Nanotec_DULCINEA.py and RHK.py)
image_file_list.sort()
# Initialize the string for gm montage
# p: font size of the title, scale with number of images in one row
para_mon_p = globvar_ThumbPara.col * 8
str_tile = str(globvar_ThumbPara.col) + "x" + str(globvar_ThumbPara.row)
geo_x = max(globvar_ThumbPara.geometry_x)
geo_y = max(globvar_ThumbPara.geometry_y)
# First part of the string for graphicsmagick with standard parameters for
# all pdfs.
para_gm_mon_1 = ("gm montage -geometry " + str(geo_x) + "x" + str(geo_y) +
" -pointsize " + str(para_mon_p) +
" -title \"" + globvar_AFMdir.working_directory + "\"" +
" -tile " + str_tile + " " )
# Initialization of the string for gm and convert
m_str = ""
r = 0 # counter - total number of images on one page
q = 0 # counter - number of pages
FLAG_first_spec_image = False
# This "for loop" takes up to 'globvar_ThumbPara.col*globvar_ThumbPara.row'
# images for one page. The code is done such that first single pdf pages
# are created in the thumbnail directory. The reason is that graphicsmagic
# is asking for too much RAM otherwise. After all, pdftk puts together
# all pdf pages (see below).
#
# This was strongly improved on 2017-07-28.
for image_file in image_file_list:
if r < globvar_ThumbPara.col*globvar_ThumbPara.row:
# If a spectroscopy image appears then ...
if "_s" in image_file:
#if image_file[9:10] == "s":
# For the first spectroscopy image:
if "_s00" in image_file:
#if image_file[9:11] == "s0":
# Note that there is some spectroscopy data.
FLAG_first_spec_image = True
# Number of free slots in a row.
if r % globvar_ThumbPara.col == 0:
free_slots_in_row = 0
else:
free_slots_in_row = globvar_ThumbPara.col - (r % globvar_ThumbPara.col)
# If there is still some place in the row, fill it
# with dummies.
if free_slots_in_row != 0:
for i in range (free_slots_in_row):
m_str = m_str + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
"dummy_image.png\"")
r += 1
# ... if it is an image then ...
else:
# Uuups, the last image was obviously a spectroscopy image, now
# it is an SPM image. If so, new row:
if FLAG_first_spec_image == True:
# Number of free slots in a row.
if r % globvar_ThumbPara.col == 0:
free_slots_in_row = 0
else:
free_slots_in_row = globvar_ThumbPara.col - (r % globvar_ThumbPara.col)
# If there is still some place in the row, fill it
# with dummies.
if free_slots_in_row != 0:
for i in range (free_slots_in_row):
m_str = m_str + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
"dummy_image.png\"")
r += 1
FLAG_first_spec_image = False
# Put image and ...
m_str = m_str + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
image_file) + "\""
# ... image counter one up
r += 1
# globvar_ThumbPara.col*globvar_ThumbPara.row images are
# collected, or, end of image_file_list. So then do:
else:
# Create only one page first!
# Reason for this: If about 20 pages shall be created the pages
# cannot be stored within one pdf because Graphicsmagick is
# asking for too much RAM!!! So, page after page ...
# Number of pages
q += 1
# Graphicsmagic - montage
last_part = "_%.02d" + end + "\""
image_string = (para_gm_mon_1 + m_str + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
globvar_AFMdir.data_directory_name) + \
last_part % q)
os.system(image_string)
# Imagemagic - pdf
middle_part = "_%.02d" + end + "\" \""
pdf_string = ("convert -density 300 -compress JPEG -quality " + \
str(globvar_ThumbPara.jpeg) + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
globvar_AFMdir.data_directory_name) + \
middle_part%q + \
os.path.join(globvar_AFMdir.thumbnail_directory,
globvar_AFMdir.data_directory_name) + \
"_%.03d.pdf\" "%q )
os.system(pdf_string)
# Initialize and put in the first image
r = 1
m_str = "\""+os.path.join(globvar_AFMdir.thumbnail_directory,
image_file) + "\""
# If the image is a 'first' spectroscopy image then ...
if "_s00" in image_file:
# if image_file[9:11] == "s00":
# Note that there is some spectroscopy data.
FLAG_first_spec_image = True
# if there are remaining pages (r > 1) put them on one page
if r > 1:
q += 1
last_part = "_%.02d" + end + "\""
image_string = (para_gm_mon_1+m_str + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
globvar_AFMdir.data_directory_name) + \
last_part % q )
os.system(image_string)
middle_part = "_%.02d" + end + "\" \""
pdf_string = ("convert -density 300 -compress JPEG -quality " + \
str(globvar_ThumbPara.jpeg) + " \"" + \
os.path.join(globvar_AFMdir.thumbnail_directory,
globvar_AFMdir.data_directory_name) + \
middle_part%q + \
os.path.join(globvar_AFMdir.thumbnail_directory,
globvar_AFMdir.data_directory_name) + \
"_%.03d.pdf\" "%q )
os.system(pdf_string)
#
#
# Prepare the command string for pdftk for connecting all pdf pages.
#
#
# This following 'directory thing' was done for pdftk under Windows XP.
# First, we save the directory of AFM_thumbs and ...
AFM_thumbs_directory = os.getcwd()
# ... then, we go inside the thumbnail directory, and later we put the
# system path back onto 'AFM_thumbs_directory' (see below).
os.chdir(globvar_AFMdir.thumbnail_directory)
# Apply pdftk for putting together the pdfs.
if globvar_AFMdir.pdf_path == "":
pdf_string = ("pdftk *.pdf cat output \"" + \
globvar_AFMdir.working_directory + \
globvar_ThumbPara.extension + ".pdf\"" )
else:
pdf_string = ("pdftk *.pdf cat output \"" + \
os.path.join(globvar_AFMdir.pdf_path,
globvar_AFMdir.data_directory_name) + \
globvar_ThumbPara.extension+".pdf\"" )
# Execute pdftk
os.system(pdf_string)
# Now, we go back into the directory of AFM_thumbs
os.chdir(AFM_thumbs_directory)
# If true, delete all thumbnails and pdfs and finally the thumbnail
# directory
if globvar_ThumbPara.thumbs_after:
delete_string = globvar_AFMdir.thumbnail_directory
shutil.rmtree(delete_string)
else:
file_list = os.listdir(globvar_AFMdir.thumbnail_directory)
for f in file_list:
if f.endswith(".pdf"):
os.remove(os.path.join(globvar_AFMdir.thumbnail_directory,f))
elif f.endswith(end):
if re.search(globvar_AFMdir.data_directory_name,f):
os.remove(os.path.join(globvar_AFMdir.thumbnail_directory,f))

BIN
AFM_thumbs/PDF.pyc Executable file

Binary file not shown.

674
AFM_thumbs/RHK.py Executable file
View File

@@ -0,0 +1,674 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import sys
import os
import struct
import numpy
import math
import re
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_spaces
from AFM_thumbs.Variables import RHK_must_exist
from AFM_thumbs.Variables import RHK_PositionCounter
from AFM_thumbs.Variables import globvar_thumb_size_x
from AFM_thumbs.Variables import globvar_thumb_size_y
from AFM_thumbs.Linalg import check_image_properties
from AFM_thumbs.Thumbs import create_thumb_images
from AFM_thumbs.Thumbs import create_thumb_spectra
from AFM_thumbs.Thumbs import spectra_text
from AFM_thumbs.Linalg import linalg_plane_fit
from AFM_thumbs.Linalg import linalg_line_fit
from AFM_thumbs.Initialize import initialize_AFM_data
from AFM_thumbs.Channel import proceed_with
from AFM_thumbs.Channel import line_fit
from AFM_thumbs.Channel import plane_fit
from AFM_thumbs.Channel import rename_channel
# Method to determine whether there are RHK files.
def is_RHK_file(directory, files):
list_directories_sm4 = []
# A directroy is only interesting if there is at least
# one SM4 file.
FLAG = False
for filename in files:
file_name = os.path.join(directory, filename)
if file_name[-4:] in RHK_must_exist:
FLAG = True
if FLAG == True:
if os.path.isdir(directory):
list_directories_sm4.append(directory)
break
return list_directories_sm4
# This method reads out the scan information.
# RHK technology stores all measurement data in one file with no order!
# Because of this the plane- and linefitting settings doesn't matter in the
# current version of this method
def read_RHK_data(SM4_file):
# _______________________________________________________ Direction check
initialize_AFM_data()
sm4_file_path = os.path.join(globvar_AFMdir.working_directory,SM4_file)
with open(sm4_file_path, "rb") as sm4_datafile: # open file
sm4_file = sm4_datafile.read()
globvar_AFMdata.datfile.append(sm4_file_path)
# ___________________________________________ Reading of the File Header
# Version Check
current_position = 38
version = sm4_file[0:current_position]
if not version[2:-2:2] == "STiMage 005.004 1":
version_error = "This method was written on base of SM4 Version " \
"\'STiMage 005.004 1\'. The results of any other " \
"version can differ from the expected one. The current " \
"file version: "
print(globvar_spaces + version_error + version.decode("utf-8"))
print
# File Header information
total_page_count = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
object_list_count = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
# Check the Ocject Field size
if not struct.unpack('i', sm4_file[current_position: \
current_position+4])[0] == 12:
obJect_field_error = "Wrong size of object field. " \
"This may cause a problem."
print(globvar_spaces + obJect_field_error)
print
current_position += 12
# Create Array for the Object List Items
objects = numpy.zeros((object_list_count, 3))
for i in range(object_list_count):
objects[i,0] = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0] # tape
current_position += 4
objects[i,1] = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0] # offset
current_position += 4
objects[i,2] = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0] # size
current_position += 4
# _________________________________________ Content of PAGE INDEX HEADER
# Page Count Check
page_count = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
if not page_count == total_page_count:
page_count_error = "The total number of pages is not the same as " \
"the number of pages. Some data may be left out or doubled."
print(globvar_spaces + page_count_error)
print
page_object_list_count = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
current_position += 8
# Page Index Object
index_array = numpy.zeros((page_object_list_count, 3))
for i in range(page_object_list_count):
index_array[i,0] = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0];
current_position += 4
# beginning of the Page index Array
index_array[i,1] = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0];
current_position += 4
index_array[i,2] = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0];
current_position += 4
# Page ID Offset
pageindex_page_id_offset = 16 # Page ID hat Laenge 16
# for-loop over all channels
for channel in range(page_count):
# Determining the startpoint
if channel is 0:
next_page_index_array_offset = 0
current_position = int(index_array[0,1]) + pageindex_page_id_offset
else:
current_position = int(next_page_index_array_offset) \
+ pageindex_page_id_offset
# Page Index Array
current_position += 4
# Page Type
page_data_type = struct.unpack('i', sm4_file \
[current_position:current_position+4])[0]
current_position += 4
pageindex_object_list_count = struct.unpack('i', sm4_file \
[current_position:current_position+4])[0]
current_position += 4
current_position += 4
# Create an array for the Object List Items
array_objects = numpy.zeros((pageindex_object_list_count, 3))
for i in range(pageindex_object_list_count):
array_objects[i,0] = struct.unpack('i', sm4_file[current_position \
:current_position+4])[0] # tape
current_position += 4
array_objects[i,1] = struct.unpack('i', sm4_file[current_position \
:current_position+4])[0] # offset
current_position += 4
array_objects[i,2] = struct.unpack('i', sm4_file[current_position \
:current_position+4])[0] # size
current_position += 4
# Request of the current position for the start of the next loop
next_page_index_array_offset = current_position
# Page header
current_position = int(array_objects[0,1])+4
page_type = str(struct.unpack('i', sm4_file[current_position: \
current_position+4])[0])
# Pixel
current_position = int(array_objects[0,1])+24
globvar_AFMdata.x_pixel = str(struct.unpack('i',
sm4_file[current_position:current_position+4])[0])
current_position += 4
globvar_AFMdata.y_pixel = str(struct.unpack('i',
sm4_file[current_position:current_position+4])[0])
current_position += 4
# Scan direction
current_position = int(array_objects[0,1])+36
scan_direction = struct.unpack('i',
sm4_file[current_position:current_position+4])[0];
current_position += 4
if scan_direction == 0:
globvar_AFMdata.scandir.append("right")
elif scan_direction == 1:
globvar_AFMdata.scandir.append("left")
elif scan_direction == 2:
globvar_AFMdata.scandir.append("up")
elif scan_direction == 3:
globvar_AFMdata.scandir.append("down")
current_position += 4
data_size = struct.unpack('i', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
# Maximum z-Values
globvar_AFMdata.z_min.append(struct.unpack('=l',
sm4_file[current_position:current_position+4])[0])
current_position += 4
globvar_AFMdata.z_max.append(struct.unpack('=l',
sm4_file[current_position:current_position+4])[0])
current_position += 4
# Sizes
globvar_AFMdata.x_size = struct.unpack('f', sm4_file[current_position:\
current_position+4])[0]
current_position += 4
globvar_AFMdata.y_size = struct.unpack('f', sm4_file[current_position:\
current_position+4])[0]
current_position += 4
globvar_AFMdata.z_factor.append(struct.unpack('f',
sm4_file[current_position:current_position+4])[0])
current_position += 4
# Offsets
current_position += 4
globvar_AFMdata.x_off = struct.unpack('f', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
globvar_AFMdata.y_off = struct.unpack('f', sm4_file[current_position: \
current_position+4])[0]
current_position += 4
# Speed
current_position += 4
globvar_AFMdata.speed = struct.unpack('f', sm4_file[current_position: \
current_position+4])[0] * \
int(globvar_AFMdata.x_pixel) * 1000
current_position += 4
# Voltage
globvar_AFMdata.voltage = "{0:.1f}".format(struct.unpack('f',
sm4_file[current_position: \
current_position+4])[0])
current_position += 4
# Angle
current_position += 4
globvar_AFMdata.angle = "{0:.1f}".format(struct.unpack('f', sm4_file[ \
current_position:current_position+4])[0])
current_position += 4
# Page Header Object List
current_position += 12
page_header_object_list_count = struct.unpack('i', sm4_file \
[current_position:current_position+4])[0]
current_position += 4
# Go to the page header object list.
current_position = int(array_objects[0,1]) + int(array_objects[0,2])
array_header_objects = numpy.zeros((page_header_object_list_count, 3))
for i in range(page_header_object_list_count):
array_header_objects[i,0] = struct.unpack('i', \
sm4_file[current_position:current_position+4])[0]
current_position += 4
array_header_objects[i,1] = struct.unpack('i', \
sm4_file[current_position:current_position+4])[0]
current_position += 4
array_header_objects[i,2] = struct.unpack('i', \
sm4_file[current_position:current_position+4])[0]
current_position += 4
# Go to the text string to get the title.
current_position = int(array_header_objects[0,1])
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
channel_name = sm4_file[current_position:current_position+str_length:2]
current_position += str_length
# __________________________________________________ Check the title
# Substitut all whitespaces with underscore.
channel_name = str(re.sub('\s', '_', channel_name.decode("utf-8")))
# Search all special characters and change the title.
if re.search('\W', channel_name):
channel_name_index = re.search('\W', channel_name).start()
channel_name = channel_name[:channel_name_index]
# If there are underscores at the end of the title, eliminate them.
Space = True
while Space:
if channel_name[-1] == "_":
channel_name = channel_name[:-1]
else:
Space = False
# Replace all underscores with a simple whitespace
channel_name = re.sub('_', ' ', channel_name)
# Add the channel name.
rename_channel(channel_name)
# Skip next 4 strings.
for i in range(4):
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
current_position += str_length
# date
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.date = sm4_file[current_position: \
current_position+str_length:2].decode("utf-8")
current_position += str_length
# time
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.date += ", " + sm4_file[current_position: \
current_position+str_length:2].decode("utf-8")
current_position += str_length
# Units
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.spec_x_unit.append(sm4_file[current_position: \
current_position+str_length:2].decode("utf-8"))
# Clemens Barth, 2016-01-15 ........................
#
# There is a problem with the unit for y! The following code
# needs to be revized.
current_position += str_length
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.spec_y_unit.append(sm4_file[current_position: \
current_position+str_length:2].decode("utf-8"))
#print(globvar_AFMdata.spec_x_unit, globvar_AFMdata.spec_y_unit)
# ...................... until here
current_position += str_length
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.unit.append(sm4_file[current_position: \
current_position+str_length:2].decode("utf-8"))
current_position += str_length
# Topography scale is in nm.
if globvar_AFMdata.channel[-1].find("Topography") != -1 and \
globvar_AFMdata.unit[-1].find("m") != -1:
globvar_AFMdata.z_factor[-1] = float(globvar_AFMdata.z_factor[-1] \
*math.pow(10,9))
globvar_AFMdata.unit[-1] = "nm"
# Labels
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.spec_x_label.append(sm4_file[current_position: \
current_position+str_length:2].decode("utf-8"))
current_position += str_length
str_length = 2*struct.unpack('h', sm4_file[current_position: \
current_position+2])[0]
current_position += 2
globvar_AFMdata.spec_y_label.append(sm4_file[current_position: \
current_position+str_length:2].decode("utf-8"))
current_position += str_length
# _____________________________________________________ Prepare image
if channel%2 == 0:
direction = "forward"
elif channel%2 != 0:
direction = "backward"
if int(page_data_type) != 0:
prepare_RHK_spektra(sm4_file_path, SM4_file,
channel,
int(array_objects[1,1]))
elif int(page_type) in [16,38,39]:
if globvar_ThumbPara.spektra == 1:
prepare_RHK_spektra(sm4_file_path,
SM4_file, channel,
int(array_objects[1,1]))
else:
if proceed_with(channel,direction):
prepare_RHK_images(sm4_file_path, SM4_file,
channel,
int(array_objects[1,1]))
else:
continue
return True
# This methods reads out the measurement data and prepares it for the image.
def prepare_RHK_images(file_path, file_name, image_nr, data_off):
# If the thumb image exists continue with the next one ... .
# (Don't calculate a second time.)
if image_nr%2 == 0:
direction = "forward"
elif image_nr%2 != 0:
direction = "backward"
picture_file_name = globvar_AFMdata.channel[-1].replace(" ","_") + "_" + \
direction + "_" + file_name
# Add the specific number of the channel.
# Fill empty space with zeros.
if int(RHK_PositionCounter.position / 10) == 0:
picture_file_name = "000" + str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
elif int(RHK_PositionCounter.position / 10) < 10:
picture_file_name = "00" + str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
elif int(RHK_PositionCounter.position / 10) < 100:
picture_file_name = "0" + str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
else:
picture_file_name = str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
picture_file_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
picture_file_name) + ".jpeg"
if os.path.isfile(image_path):
return
# Format Information
size_x = int(globvar_AFMdata.x_pixel)
size_y = int(globvar_AFMdata.y_pixel)
globvar_AFMdata.speed = "{0:.1f}".format(globvar_AFMdata.speed)
globvar_AFMdata.x_size = int(globvar_AFMdata.x_pixel) * \
float(globvar_AFMdata.x_size)*math.pow(10,9)
globvar_AFMdata.y_size = int(globvar_AFMdata.y_pixel) * \
float(globvar_AFMdata.y_size)*math.pow(10,9)
mirror_x = False
mirror_y = False
if globvar_AFMdata.x_size < 0:
mirror_x = True
if globvar_AFMdata.y_size < 0:
mirror_y = True
globvar_AFMdata.x_size = "{0:.1f}".format(abs(globvar_AFMdata.x_size))
globvar_AFMdata.y_size = "{0:.1f}".format(abs(globvar_AFMdata.y_size))
globvar_AFMdata.x_off = "{0:.1f}".format(float(globvar_AFMdata.x_off) * \
math.pow(10,9))
globvar_AFMdata.y_off = "{0:.1f}".format(float(globvar_AFMdata.y_off) * \
math.pow(10,9))
# Read the position of the binary data.
with open(file_path, "rb") as sm4_file: # open file
# Go to position in the file.
sm4_file.seek(data_off,0)
# Go straight to numpy data (no buffering).
data = numpy.fromfile(sm4_file, dtype = numpy.int32,
count = size_x*size_y)
# Check if the image really has the expected size.
# 'size_x*size_y'.
# old_y_size and old_y_pixel are needed to temporarily store
# the original size in y (nm and pixel). This is then used
# at the end to put back the original values for
# globvar_AFMdata.y_size and globvar_AFMdata.y_pixel, for the
# text in the thumbs.
data, old_y_size, old_y_pixel = check_image_properties(data,
globvar_AFMdata.datfile[-1])
# If there is some corrupt image the y value, which has been
# changed in check_image_properties, needs to be updated.
size_y = int(globvar_AFMdata.y_pixel)
# First, transform the integers into floats. This is needed for all
# mathematical operations.
data = data.astype(float)
# Average value
average = numpy.average(data)
data = data * globvar_AFMdata.z_factor[-1]
# Calibrate the avergae value and write it into the globvar_AFMdata
# structure.
globvar_AFMdata.z_average = average * globvar_AFMdata.z_factor[-1]
# Make now a 2D array.
data.shape = numpy.array([size_y, size_x])
# Mirror the data
if mirror_x:
data = numpy.fliplr(data)
if not mirror_y:
data = numpy.flipud(data)
# Fitting
if line_fit(image_nr,direction):
data = linalg_line_fit(size_x, size_y, data)
if plane_fit(image_nr,direction):
data = linalg_plane_fit(size_x, size_y, data)
create_thumb_images(data, image_nr, picture_file_name, file_name)
if old_y_size != "" and old_y_pixel != "":
globvar_AFMdata.y_size = old_y_size
globvar_AFMdata.y_pixel = old_y_pixel
return True
def prepare_RHK_spektra(file_path, file_name, image_nr, data_off):
picture_file_name = globvar_AFMdata.channel[-1].replace(" ","_") + "_" + \
file_name
# Add the specific number of the channel.
# Fill empty space with zeros.
if int(RHK_PositionCounter.position / 10) == 0:
picture_file_name = "000" + str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
elif int(RHK_PositionCounter.position / 10) < 10:
picture_file_name = "00" + str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
elif int(RHK_PositionCounter.position / 10) < 100:
picture_file_name = "0" + str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
else:
picture_file_name = str(RHK_PositionCounter.position) + \
"_" + picture_file_name
RHK_PositionCounter.add()
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
picture_file_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
picture_file_name) + ".jpeg"
if os.path.isfile(image_path):
return
# Format Text
globvar_AFMdata.spec_points = [0]
globvar_AFMdata.spec_points[0] = globvar_AFMdata.x_pixel
globvar_AFMdata.spec_acquisition.append(
"{0:.6f}".format(globvar_AFMdata.speed / math.pow(10,6)))
globvar_AFMdata.spec_delay = [""]
globvar_AFMdata.spec_feedback = [""]
# Read the position of the binary data.
size_x = int(globvar_AFMdata.x_pixel)
size_y = int(globvar_AFMdata.y_pixel)
x_data_list = []
y_data_list = []
x_data = [(x*abs(float(globvar_AFMdata.x_size))) + \
float(globvar_AFMdata.x_off) for x in range(size_x)]
with open(file_path, "rb") as sm4_file: # open file
# Go to position in the file.
sm4_file.seek(data_off,0)
# Go straight to numpy data (no buffering).
for i in range(size_y):
x_data_list.append(x_data)
y_data = numpy.fromfile(sm4_file, dtype = numpy.int32,
count = size_x)
y_data = y_data.astype(float)
y_data = y_data*globvar_AFMdata.z_factor[-1]
y_data += globvar_AFMdata.y_off
y_data_list.append(y_data)
create_thumb_spectra(x_data_list,
y_data_list,
0,
picture_file_name,
image_path,
globvar_AFMdata.channel[-1])
return True

BIN
AFM_thumbs/RHK.pyc Executable file

Binary file not shown.

947
AFM_thumbs/SPECS_Nanonis.py Executable file
View File

@@ -0,0 +1,947 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import sys
import os
import numpy as np
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_thumb_size_x
from AFM_thumbs.Variables import globvar_thumb_size_y
from AFM_thumbs.Variables import SPECS_Nanonis_images_must_exist
from AFM_thumbs.Variables import SPECS_Nanonis_spectroscopy_must_exist
from AFM_thumbs.Linalg import linalg_plane_fit
from AFM_thumbs.Linalg import linalg_line_fit
from AFM_thumbs.Linalg import check_image_properties
from AFM_thumbs.Thumbs import create_thumb_images
from AFM_thumbs.Thumbs import create_thumb_spectra
from AFM_thumbs.Initialize import initialize_AFM_data
from AFM_thumbs.Channel import proceed_with
from AFM_thumbs.Channel import line_fit
from AFM_thumbs.Channel import plane_fit
from AFM_thumbs.Channel import rename_channel
# _________________________________________________________________ Definitions
def is_SPECS_Nanonis_file(directory, files):
list_directories = []
# A directroy is listed if there is at least one Nanonis file.
for filename in files:
file_name = os.path.join(directory, filename)
if os.path.splitext(filename)[1] == SPECS_Nanonis_images_must_exist:
if os.path.isdir(directory):
list_directories.append(directory)
break
if os.path.splitext(filename)[1] == SPECS_Nanonis_spectroscopy_must_exist:
if os.path.isdir(directory):
list_directories.append(directory)
break
return list_directories
# This is the definition, which stores diverse parameters from the header of
# an .sxm into the parameter class of AFM_thumbs.
def read_SPECS_Nanonis_image_data(nanonis_file):
# # Print the entire header.
# nanonis_file_path = os.path.join(globvar_AFMdir.working_directory, nanonis_file)
# nanonis_file_p = open(nanonis_file_path, "rb")
# line = ""
# while line!=b':SCANIT_END:':
# line = nanonis_file_p.readline().rstrip()
# print(line)
# nanonis_file_p.close()
initialize_AFM_data()
# Open the Nanonis file.
nanonis_file_path = os.path.join(globvar_AFMdir.working_directory,
nanonis_file)
nanonis_file_p = open(nanonis_file_path, "rb")
# Read until the end of the header and convert all into string.
line_ = ""
list_line = []
while line_!=b':SCANIT_END:':
line_ = nanonis_file_p.readline().rstrip()
list_line.append(line_.decode("utf-8"))
# Offset position of the data inside the sxm file. It is said that these
# are normally 4 bytes after the identifier ':SCANIT_END:'. However,
# the following seems to be the 'correct way'.
while nanonis_file_p.read(1)!=b'\x1a':
pass
assert nanonis_file_p.read(1)==b'\x04'
# Note the offset and ...
data_offset = nanonis_file_p.tell()
# ... close the Nanonis file ...
nanonis_file_p.close()
# Read now the header in 'list_line'.
for i in range(len(list_line)):
if ":REC_DATE:" in list_line[i]:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.date = line
if ":REC_TIME:" in list_line[i]:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.date += ", " + line
if ":SCAN_FILE:" in list_line[i]:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.datfile = [line]
if ":SCAN_RANGE:" in list_line[i]:
i += 1
line = list_line[i].rstrip().split(' ')
line = [x for x in line if x]
# The unit of x and y in nm.
x_size = float(line[0]) / 1e-9
y_size = float(line[1]) / 1e-9
globvar_AFMdata.x_size = "%.1f" % x_size
globvar_AFMdata.y_size = "%.1f" % y_size
if ":SCAN_PIXELS:" in list_line[i]:
line = list_line[i+1].rstrip().split(' ')
line = [x for x in line if x]
globvar_AFMdata.x_pixel = line[0]
globvar_AFMdata.y_pixel = line[1]
if ":SCAN_OFFSET:" in list_line[i]:
i += 1
line = list_line[i].rstrip().split(' ')
line = [x for x in line if x]
# The unit of x and y in nm.
x_off = float(line[0]) / 1e-9
y_off = float(line[1]) / 1e-9
globvar_AFMdata.x_off = "%.1f" % x_off
globvar_AFMdata.y_off = "%.1f" % y_off
if ":SCAN_ANGLE:" in list_line[i]:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.angle = str(float(line))
if ":SCAN_DIR:" in list_line[i]:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.scan_updown = line
if ":SCAN_TIME:" in list_line[i]:
i += 1
line = list_line[i].rstrip().split(' ')
line = [x for x in line if x]
globvar_AFMdata.speed = float(line[0])
# :ACQ_TIME:
# 255.6
# :SCAN_TIME:
# 4.992E-1 4.992E-1
if ":BIAS:" in list_line[i]:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.voltage = str(float(line))
if ":Z-CONTROLLER:" in list_line[i]:
# :Z-CONTROLLER:
# Name on Setpoint P-gain I-gain T-const
# log Current 1 2.000E-10 A 2.937E-11 m 3.865E-7 m/s 7.599E-5 s
i += 2
line = list_line[i].rstrip()
line = line.split(" ")
line = [x for x in line if x]
globvar_AFMdata.measurement_type = line[0]
# The unit of the feedback is needed further below
globvar_AFMdata.feedback = line[2]
# Remove the units of the gain
globvar_AFMdata.gain_prop = line[3].split(' ')[0]
globvar_AFMdata.gain_int = line[4].split(' ')[0]
#globvar_AFMdata.gain = line[5]
if ":DATA_INFO:" in list_line[i]:
# :DATA_INFO:
# Channel Name Unit Direction Calibration Offset
# 14 Z m both 1.400E-7 0.000E+0
# 0C Current A both 3.000E-10 2.218E-12
# 16 OC_D1_Phase deg both 1.800E+1 0.000E+0
# 17 OC_D1_Amplitude m both 1.000E-9 0.000E+0
# 18 OC_M1_Freq._Shift Hz both 7.812E+3 0.000E+0
# 19 OC_M1_Excitation V both 1.000E-2 0.000E+0
# The channels with the following names are not supported.
#
# Bias
# Laser_power_mon.
# Laser_Setpoint
# Output_3
# Output_4
# X
# Y
# Output_8
channels_not_supported = ["Bias",
"Laser_power_mon.",
"Laser_Setpoint",
"Output_3",
"Output_4",
"X",
"Y",
"Output_8"]
i += 1
line = list_line[i]
while True:
i += 1
line = list_line[i].rstrip()
if line == '':
break
line = line.split(" ")
line = [x for x in line if x]
# Channel name
channel_name = line[1]
# Just continue if a channel with a specific name is not
# supported.
if channel_name in channels_not_supported:
continue
# Assign the correct channel names
if channel_name == "Current":
channel_name = "I"
if channel_name == "OC_D1_Phase":
channel_name = "Phase"
if channel_name == "OC_D1_Amplitude":
channel_name = "Amplitude"
if channel_name == "OC_M1_Freq._Shift":
channel_name = "df"
if channel_name == "OC_M1_Excitation":
channel_name = "Dissipation"
if channel_name == "KPFM":
channel_name = "Kelvin"
if channel_name == "KPFM_err":
channel_name = "KELVIN_ERR"
globvar_AFMdata.scandir.append("forward")
globvar_AFMdata.scandir.append("backward")
# Put in 2x for forward and backward scanning direction.
rename_channel(channel_name)
rename_channel(channel_name)
globvar_AFMdata.unit.append(line[2])
globvar_AFMdata.unit.append(line[2])
globvar_AFMdata.z_calibration.append(line[4])
globvar_AFMdata.z_calibration.append(line[4])
globvar_AFMdata.z_offset.append(line[5])
globvar_AFMdata.z_offset.append(line[5])
# AFM part
if ":Oscillation Control>Center Frequency (Hz):" in list_line[i]:
if "Frequency" in globvar_AFMdata.measurement_type:
i += 1
line = list_line[i].rstrip().strip()
globvar_AFMdata.res_freq = line
if ":Oscillation Control>FrequencyShift (Hz):" in list_line[i]:
if "Frequency" in globvar_AFMdata.measurement_type:
i += 1
line = list_line[i].rstrip().strip()
if ":Oscillation Control>Amplitude Setpoint (m):" in list_line[i]:
if "Frequency" in globvar_AFMdata.measurement_type:
i += 1
line = list_line[i].rstrip().strip()
# Amplitude in nm!
amplitude = "%.1f" % (float(line) * 1e9)
if ":Oscillation Control>Input Calibration (m/V):" in list_line[i]:
if "Frequency" in globvar_AFMdata.measurement_type:
i += 1
line = list_line[i].rstrip().strip()
# S_A in nm/V!
S_A = "%.1f" % (float(line) * 1e9)
# The amplitude info is a combination of the amplitude in nm AND the
# S_A calibration factor in nm/V.
if "Frequency" in globvar_AFMdata.measurement_type:
globvar_AFMdata.amplitude = amplitude + ", S_A: " + S_A
# Preparation of some variables
# =============================
# 1. We need to prepare the feedback variable. It can be the current
# (I, here in nA), force (here in nN) or df (here in Hz).
feedback = globvar_AFMdata.feedback.split(' ')
# For current and force
if feedback[-1] == 'A' or feedback[-1] == 'F':
globvar_AFMdata.feedback = str(float(feedback[0]) * 1e9)
# Everything in Hz etc.
else:
globvar_AFMdata.feedback = str(float(feedback[0]))
# 2. The scan speed. Currently it is the time per line, however, we
# translate it into nm/s. Later, it is translated into frequency (Hz).
speed = float(globvar_AFMdata.x_size) / globvar_AFMdata.speed
globvar_AFMdata.speed = "%.2f" % speed
# Return the offset, which is used in the definition
# 'prepare_Nanonis_images'.
return data_offset
# This is the definition, which prepares the image data of all channels. The
# data is then directly send to the definition, which prepares the thumbnails.
def prepare_SPECS_Nanonis_images(nanonis_file, data_offset):
# Open the Nanonis file. Inside this file, all images can be found. So,
# the file remains open during the entire loading of the images.
nanonis_file_path = os.path.join(globvar_AFMdir.working_directory,
nanonis_file)
nanonis_file_p = open(nanonis_file_path, "rb")
# Go through all channels and create the thumbnails.
for image_nr, channel in enumerate(globvar_AFMdata.channel):
# The definition 'proceed_with' is 'connected' with the GUI of
# AFM_thumbs where one can choose if a channel of a specific
# scanning direction shall be represented in a pdf file or not.
if proceed_with(image_nr,globvar_AFMdata.scandir[image_nr]):
# Prepare the file path.
pos = globvar_AFMdata.datfile[0].rfind('\\')
data_file_name = globvar_AFMdata.datfile[0][pos+1:]
# The name of the thumbnail image, in a correct order.
image_name = data_file_name[:-4]
if image_name[2] == "_":
image_name = image_name[0:1]+"00"+image_name[1:]
if image_name[3] == "_":
image_name = image_name[0:1]+"0"+image_name[1:]
image_name = image_name + "_" + str(image_nr)
# This is a code that is related to the option in the GUI, if the
# thumbs shall be saved as pngs or jpegs.
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".jpeg"
# If a thumb image exists continue with the next one (don't
# calculate a second time).
if os.path.isfile(image_path):
continue
# x/y size of the image, taken from the parameter class.
size_x = int(globvar_AFMdata.x_pixel)
size_y = int(globvar_AFMdata.y_pixel)
# Put the file pointer onto the correct position. One has to
# multipy by a factor of 4 because ... .
nanonis_file_p.seek(data_offset + image_nr*size_x*size_y*4)
# Read the data block. It is 'big endian float 32' type of data.
# A block (an image) has the image size of 'size_x*size_y'.
data = np.fromfile(nanonis_file_p,
dtype = '>f4',
count = size_x*size_y)
# 'big endian float 32' : '>f4'
# 'little endian float 32': '<f4'
# 'big endian float 64' : '>f8'
# 'little endian float 64': '<f8'
# old_y_size and old_y_pixel are needed to temporarily store
# the original size in y (nm and pixel). This is then used
# at the end to put back the original values for
# globvar_AFMdata.y_size and globvar_AFMdata.y_pixel, for the
# text in the thumbs.
# The 'nanonis_file_path' is used for an eventual error message.
data, old_y_size, old_y_pixel = check_image_properties(data,
nanonis_file_path)
# If there is some corrupt image the y value, which has been
# changed in check_image_properties, needs to be updated.
size_y = int(globvar_AFMdata.y_pixel)
# Average value
average = np.average(data)
# Put the lowest point onto ZERO.
data = data - data.min()
# Scale the image with the values found in the header.
# A bit strange: in 'globvar_AFMdata.z_calibration[image_nr]'
# the factor does not seem to be the correct one for z values. To
# be clarified in future.
data = data * 1e9
# Calibrate the average value.
globvar_AFMdata.z_average = average * 1e9
# Make now a 2D array.
data.shape = np.array([size_y, size_x])
# Mirror the data along the y-axis for backward images
if globvar_AFMdata.scandir[image_nr] == "backward":
# Left-right flip
data = np.fliplr(data)
# Mirror the data along the x-axisy for down scanning.
if globvar_AFMdata.scan_updown == "down":
# Up-down flip
data = np.flipud(data)
# Line fit
if line_fit(image_nr,globvar_AFMdata.scandir[image_nr]):
data = linalg_line_fit(size_x, size_y, data)
# Plane fit
if plane_fit(image_nr,globvar_AFMdata.scandir[image_nr]):
data = linalg_plane_fit(size_x, size_y, data)
create_thumb_images(data, image_nr, image_name, data_file_name)
if old_y_size != "" and old_y_pixel != "":
globvar_AFMdata.y_size = old_y_size
globvar_AFMdata.y_pixel = old_y_pixel
else:
continue
# Close the Nanonis file ...
nanonis_file_p.close()
# This is the definition, which stores diverse parameters from the header of
# a spectrum/sweep file into the parameter class of AFM_thumbs.
def read_SPECS_Nanonis_spectra_data(nanonis_file):
# If the file is 0 Byte large (empty) continue loop (Do not consider
# the file)
if os.stat(nanonis_file)[6] == 0:
return [], []
# Initialization of FLAGs
# =======================
# Regular z spectroscopy
FLAG_Z_SPEC = False
# Regular bias sweep spectroscopy
FLAG_U_SWEEP = False
# Regular bias spectroscopy
FLAG_U_SPEC = False
# Frequency sweep
FLAG_f0_SPEC = False
# NP charging spectroscopy
FLAG_NPC = False
# Focre curve alignement (FCA) spectroscopy
FLAG_FCA = False
# Open the file
data_file_p = open(nanonis_file, "r")
# Determine the type of spectroscopy.
for line in data_file_p:
# End of header, get out.
if "[DATA]" in line:
break
if "Experiment Z spectroscopy " in line:
FLAG_Z_SPEC = True
if "Experiment bias sweep " in line:
FLAG_U_SWEEP = True
if "Experiment bias spectroscopy" in line:
FLAG_U_SPEC = True
if "Q " in line:
FLAG_f0_SPEC = True
if "# Calibrate Amplitude" in line:
FLAG_FCA = True
if "# Charge Nanoparticles" in line:
FLAG_NPC = True
# Close the file.
data_file_p.close()
# Open the file again.
data_file_p = open(nanonis_file, "r")
# Parse the entire file.
FLAG_real_dat_file = False
spec_position = ""
for line in data_file_p:
# End of header
if "[DATA]" in line:
FLAG_real_dat_file = True
break
# For all: x, y, z, z_offset position, date
# =========================================
if "X (m) " in line[:7]:
line = line.rstrip().split(' ')
spec_pos_x = "Pos: %.1f" % (float(line[-1]) * 1e9)
if "Y (m) " in line[:7]:
line = line.rstrip().split(' ')
spec_pos_y = "%.1f" % (float(line[-1]) * 1e9)
if "Z (m) " in line[:7]:
line = line.rstrip().split(' ')
spec_pos_z = "%.1f" % (float(line[-1]) * 1e9)
if "Z offset (m) " in line:
line = line.rstrip().split(' ')
spec_pos_z_off = "%.1f" % (float(line[-1]) * 1e9)
if "Saved Date" in line:
date = line[10:].rstrip().strip()
date = date.split()
date = date[0] + ", " + date[1]
# Distance spectroscopy
# =====================
if FLAG_Z_SPEC:
if "Z offset (m) " in line:
line = line.rstrip().split(' ')
spec_z_off = "%.1f" % (float(line[-1]) * 1e9)
if "Z sweep distance (m) " in line:
line = line.rstrip().split(' ')
spec_z_dist = "%.1f" % (float(line[-1]) * 1e9)
if "Integration time (s) " in line:
line = line.rstrip().split(' ')
spec_z_t_integr = "%.1f" % (float(line[-1]) * 1000.0)
if "Settling time (s) " in line:
line = line.rstrip().split(' ')
spec_z_t_settl = "%.1f" % (float(line[-1]) * 1000.0)
if "Filter type " in line:
line = line.rstrip().split(' ')
spec_z_filter = line[-1]
# Bias spectroscopy
# =================
if FLAG_U_SPEC:
if "Integration time (s) " in line:
line = line.rstrip().split(' ')
spec_U_t_integr = "%.1f" % (float(line[-1]) * 1000.0)
if "Settling time (s) " in line:
line = line.rstrip().split(' ')
spec_U_t_settl = "%.1f" % (float(line[-1]) * 1000.0)
if "Filter type " in line:
line = line.rstrip().split(' ')
spec_U_filter = line[-1]
# Bias sweep
# ==========
if FLAG_U_SWEEP:
if "Number of steps " in line:
line = line.rstrip().split(' ')
sweep_U_points = line[-1]
if "Initial Bias (V) " in line:
line = line.rstrip().split(' ')
sweep_U_ini = "%.2f" % float(line[-1])
if "Lower limit (V) " in line:
line = line.rstrip().split(' ')
sweep_U_lower_limit = "%.2f" % float(line[-1])
if "Upper limit (V) " in line:
line = line.rstrip().split(' ')
sweep_U_upper_limit = "%.2f" % float(line[-1])
if "Step size (V) " in line:
line = line.rstrip().split(' ')
sweep_U_step = "%.2f" % float(line[-1])
if "Measurement period (s) " in line:
line = line.rstrip().split(' ')
sweep_U_t_integr = "%.1f" % (float(line[-1]) * 1000.0)
if "Settling time (s) " in line:
line = line.rstrip().split(' ')
sweep_U_t_settl = "%.1f" % (float(line[-1]) * 1000.0)
if "Z-Controller off " in line:
line = line.rstrip().split(' ')
sweep_U_controller = line[-1]
if "Reset Bias " in line:
line = line.rstrip().split(' ')
sweep_U_reset = line[-1]
# Normal f0 sweep
# ===============
if FLAG_f0_SPEC:
if "Number of points " in line:
line = line.rstrip().split(' ')
sweep_points_curve = line[-1]
if "f_res (Hz) " in line:
line = line.rstrip().split(' ')
sweep_f0 = "%.2f" % (float(line[-1]) / 1000.0)
if "Q " in line:
line = line.rstrip().split(' ')
sweep_Q = line[-1]
if "Phase (deg) " in line:
line = line.rstrip().split(' ')
sweep_phase = "%.1f" % float(line[-1])
if "Amp/Exc (nm/mV) " in line:
line = line.rstrip().split(' ')
sweep_A_exi_cal= "%.2f" % float(line[-1])
if "Oscillation Control>Input Calibration (m/V) " in line:
line = line.rstrip().split(' ')
sweep_A_cali = "%.2f" % (float(line[-1]) * 1e9)
if "Oscillation Control>Excitation (V) " in line:
line = line.rstrip().split(' ')
sweep_A_exi = "%.2f" % (float(line[-1]) * 1000.0)
# NPC (NP charging)
# =================
if FLAG_NPC:
if "Add_dz_start (m) " in line:
line = line.rstrip().split(' ')
spec_NPC_add_dz_start = "%.2f" % (float(line[-1]) * 1e9)
if "No_points " in line:
line = line.rstrip().split(' ')
spec_NPC_n_points = str(int(line[-1]) * 2)
if "DV_to_CPD (V) " in line:
line = line.rstrip().split(' ')
spec_NPC_dv_to_cpd = "%.2f" % (float(line[-1]))
if "CPD_measured (V) " in line:
line = line.rstrip().split(' ')
spec_NPC_cpd_measured = "%.2f" % (float(line[-1]))
if "Delay_for_CPD (ms) " in line:
line = line.rstrip().split(' ')
spec_NPC_cpd_delay = "%.1f" % (float(line[-1]))
if "Bias_voltage_range (V) " in line:
line = line.rstrip().split(' ')
spec_NPC_bias_range = "%.2f" % (float(line[-1]))
if "Z_averaging_time (s) " in line:
line = line.rstrip().split(' ')
spec_NPC_z_average_t = "%.2f" % (float(line[-1]) * 1000.0)
if "Z_offset (m) " in line:
line = line.rstrip().split(' ')
spec_NPC_z_off = "%.2f" % (float(line[-1]) * 1e9)
if "Integration_time (s) " in line:
line = line.rstrip().split(' ')
spec_NPC_t_integr = "%.2f" % (float(line[-1]) * 1000.0)
if "Settling_time (s) " in line or "Settling time (s) " in line:
line = line.rstrip().split(' ')
spec_NPC_t_settl = "%.2f" % (float(line[-1]) * 1000.0)
# FCA (force curve alignement method)
# ===================================
if FLAG_FCA:
if "No_points_curve " in line:
line = line.rstrip().split(' ')
spec_FCA_points_curve = line[-1]
if "Oscillation Control>Center Frequency (Hz) " in line:
line = line.rstrip().split(' ')
spec_FCA_f0 = "%.2f" % (float(line[-1]) / 1000.0)
if "Z_offset (m) " in line:
line = line.rstrip().split(' ')
spec_FCA_z_off = "%.1f" % (float(line[-1]) * 1e9)
if "Spring_constant (Hz) " in line:
line = line.rstrip().split(' ')
spec_FCA_k = "%.2f" % (float(line[-1]))
if "No_amplitude_values " in line:
line = line.rstrip().split(' ')
spec_FCA_A_no = line[-1]
if "Amplitude_start (V) " in line:
line = line.rstrip().split(' ')
spec_FCA_A_start = "%.2f" % (float(line[-1]))
if "Amplitude_change (V) " in line:
line = line.rstrip().split(' ')
spec_FCA_A_change = "%.2f" % (float(line[-1]))
if "Sweep_distance (m) " in line:
line = line.rstrip().split(' ')
spec_FCA_sweep_dist = "%.2f" % (float(line[-1]) * 1e9)
if "Time_acq_point (ms) " in line:
line = line.rstrip().split(' ')
spec_FCA_acquisition = "%.2f" % (float(line[-1]) / 1000.0)
if "Time_passed_loop" in line:
line = line.rstrip().split(' ')
spec_FCA_t_loop = "%.2f" % (float(line[-1]))
if "Time_passed_tot" in line:
line = line.rstrip().split(' ')
spec_FCA_t_tot = "%.2f" % (float(line[-1]))
# It is not a Nanonis data file because the identifier '[DATA]' could not
# be found!
if not FLAG_real_dat_file:
return [], []
list_data = []
for i, line in enumerate(data_file_p):
# Do not consider empty lines.
if line[:-2] == "":
continue
# Do not consider FCA specific identifiers.
if "loop_" in line.lower():
continue
line = line.rstrip().strip().split(' ')
if i == 0:
for channel in line[1:]:
# We basically use always the same x values
unit = line[0].split(' ')[-1][1:-1]
globvar_AFMdata.spec_x_label.append(line[0][:-(len(unit)+2)])
globvar_AFMdata.spec_x_unit.append(unit)
# The y values
unit = channel.split(' ')[-1][1:-1]
globvar_AFMdata.spec_y_label.append(channel[:-(len(unit)+2)])
globvar_AFMdata.spec_y_unit.append(unit)
continue
list_data.append(line)
# Close the file.
data_file_p.close()
list_X = []
list_Y = []
for i in range(len(list_data[0])-1):
list_x = []
list_y = []
for line in list_data:
list_x.append(float(line[0]))
list_y.append(float(line[i+1]))
list_X.append(list_x)
list_Y.append(list_y)
nr_channels = len(list_data[0])-1
nr_points = len(list_X[0])
# Preparation of text string for the thumbs
# =========================================
# Attention!
# ----------
# We have to adapt to the 'old' way of SCALA doing... . However, we ceate
# our specific 'globvar_AFMdata.spec_other' variable, which contains all
# parameters. Preparing the text string already here is much more easy ... .
globvar_AFMdata.spec_other = ""
if 'date' in locals():
globvar_AFMdata.spec_other += "-- " + date + " -- "
# First the x, y, z position
spec_position = ""
if 'spec_pos_x' in locals():
spec_position += spec_pos_x + "|"
if 'spec_pos_y' in locals():
spec_position += spec_pos_y + "|"
if 'spec_pos_z' in locals():
spec_position += spec_pos_z
else:
if globvar_AFMdata.spec_position != "":
spec_position = spec_position[:-1]
if 'spec_pos_z_off' in locals():
spec_position += "(" + spec_pos_z_off + ")"
globvar_AFMdata.spec_position = [spec_position] * nr_channels
# Text for z spectroscopy
if FLAG_Z_SPEC:
globvar_AFMdata.spec_other += "Points: " + str(nr_points) + "nm, "
if 'spec_z_off' in locals():
globvar_AFMdata.spec_other += "Z off: " + spec_z_off + "nm, "
if 'spec_z_dist' in locals():
globvar_AFMdata.spec_other += "Z dist. range: " + spec_z_dist + "nm, "
if 'spec_z_filter' in locals():
globvar_AFMdata.spec_other += "Filter: " + spec_z_filter + ", "
if 'spec_z_t_integr' in locals():
globvar_AFMdata.spec_other += "t (integr): " + spec_z_t_integr + "ms, "
if 'spec_z_t_settl' in locals():
globvar_AFMdata.spec_other += "t (settl): " + spec_z_t_settl + "ms, "
if 'spec_z_t_integr' in locals() and 'spec_z_t_settl':
spec_z_t_total = "%.2f" % ((float(spec_z_t_integr) +
float(spec_z_t_settl)) *
float(nr_points) / 1000.0)
globvar_AFMdata.spec_other += "t (tot): " + spec_z_t_total + "s, "
# Text for U spectroscopy
if FLAG_U_SPEC:
globvar_AFMdata.spec_other += "Points: " + str(nr_points) + "nm, "
if 'spec_U_filter' in locals():
globvar_AFMdata.spec_other += "Filter: " + spec_U_filter + ", "
if 'spec_U_t_integr' in locals():
globvar_AFMdata.spec_other += "t (integr): " + spec_U_t_integr + "ms, "
if 'spec_U_t_settl' in locals():
globvar_AFMdata.spec_other += "t (settl): " + spec_U_t_settl + "ms, "
if 'spec_U_t_integr' in locals() and 'spec_U_t_settl' in locals():
spec_t_total = "%.2f" % ((float(spec_U_t_integr) +
float(spec_U_t_settl)) *
float(nr_points) / 1000.0)
globvar_AFMdata.spec_other += "t (tot): " + spec_t_total + "s, "
# Text for U sweep
if FLAG_U_SWEEP:
if 'sweep_U_points' in locals():
globvar_AFMdata.spec_other += "Points: " + sweep_U_points + ", "
if 'sweep_U_ini' in locals():
globvar_AFMdata.spec_other += "U_ini: " + sweep_U_ini + "V, "
if 'sweep_U_lower_limit' in locals():
globvar_AFMdata.spec_other += "U_low: " + sweep_U_lower_limit + "V, "
if 'sweep_U_upper_limit' in locals():
globvar_AFMdata.spec_other += "U_up: " + sweep_U_upper_limit + "V, "
if 'sweep_U_step' in locals():
globvar_AFMdata.spec_other += "U_step: " + sweep_U_step + "V, "
if 'sweep_U_controller' in locals():
globvar_AFMdata.spec_other += "Controller: " + sweep_U_controller + ", "
if 'sweep_U_reset' in locals():
globvar_AFMdata.spec_other += "Reset: " + sweep_U_reset + ", "
if 'sweep_U_t_integr' in locals():
globvar_AFMdata.spec_other += "t (integr): " + sweep_U_t_integr + "ms, "
if 'sweep_U_t_settl' in locals():
globvar_AFMdata.spec_other += "t (settl): " + sweep_U_t_settl + "ms, "
if 'sweep_U_t_integr' in locals() and 'sweep_U_t_settl' in locals() and 'sweep_U_points' in locals():
sweep_t_total = "%.2f" % ((float(sweep_U_t_integr) +
float(sweep_U_t_settl)) *
float(sweep_U_points) / 1000.0)
globvar_AFMdata.spec_other += "t (tot): " + sweep_t_total + "s, "
# Text for f0 sweep
if FLAG_f0_SPEC:
if 'sweep_points_curve' in locals():
globvar_AFMdata.spec_other += "Points: " + sweep_points_curve + ", "
if 'sweep_f0' in locals():
globvar_AFMdata.spec_other += "f0: " + sweep_f0 + "Hz, "
if 'sweep_Q' in locals():
globvar_AFMdata.spec_other += "Q: " + sweep_Q + ", "
if 'sweep_phase' in locals():
globvar_AFMdata.spec_other += "Phi: " + sweep_phase + "V, "
if 'sweep_A_exi_cal' in locals():
globvar_AFMdata.spec_other += "A_exi_cal: " + sweep_A_exi_cal + "nm/mV, "
if 'sweep_A_cali' in locals():
globvar_AFMdata.spec_other += "A_cali: " + sweep_A_cali + "nm/V, "
if 'sweep_A_exi' in locals():
globvar_AFMdata.spec_other += "A_exi: " + sweep_A_exi + "mV"
# Text for the NPC method
if FLAG_NPC:
if 'spec_NPC_n_points' in locals():
globvar_AFMdata.spec_other += "Points: " + spec_NPC_n_points + ", "
if 'spec_NPC_add_dz_start' in locals():
globvar_AFMdata.spec_other += "Add_z_start: " + spec_NPC_add_dz_start + "nm, "
if 'spec_NPC_dv_to_cpd' in locals():
globvar_AFMdata.spec_other += "CPD-dV: " + spec_NPC_dv_to_cpd + "V, "
if 'spec_NPC_cpd_measured' in locals():
globvar_AFMdata.spec_other += "CPD: " + spec_NPC_cpd_measured + "V, "
if 'spec_NPC_cpd_delay' in locals():
globvar_AFMdata.spec_other += "t (CPD): " + spec_NPC_cpd_delay + "ms, "
if 'spec_NPC_bias_range' in locals():
globvar_AFMdata.spec_other += "V range: " + spec_NPC_bias_range + "V, "
if 'spec_NPC_z_average_t' in locals():
globvar_AFMdata.spec_other += "Z average t: " + spec_NPC_z_average_t + "ms, "
if 'spec_NPC_z_off' in locals():
globvar_AFMdata.spec_other += "Z off: " + spec_NPC_z_off + "nm, "
if 'spec_NPC_t_integr' in locals():
globvar_AFMdata.spec_other += "t (integr): " + spec_NPC_t_integr + "ms, "
if 'spec_NPC_t_settl' in locals():
globvar_AFMdata.spec_other += "t (settl): " + spec_NPC_t_settl + "ms, "
if 'spec_NPC_t_integr' in locals() and 'spec_NPC_n_points' in locals() and 'spec_NPC_t_settl' in locals():
spec_NPC_t_total = "%.2f" % ((float(spec_NPC_t_integr) +
float(spec_NPC_t_settl)) *
float(spec_NPC_n_points) / 1000.0)
globvar_AFMdata.spec_other += "t (tot): " + spec_NPC_t_total + "s, "
# Text for the FCA method
if FLAG_FCA:
if 'spec_FCA_points_curve' in locals():
globvar_AFMdata.spec_other += "Points/curve: " + spec_FCA_points_curve + ", "
if 'spec_FCA_k' in locals():
globvar_AFMdata.spec_other += "k: " + spec_FCA_k + "N/m, "
if 'spec_FCA_f0' in locals():
globvar_AFMdata.spec_other += "f0: " + spec_FCA_f0 + "Hz, "
if 'spec_FCA_A_no' in locals():
globvar_AFMdata.spec_other += "No. Ampls: " + spec_FCA_A_no + ", "
if 'spec_FCA_A_start' in locals():
globvar_AFMdata.spec_other += "A_start: " + spec_FCA_A_start + "V, "
if 'spec_FCA_A_change' in locals():
globvar_AFMdata.spec_other += "A_change: " + spec_FCA_A_change + "V, "
if 'spec_FCA_z_off' in locals():
globvar_AFMdata.spec_other += "Z_offset: " + spec_FCA_z_off + "nm, "
if 'spec_FCA_sweep_dist' in locals():
globvar_AFMdata.spec_other += "Dist: " + spec_FCA_sweep_dist + "nm, "
if 'spec_FCA_t_loop' in locals():
globvar_AFMdata.spec_other += "t (exp): " + spec_FCA_t_loop + "min, "
if 'spec_FCA_t_tot' in locals():
globvar_AFMdata.spec_other += "t (tot): " + spec_FCA_t_tot + "min, "
#print(nanonis_file,
# globvar_AFMdata.date,
# globvar_AFMdata.spec_files,
# globvar_AFMdata.spec_x_label,
# globvar_AFMdata.spec_x_unit,
# globvar_AFMdata.spec_y_label,
# globvar_AFMdata.spec_y_unit,
# globvar_AFMdata.spec_y_factor,
# globvar_AFMdata.spec_points,
# globvar_AFMdata.spec_feedback,
# globvar_AFMdata.spec_acquisition,
# globvar_AFMdata.spec_time,
# globvar_AFMdata.spec_position,
# globvar_AFMdata.spec_delay,
# globvar_AFMdata.sweep_f0,
# globvar_AFMdata.sweep_Q,
# globvar_AFMdata.sweep_phase,
# globvar_AFMdata.sweep_A_exec)
return list_X, list_Y
# This is the definition, which prepares the spectra data. The
# data is then directly send to the definition, which prepares the thumbnails.
def prepare_SPECS_Nanonis_spectra_curves(nanonis_file):
initialize_AFM_data()
data_file_name = nanonis_file
data_file = os.path.join(globvar_AFMdir.working_directory,data_file_name)
list_X, list_Y = read_SPECS_Nanonis_spectra_data(data_file)
if list_X == [] or list_Y == []:
return False
i = 0
for list_x, list_y in zip(list_X, list_Y):
image_name, file_extension = os.path.splitext(nanonis_file)
# There has to be an 's', which is used to identify the thumb image as
# an spectroscopy thumb image!
image_name = image_name + "_" + "s%02d" % (i)
if globvar_ThumbPara.png:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".png"
else:
image_path = os.path.join(globvar_AFMdir.thumbnail_directory,
image_name) + ".jpeg"
if os.path.isfile(image_path):
return True
create_thumb_spectra([list_x],
[list_y],
i,
image_name,
image_path,
globvar_AFMdata.spec_y_label[i])
i += 1
return True

BIN
AFM_thumbs/SPECS_Nanonis.pyc Executable file

Binary file not shown.

571
AFM_thumbs/SPECS_Nanonis.txt Executable file
View File

@@ -0,0 +1,571 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
# Example for the complete header of a SPECS Nanonis '.sxm' file
# ==============================================================
#
# :NANONIS_VERSION:
# 2
# :SCANIT_TYPE:
# FLOAT MSBFIRST
# :REC_DATE:
# 17.01.2021
# :REC_TIME:
# 11:22:04
# :REC_TEMP:
# 290.0000000000
# :ACQ_TIME:
# 32.8
# :SCAN_PIXELS:
# 256 256
# :SCAN_FILE:
# D:\Session_test\Session_first_time_test\Test0001.sxm
# :SCAN_TIME:
# 6.400E-2 6.400E-2
# :SCAN_RANGE:
# 2.000000E-8 2.000000E-8
# :SCAN_OFFSET:
# 0.000000E+0 0.000000E+0
# :SCAN_ANGLE:
# 0.000E+0
# :SCAN_DIR:
# up
# :BIAS:
# 2.000E+0
# :Z-CONTROLLER:
# Name on Setpoint P-gain I-gain T-const
# log Current 1 5.000E-11 A 2.000E-10 m 2.000E-7 m/s 1.000E-3 s
# :COMMENT:
# Aha, so geht das ...
# :NanonisMain>Session Path:
# D:\Session_test\Session_first_time_test
# :NanonisMain>SW Version:
# Generic 5e
# :NanonisMain>UI Release:
# 10278
# :NanonisMain>RT Release:
# 10278
# :NanonisMain>RT Frequency (Hz):
# 20E+3
# :NanonisMain>Signals Oversampling:
# 10
# :NanonisMain>Acquisition Period (s):
# 20E-3
# :NanonisMain>Animations Period (s):
# 20E-3
# :NanonisMain>Indicators Period (s):
# 300E-3
# :NanonisMain>Measurements Period (s):
# 500E-3
# :Bias>Bias (V):
# 2E+0
# :Bias>Calibration (V/V):
# 1E+0
# :Bias>Offset (V):
# 0E+0
# :Current>Current (A):
# 50.033E-12
# :Current>Calibration (A/V):
# 5E-9
# :Current>Offset (A):
# 0E+0
# :Current>Gain:
# Low
# :Piezo Configuration>Active Calib.:
# Default
# :Piezo Configuration>Calib. X (m/V):
# 6E-9
# :Piezo Configuration>Calib. Y (m/V):
# 6E-9
# :Piezo Configuration>Calib. Z (m/V):
# -6E-9
# :Piezo Configuration>HV Gain X:
# 15
# :Piezo Configuration>HV Gain Y:
# 15
# :Piezo Configuration>HV Gain Z:
# 15
# :Piezo Configuration>Tilt X (deg):
# 0
# :Piezo Configuration>Tilt Y (deg):
# 0
# :Piezo Configuration>Curvature radius X (m):
# Inf
# :Piezo Configuration>Curvature radius Y (m):
# Inf
# :Piezo Configuration>2nd order corr X (V/m^2):
# 0E+0
# :Piezo Configuration>2nd order corr Y (V/m^2):
# 0E+0
# :Piezo Configuration>Drift X (m/s):
# 0E+0
# :Piezo Configuration>Drift Y (m/s):
# 0E+0
# :Piezo Configuration>Drift Z (m/s):
# 0E+0
# :Piezo Configuration>Drift correction status (on/off):
# FALSE
# :Z-Controller>Z (m):
# 39.1035E-9
# :Z-Controller>Controller name:
# log Current
# :Z-Controller>Controller status:
# ON
# :Z-Controller>Setpoint:
# 50E-12
# :Z-Controller>Setpoint unit:
# A
# :Z-Controller>P gain:
# 200E-12
# :Z-Controller>I gain:
# 200E-9
# :Z-Controller>Time const (s):
# 1E-3
# :Z-Controller>TipLift (m):
# 0E+0
# :Z-Controller>Switch off delay (s):
# 0E+0
# :Oscillation Control>differential input:
# FALSE
# :Oscillation Control>input 1/10:
# FALSE
# :Oscillation Control>Input Calibration (m/V):
# 1E-6
# :Oscillation Control>Input Range (m):
# 20.2162E-9
# :Oscillation Control>Center Frequency (Hz):
# 200E+3
# :Oscillation Control>Range (Hz):
# 9.53674E+0
# :Oscillation Control>Demod 1 Input:
# 1
# :Oscillation Control>Demod 2 Input:
# 1
# :Oscillation Control>Demod 3 Input:
# 1
# :Oscillation Control>Demod 4 Input:
# 1
# :Oscillation Control>Demod 1 Frequency:
# 1
# :Oscillation Control>Demod 2 Frequency:
# 1
# :Oscillation Control>Demod 3 Frequency:
# 1
# :Oscillation Control>Demod 4 Frequency:
# 1
# :Oscillation Control>Demod 1 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 2 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 3 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 4 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 1 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 2 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 3 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 4 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 1 Harmonic:
# 1
# :Oscillation Control>Demod 2 Harmonic:
# 1
# :Oscillation Control>Demod 3 Harmonic:
# 1
# :Oscillation Control>Demod 4 Harmonic:
# 1
# :Oscillation Control>Demod 1 Filter Order:
# 2
# :Oscillation Control>Demod 2 Filter Order:
# 2
# :Oscillation Control>Demod 3 Filter Order:
# 2
# :Oscillation Control>Demod 4 Filter Order:
# 2
# :Oscillation Control>Phase P gain (Hz/rad):
# 151.8E-3
# :Oscillation Control>Phase I gain (Hz/rad/s):
# 755.511E-3
# :Oscillation Control>Phase controller on:
# FALSE
# :Oscillation Control>FrequencyShift (Hz):
# 0E+0
# :Oscillation Control>Amplitude Setpoint (m):
# 1E-9
# :Oscillation Control>Amplitude P gain (V/nm):
# 1.41747E+3
# :Oscillation Control>Amplitude I gain (V/nm/s):
# 1.32194E+3
# :Oscillation Control>Amplitude controller on:
# FALSE
# :Oscillation Control>Excitation (V):
# 1E-3
# :Oscillation Control>Output Ampl. Range (V):
# 10
# :Oscillation Control>output off:
# FALSE
# :Oscillation Control>output add:
# TRUE
# :Oscillation Control>PLL-Setup Q-Factor:
# 14.284E+3
# :Oscillation Control>PLL-Setup Demod. Bandwidth Amp (Hz):
# 78.7927E-6
# :Oscillation Control>PLL-Setup Demod. Bandwidth Pha (Hz):
# 8.69749E+0
# :Oscillation Control>PLL-Setup amplitude/excitation (m/V):
# 7.94E-9
# :Scan>Scanfield:
# 0E+0;0E+0;20E-9;20E-9;0E+0
# :Scan>series name:
# Test
# :Scan>channels:
# Current (A);Z (m)
# :Scan>pixels/line:
# 256
# :Scan>lines:
# 256
# :Scan>speed forw. (m/s):
# 312.5E-9
# :Scan>speed backw. (m/s):
# 312.5E-9
# :DATA_INFO:
# Channel Name Unit Direction Calibration Offset
# 14 Z m both -9.000E-8 0.000E+0
# 0 Current A both 5.000E-9 0.000E+0
#
# :SCANIT_END:
# Another one
# :NANONIS_VERSION:
# 2
# :SCANIT_TYPE:
# FLOAT MSBFIRST
# :REC_DATE:
# 05.02.2021
# :REC_TIME:
# 19:40:42
# :REC_TEMP:
# 290.0000000000
# :ACQ_TIME:
# 288.5
# :SCAN_PIXELS:
# 512 512
# :SCAN_FILE:
# D:\Data\sessions_Ag001\2021-02-03_cycle_13\m_0086.sxm
# :SCAN_TIME:
# 5.120E-1 5.120E-1
# :SCAN_RANGE:
# 2.500000E-7 2.500000E-7
# :SCAN_OFFSET:
# 1.235544E-7 2.410663E-7
# :SCAN_ANGLE:
# 0.000E+0
# :SCAN_DIR:
# down
# :BIAS:
# 5.321E-1
# :Z-CONTROLLER:
# Name on Setpoint P-gain I-gain T-const
# Frequency (neg) 1 -4.500E+1 Hz 6.983E-11 m/Hz 2.643E-8 m/Hz/s 2.643E-3 s
# :COMMENT:
#
# :NanonisMain>Session Path:
# D:\Data\sessions_Ag001\2021-02-03_cycle_13
# :NanonisMain>SW Version:
# Generic 5e
# :NanonisMain>UI Release:
# 10278
# :NanonisMain>RT Release:
# 10278
# :NanonisMain>RT Frequency (Hz):
# 20E+3
# :NanonisMain>Signals Oversampling:
# 10
# :NanonisMain>Acquisition Period (s):
# 20E-3
# :NanonisMain>Animations Period (s):
# 20E-3
# :NanonisMain>Indicators Period (s):
# 300E-3
# :NanonisMain>Measurements Period (s):
# 10E-3
# :Bias>Bias (V):
# 532.11E-3
# :Bias>Calibration (V/V):
# 1E+0
# :Bias>Offset (V):
# 0E+0
# :Current>Current (A):
# -132.953E-15
# :Current>Calibration (A/V):
# 300E-12
# :Current>Offset (A):
# 2.2182E-12
# :Current>Gain:
# High
# :Piezo Configuration>Active Calib.:
# Default
# :Piezo Configuration>Calib. X (m/V):
# 10E-9
# :Piezo Configuration>Calib. Y (m/V):
# 10E-9
# :Piezo Configuration>Calib. Z (m/V):
# 10E-9
# :Piezo Configuration>HV Gain X:
# 14
# :Piezo Configuration>HV Gain Y:
# 14
# :Piezo Configuration>HV Gain Z:
# 14
# :Piezo Configuration>Tilt X (deg):
# 14.5234
# :Piezo Configuration>Tilt Y (deg):
# 2.32116
# :Piezo Configuration>Curvature radius X (m):
# Inf
# :Piezo Configuration>Curvature radius Y (m):
# Inf
# :Piezo Configuration>2nd order corr X (V/m^2):
# 0E+0
# :Piezo Configuration>2nd order corr Y (V/m^2):
# 0E+0
# :Piezo Configuration>Drift X (m/s):
# 0E+0
# :Piezo Configuration>Drift Y (m/s):
# 0E+0
# :Piezo Configuration>Drift Z (m/s):
# 0E+0
# :Piezo Configuration>Drift correction status (on/off):
# FALSE
# :Z-Controller>Z (m):
# 136.55E-9
# :Z-Controller>Controller name:
# Frequency (neg)
# :Z-Controller>Controller status:
# ON
# :Z-Controller>Setpoint:
# -45E+0
# :Z-Controller>Setpoint unit:
# Hz
# :Z-Controller>P gain:
# 69.8291E-12
# :Z-Controller>I gain:
# 26.4252E-9
# :Z-Controller>Time const (s):
# 2.64252E-3
# :Z-Controller>TipLift (m):
# 0E+0
# :Z-Controller>Switch off delay (s):
# 0E+0
# :Oscillation Control>differential input:
# TRUE
# :Oscillation Control>input 1/10:
# FALSE
# :Oscillation Control>Input Calibration (m/V):
# 10E-9
# :Oscillation Control>Input Range (m):
# 10E-9
# :Oscillation Control>Center Frequency (Hz):
# 311.101E+3
# :Oscillation Control>Range (Hz):
# 78.125E+3
# :Oscillation Control>Demod 1 Input:
# 1
# :Oscillation Control>Demod 2 Input:
# 1
# :Oscillation Control>Demod 3 Input:
# 1
# :Oscillation Control>Demod 4 Input:
# 1
# :Oscillation Control>Demod 1 Frequency:
# 1
# :Oscillation Control>Demod 2 Frequency:
# 1
# :Oscillation Control>Demod 3 Frequency:
# 1
# :Oscillation Control>Demod 4 Frequency:
# 1
# :Oscillation Control>Demod 1 Reference Phase (deg):
# 88.88E+0
# :Oscillation Control>Demod 2 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 3 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 4 Reference Phase (deg):
# 0E+0
# :Oscillation Control>Demod 1 Cut off frq (Hz):
# 3.11k
# :Oscillation Control>Demod 2 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 3 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 4 Cut off frq (Hz):
# 1.55k
# :Oscillation Control>Demod 1 Harmonic:
# 1
# :Oscillation Control>Demod 2 Harmonic:
# 1
# :Oscillation Control>Demod 3 Harmonic:
# 1
# :Oscillation Control>Demod 4 Harmonic:
# 1
# :Oscillation Control>Demod 1 Filter Order:
# 2
# :Oscillation Control>Demod 2 Filter Order:
# 2
# :Oscillation Control>Demod 3 Filter Order:
# 2
# :Oscillation Control>Demod 4 Filter Order:
# 2
# :Oscillation Control>Phase P gain (Hz/rad):
# 1.67285E+0
# :Oscillation Control>Phase I gain (Hz/rad/s):
# 57.6281E+0
# :Oscillation Control>Phase controller on:
# TRUE
# :Oscillation Control>FrequencyShift (Hz):
# -44.9015E+0
# :Oscillation Control>Amplitude Setpoint (m):
# 300E-12
# :Oscillation Control>Amplitude P gain (V/nm):
# 12.4425E+6
# :Oscillation Control>Amplitude I gain (V/nm/s):
# 428.632E+6
# :Oscillation Control>Amplitude controller on:
# TRUE
# :Oscillation Control>Excitation (V):
# 408.923E-6
# :Oscillation Control>Output Ampl. Range (V):
# 0.1
# :Oscillation Control>output off:
# TRUE
# :Oscillation Control>output add:
# FALSE
# :Oscillation Control>PLL-Setup Q-Factor:
# 27.721E+3
# :Oscillation Control>PLL-Setup Demod. Bandwidth Amp (Hz):
# 392.6E+0
# :Oscillation Control>PLL-Setup Demod. Bandwidth Pha (Hz):
# 95.847E+0
# :Oscillation Control>PLL-Setup amplitude/excitation (m/V):
# 753.229E-9
# :Scan>Scanfield:
# 123.554E-9;241.066E-9;250E-9;250E-9;0E+0
# :Scan>series name:
# m_
# :Scan>channels:
# Current (A);Z (m);OC D1 Amplitude (m);OC M1 Freq. Shift (Hz);OC M1 Excitation (V)
# :Scan>pixels/line:
# 512
# :Scan>lines:
# 512
# :Scan>speed forw. (m/s):
# 488.281E-9
# :Scan>speed backw. (m/s):
# 488.281E-9
# :Bias Spectroscopy>Sweep Start (V):
# -5E+0
# :Bias Spectroscopy>Sweep End (V):
# 5E+0
# :Bias Spectroscopy>Num Pixel:
# 256
# :Bias Spectroscopy>Z Avg time (s):
# 50E-3
# :Bias Spectroscopy>Z offset (m):
# 0E+0
# :Bias Spectroscopy>1st Settling time (s):
# 5E-3
# :Bias Spectroscopy>Settling time (s):
# 200E-6
# :Bias Spectroscopy>Integration time (s):
# 100E-6
# :Bias Spectroscopy>End Settling time (s):
# 5E-3
# :Bias Spectroscopy>Z control time (s):
# 200E-3
# :Bias Spectroscopy>Max Slew rate (V/s):
# Inf
# :Bias Spectroscopy>backward sweep:
# FALSE
# :Bias Spectroscopy>Z-controller hold:
# TRUE
# :Bias Spectroscopy>Number of sweeps:
# 1
# :Bias Spectroscopy>Channels:
# Current (A)
# :Bias Spectroscopy>Reset Bias:
# TRUE
# :Bias Spectroscopy>Record final Z:
# FALSE
# :Bias Spectroscopy>Lock-In run:
# FALSE
# :Z Spectroscopy>Initial Z-offset (m):
# 1E-9
# :Z Spectroscopy>Sweep distance (m):
# -7E-9
# :Z Spectroscopy>Num Pixel:
# 256
# :Z Spectroscopy>Z Avg time (s):
# 50E-3
# :Z Spectroscopy>1st Settling time (s):
# 5E-3
# :Z Spectroscopy>Settling time (s):
# 200E-6
# :Z Spectroscopy>Integration time (s):
# 100E-6
# :Z Spectroscopy>End Settling time (s):
# 5E-3
# :Z Spectroscopy>Z control time (s):
# 200E-3
# :Z Spectroscopy>Max Slew rate (V/s):
# Inf
# :Z Spectroscopy>backward sweep:
# TRUE
# :Z Spectroscopy>Number of sweeps:
# 1
# :Z Spectroscopy>Channels:
# Current (A)
# :Z Spectroscopy>Time between fwd/bwd (s):
# 0E+0
# :Z Spectroscopy>Record final Z:
# FALSE
# :Z Spectroscopy>Lock-In run:
# FALSE
# :Z Spectroscopy>Reset Z:
# TRUE
# :DATA_INFO:
# Channel Name Unit Direction Calibration Offset
# 14 Z m both 1.400E-7 0.000E+0
# 0 Current A both 3.000E-10 2.218E-12
# 17 OC_D1_Amplitude m both 1.000E-9 0.000E+0
# 18 OC_M1_Freq._Shift Hz both 7.812E+3 0.000E+0
# 19 OC_M1_Excitation V both 1.000E-2 0.000E+0
#
# :SCANIT_END:

463
AFM_thumbs/Thumbs.py Executable file
View File

@@ -0,0 +1,463 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
import sys
import os
import numpy as np
import re
# The following is a bit confusing but needed for crontab and ssh under Linux:
# Matplotlib needs an X-Server, which does not exist when doing, e.g., ssh.
# In the following we ask if the DISPLAY variable of the Linux system is set.
# If this is not the case then we tell Python to do something special for
# matplotlib (use of 'Agg')
#
# From: "http://stackoverflow.com/questions/4931376/
# generating-matplotlib-graphs-without-a-running-x-server"
# Other solution: matplotlib API, see "http://www.dalkescientific.com/writings/
# diary/archive/2005/04/23/matplotlib_without_gui.html"
if sys.platform == "linux2":
environ = os.environ
if "DISPLAY" not in environ:
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.lines as mpllines
from matplotlib.colors import LinearSegmentedColormap
from AFM_thumbs.Variables import globvar_AFMdata
from AFM_thumbs.Variables import globvar_AFMdir
from AFM_thumbs.Variables import globvar_ThumbPara
from AFM_thumbs.Variables import globvar_thumb_size_x
from AFM_thumbs.Variables import globvar_thumb_size_y
from AFM_thumbs.Variables import globvar_thumb_text_width
from AFM_thumbs.Variables import ID_abbreviations
from AFM_thumbs.Channel import select_color
from AFM_thumbs.Channel import invert
from AFM_thumbs.Colour import reverse_colourmap
# _________________________________________________________________ Definitions
def create_thumb_images(data, image_nr, image_name, data_file_name):
# If there is a meaningful number in 'globvar_ThumbPara.rms':
if re.match("^\d+?\.\d+?$", globvar_ThumbPara.rms) != None:
# We reshape the array first because we can then better analyze the
# data for the contrast adjustment via the rms value.
datar = np.reshape(data, data.size)
# If there are regions in the image that are on the exact same value
# then discard them from the statistics analysis! This happens when,
# e.g., Nanonis images were not stored until the end of a scanning
# frame.
where = np.where(np.diff(datar) == 0)
# At least the length of a scanning line.
if len(where[0]) > float(globvar_AFMdata.x_pixel):
datar = np.delete(datar, where)
# Put the rms value into a float. The factor of 2.0 is to adapt old
# values.
rms = abs(float(globvar_ThumbPara.rms)) * 2.0
# Average value of the data array
aver = np.average(datar)
# Substrat the average value from the data and consider only the
# the absolute deviations from the average.
sub = np.abs(np.subtract(datar, aver))
# From the absolute deviations, calculate the mean and max value.
sub_aver = np.average(sub)
sub_max = np.max(sub)
# Are there any spikes, so, values that overpass by a factor of 30?
index = np.argwhere(sub > 30.0 * sub_aver)
if index.size > 0:
# We reduce the rms value by a factor of 2.0.
rms = rms / 2.0
#print(image_nr, image_name, len(index))
# Cut the data on the top and bottom.
data = np.ma.clip(data, aver-sub_aver*rms, aver+sub_aver*rms)
# This deaktivates the interactive pyplot frame
# plt.ioff()
fig = plt.figure(figsize=(globvar_thumb_size_x, globvar_thumb_size_y))
frame = plt.subplot(111)
# Positioning of the image
plt.subplots_adjust(left=0.08, bottom=None,
right=0.99, top=1.1,
wspace=None, hspace=None)
# Image is put in
try:
float(globvar_AFMdata.x_size)
except ValueError:
globvar_AFMdata.x_size = "-100.0"
try:
float(globvar_AFMdata.y_size)
except ValueError:
globvar_AFMdata.y_size = "-100.0"
imgage = frame.imshow(data,extent=[0,abs(float(globvar_AFMdata.x_size)),
0,abs(float(globvar_AFMdata.y_size))])
# What kind of color scale do we have?
# Is it a pre-definied color from matplotlib, then it must be a string.
if type(select_color(image_nr, globvar_AFMdata.scandir[image_nr])) is str:
colormap = select_color(image_nr, globvar_AFMdata.scandir[image_nr])
if invert(image_nr,globvar_AFMdata.scandir[image_nr]):
colormap = reverse_colourmap("ListedColormap", colormap)
# If it is not a string, then it must be a color definied by ourselves,
# so go to here and transform this linear segment into a colormap.
else:
colormap = LinearSegmentedColormap("Colormap",select_color(image_nr,
globvar_AFMdata.scandir[image_nr]))
if invert(image_nr,globvar_AFMdata.scandir[image_nr]):
colormap = reverse_colourmap("LinearSegmentedColormap", colormap)
# Color scale
imgage.set_cmap(colormap)
if globvar_ThumbPara.peek:
imgage.set_clim(vmin=np.amin(data), vmax=np.amax(data))
# The colorbar
colorbar = fig.colorbar(imgage, shrink=0.65, aspect=30)
for t in colorbar.ax.get_yticklabels():
t.set_fontsize('x-small')
# The ticks and the size of the labels
plt.xticks(size = 'x-small')
plt.yticks(size = 'x-small')
# The ticks and their orientation
# ... at the bottom
lines = frame.get_xticklines()
labels = frame.get_xticklabels()
for line in lines:
line.set_marker(mpllines.TICKDOWN)
for label in labels:
label.set_y(-0.02)
# ... on the left
lines = frame.get_yticklines()
labels = frame.get_yticklabels()
for line in lines:
line.set_marker(mpllines.TICKLEFT)
for label in labels:
label.set_x(-0.02)
# Some text into the figure
# 1. Scanning direction to the bottom right
if globvar_AFMdata.scandir[image_nr] == "forward":
fig.text(0.83, 0.17, "forward", fontsize=10)
if globvar_AFMdata.scandir[image_nr] == "backward":
fig.text(0.83, 0.17, "backward", fontsize=10)
# 2. Channel to the top right
fig.text(0.83, 0.95,
globvar_AFMdata.channel[image_nr] + " (" + \
globvar_AFMdata.unit[image_nr] + ")",
fontsize=11)
# 3. Text with parameters below the image
fig.text(0.035 + float(globvar_ThumbPara.text_x),
0.015 + float(globvar_ThumbPara.text_y),
image_text(image_name),
fontname=globvar_ThumbPara.font,
size=int(globvar_ThumbPara.text_size))
# 4. Average value below color scale
data_average = globvar_AFMdata.z_average
data_average = str(data_average)
data_average = data_average[:data_average.find(".")+2]
fig.text(0.83, 0.2,
"Aver. (raw)\n" + data_average + " (" + \
globvar_AFMdata.unit[image_nr] + ")",
fontsize=10)
# Save image now !
image_path = os.path.join(globvar_AFMdir.thumbnail_directory, image_name)
if globvar_ThumbPara.png:
image_path=image_path+".png"
else:
image_path=image_path+".jpeg"
plt.savefig(image_path, dpi=int(globvar_ThumbPara.res))
#plt.close('all')
plt.close(fig)
plt.clf()
def image_text(image_name):
text_string = image_name + ", "
if globvar_ThumbPara.date and globvar_AFMdata.date != "":
text_string += "--"+globvar_AFMdata.date+"--, "
if globvar_ThumbPara.sizenm and globvar_AFMdata.x_size != "" and \
globvar_AFMdata.y_size != "":
text_string += "Size: " + globvar_AFMdata.x_size + "x" + \
globvar_AFMdata.y_size + ", "
if globvar_ThumbPara.sizepx and globvar_AFMdata.x_pixel != "" and \
globvar_AFMdata.y_pixel != "":
text_string += "Pixl: " + globvar_AFMdata.x_pixel + "x" + \
globvar_AFMdata.y_pixel + ", "
if globvar_ThumbPara.offset and globvar_AFMdata.x_off != "" and \
globvar_AFMdata.y_off != "":
text_string += "Off: " + globvar_AFMdata.x_off + "x" + \
globvar_AFMdata.y_off + ", "
# SPECS Nanonis
# =============
# So far, there is no option(button). This needs to be implemented in future.
if globvar_AFMdata.res_freq != "":
text_string += "f0: " + globvar_AFMdata.res_freq + ", "
if globvar_ThumbPara.gain and globvar_AFMdata.gain != "":
text_string += "Gain: " + globvar_AFMdata.gain + ", "
if globvar_ThumbPara.gain and globvar_AFMdata.gain_int != "":
text_string += "IGain: " + globvar_AFMdata.gain_int + ", "
if globvar_ThumbPara.gain and globvar_AFMdata.gain_prop != "":
text_string += "PGain: " + globvar_AFMdata.gain_prop + ", "
if globvar_ThumbPara.gain and globvar_AFMdata.gain_signal != "":
text_string += "SigGain: " + globvar_AFMdata.gain_signal + ", "
if globvar_ThumbPara.gain and globvar_AFMdata.gain_xy != "":
text_string += "XYGain: " + globvar_AFMdata.gain_xy + ", "
if globvar_ThumbPara.gain and globvar_AFMdata.gain_z != "":
text_string += "ZGain: " + globvar_AFMdata.gain_z + ", "
# SPECS Nanonis
# =============
# So far, there is no option (button). This needs to be implemented
# in future.
if globvar_AFMdata.scan_updown != "":
text_string += globvar_AFMdata.scan_updown.capitalize() + " scan, "
if globvar_ThumbPara.speed and globvar_AFMdata.speed != "":
# For Dulcinea
if " Hz" in globvar_AFMdata.speed:
speed = globvar_AFMdata.speed
text_string += speed
# Otherwise: we now use the scan frequency as a speed because it is
# more readable. (2021-02-05)
else:
speed = float(globvar_AFMdata.speed) / float(globvar_AFMdata.x_size)
text_string += "Speed: %.2f" % speed + ", "
if globvar_ThumbPara.ampl and globvar_AFMdata.amplitude != "":
text_string += "Ampl: " + globvar_AFMdata.amplitude + ", "
if globvar_ThumbPara.angle and globvar_AFMdata.angle != "":
text_string += "Phi: " + globvar_AFMdata.angle + ", "
# Change 2017-06-25
# 1. Ugap and Feedback are listed at the end!
if globvar_ThumbPara.voltage and globvar_AFMdata.voltage != "":
text_string += "Ugap: " + globvar_AFMdata.voltage + ", "
if globvar_ThumbPara.feedback and globvar_AFMdata.feedback != "":
text_string += "FB: " + globvar_AFMdata.feedback
# This loop is for building a block of the text introducing some "\n"
zaehler1 = 0
zaehler2 = 0
text_block = ""
block_length = globvar_thumb_text_width + int(globvar_ThumbPara.text_block)
while (zaehler1 < len(text_string)):
if (text_string[zaehler1] == " "):
if (zaehler2 > block_length):
text_block = text_block + "\n"
zaehler2 = 0
else:
text_block = text_block + text_string[zaehler1]
else:
text_block = text_block + text_string[zaehler1]
zaehler1 +=1
zaehler2 +=1
return text_block
# The function, which creates the thumbnails for spectra
def create_thumb_spectra(x_data_list,
y_data_list,
image_nr,
image_name,
image_path,
channel_name):
# Create figure
fig = plt.figure(figsize=(globvar_thumb_size_x,
globvar_thumb_size_y))
# Positioning of the graph inside the figure
plt.subplots_adjust(left=0.17, bottom=0.3,
right=0.95, top=0.95,
wspace=None, hspace=None)
# Plot the whole stuff
for x_data, y_data in zip(x_data_list, y_data_list):
plt.plot(x_data, y_data)
# Labels
plt.xlabel(globvar_AFMdata.spec_x_label[image_nr] + \
" ("+globvar_AFMdata.spec_x_unit[image_nr]+")")
plt.ylabel(globvar_AFMdata.spec_y_label[image_nr] + \
" ("+globvar_AFMdata.spec_y_unit[image_nr]+")")
if channel_name in ID_abbreviations:
channel_name = ID_abbreviations[channel_name]
# Some text ...
# 1. text below the spectra
fig.text(0.035 + float(globvar_ThumbPara.text_x),
0.035 + float(globvar_ThumbPara.text_y),
spectra_text(image_name,image_nr),
fontname=globvar_ThumbPara.font,
size=int(globvar_ThumbPara.text_size))
# The channel, measurement number or whatever to the bottom right
fig.text(0.92, 0.32,
channel_name,
fontsize=13,
horizontalalignment="right")
# The x, y, z(z_offset) position to the bottom left
if globvar_AFMdata.spec_position != []:
fig.text(0.92, 0.36,
globvar_AFMdata.spec_position[image_nr],
fontsize=13,
horizontalalignment="right")
# Save image now !
plt.savefig(image_path, dpi=int(globvar_ThumbPara.res))
plt.close(fig)
plt.clf()
# Create a white thumbnail image. This is needed as a space filler for
# the pdfs afterwards ... . The 'white' thumbnail is created only once.
# Name: 'dummy_image.png'. The path to the thumbnail:
image_dummy_path=os.path.join(globvar_AFMdir.thumbnail_directory,
"dummy_image")
# If it does not exist, create it.
if not os.path.isfile(image_dummy_path+".jpeg"):
fig=plt.figure(figsize=(globvar_thumb_size_x,globvar_thumb_size_y))
plt.savefig(image_dummy_path, dpi=int(globvar_ThumbPara.res))
plt.close(fig)
plt.clf()
return True
# The text below a spectrum. The routine has been modified on 2022-01-29,
# for in particular the Nanonis spectroscopy.
def spectra_text(image_name, channel):
# Cut the name if it has become too long!
if len(image_name) > 30:
image_name = image_name[:30] + "..."
text_string = image_name + ", "
if globvar_ThumbPara.date:
if globvar_AFMdata.date != "":
text_string += "--"+str(globvar_AFMdata.date)+"--, "
if globvar_AFMdata.spec_points != []:
if globvar_AFMdata.spec_points[channel] != "":
text_string += "Points: "+str(globvar_AFMdata.spec_points[channel])+", "
if globvar_AFMdata.spec_feedback != []:
if globvar_AFMdata.spec_feedback[channel] != "":
text_string += "Feedback: " + \
str(globvar_AFMdata.spec_feedback[channel])+", "
if globvar_AFMdata.spec_acquisition != []:
if globvar_AFMdata.spec_acquisition[channel] != "":
text_string += "Acq.time: "+str(float(globvar_AFMdata.spec_acquisition \
[channel])*1000.0)+"ms, "
if globvar_AFMdata.spec_delay != []:
if globvar_AFMdata.spec_delay[channel] != "":
text_string += "Delay: "+str(float(globvar_AFMdata.spec_delay \
[channel])*1000.0)+"ms, "
if globvar_AFMdata.spec_time != []:
if globvar_AFMdata.spec_time[channel] != "":
text_string += "Time: "+str(globvar_AFMdata.spec_time[channel]) + "ms, "
if globvar_ThumbPara.gain:
if globvar_AFMdata.gain != "":
text_string += "Gain: "+str(globvar_AFMdata.gain)+", "
if globvar_ThumbPara.ampl:
if globvar_AFMdata.amplitude != "":
text_string += "Ampl: "+str(globvar_AFMdata.amplitude)+"nm, "
# Other spectroscopy data that shall be displayed.
if globvar_AFMdata.spec_other != None:
text_string += globvar_AFMdata.spec_other
# Change 2017-06-25
# 1. Ugap and Feedback are listed at the end!
if globvar_ThumbPara.voltage:
if globvar_AFMdata.voltage != "":
text_string += "Ugap: "+str(globvar_AFMdata.voltage)+", "
if globvar_ThumbPara.feedback:
if globvar_AFMdata.feedback != "":
text_string += "FB: "+str(globvar_AFMdata.feedback)
# This while loop is for building a block of the text introducing
# some "\n"
zaehler1 = 0
zaehler2 = 0
text_block = ""
block_length = 50
while (zaehler1 < len(text_string)):
if (text_string[zaehler1] == " "):
if (zaehler2 > block_length):
text_block = text_block + "\n"
zaehler2 = 0
else:
text_block = text_block + text_string[zaehler1]
else:
text_block = text_block + text_string[zaehler1]
zaehler1 +=1
zaehler2 +=1
# If some variables are simply not available, then it might be that there
# is a ',' at the end. Remove the ','.
if text_block[-1] == ',':
text_block = text_block[:-1]
if text_block[-2] == ',':
text_block = text_block[:-2]
return text_block

BIN
AFM_thumbs/Thumbs.pyc Executable file

Binary file not shown.

77
AFM_thumbs/ToolTip.py Executable file
View File

@@ -0,0 +1,77 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
# This class implements Tooltips for Tkinter
# Original source: http://www.voidspace.org.uk/python/weblog/arch_d7_2006_07_01.shtml
from tkinter import *
class ToolTip(object):
def __init__(self, widget):
self.widget = widget
self.tipwindow = None
self.id = None
self.x = self.y = 0
def showtip(self, text):
"Display text in tooltip window"
self.text = text
if self.tipwindow or not self.text:
return
x, y, cx, cy = self.widget.bbox("insert")
x = x + self.widget.winfo_rootx() + 27
y = y + cy + self.widget.winfo_rooty() +27
self.tipwindow = tw = Toplevel(self.widget)
tw.wm_overrideredirect(1)
tw.wm_geometry("+%d+%d" % (x, y))
try:
# For Mac OS
tw.tk.call("::tk::unsupported::MacWindowStyle",
"style", tw._w,
"help", "noActivates")
except TclError:
pass
label = Label(tw, text=self.text, justify=LEFT,
background="#ffffe0", relief=SOLID, borderwidth=1,
font=("tahoma", "8", "normal"))
label.pack(ipadx=1)
def hidetip(self):
tw = self.tipwindow
self.tipwindow = None
if tw:
tw.destroy()
def create_tool_tip(widget, text):
toolTip = ToolTip(widget)
def enter(event):
toolTip.showtip(text)
def leave(event):
toolTip.hidetip()
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)
widget.bind('<Button-1>', leave)

BIN
AFM_thumbs/ToolTip.pyc Executable file

Binary file not shown.

648
AFM_thumbs/Variables.py Executable file
View File

@@ -0,0 +1,648 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
#
#
# __________ Change the name and path of the config file ___________ from here
#
#
#
globvar_configfile = "Config_AFM_thumbs.conf"
globvar_configfile_path = "./AFM_thumbs/"
# Example for Linux
# globvar_configfile_path = "/home/user/bin/AFM_thumbs/"
# globvar_configfile = "Config_AFM_thumbs.conf"
#
# Example for Windows
# globvar_configfile_path = "C:\Users\Username\Desktop\AFmThumbnails\" \
# "AFM_thumbs"
# globvar_configfile = "Config_AFM_thumbs.conf"
#
#
#
# _____________________________________________________________________ to here
#
#
#
# ____________________________________________________________ Global variables
# DO NOT CHANGE ANYTHING BELOW, OTHERWISE YOU KNOW WHAT TO DO !
import time
globvar_contributions = "Reinhard Olbrich (testing)\n" \
"Matthias Temmen (testing)\n" \
"Alexander v Schmidtsfeld (testing)\n" \
"..."
globvar_year = "2022-03-02"
globvar_version = "3.001"
globvar_spaces = " "
globvar_name = "AFM thumbs v" + globvar_version
globvar_bar_title = (globvar_name + " - " +
globvar_year)
globvar_note = ("Version " + globvar_version + " (" +
globvar_year + ")\n"
"www.development.root-1.de\n\n" +
"Coordinated by:\n\n" +
"Clemens Barth\n" +
"(barth@root-1.de)\n\n" +
" and\n\n" +
"Niklas Rethmann " +
"(nrethmann@uni-osnabrueck.de)\n\n"+
"Contributions from:\n" +
globvar_contributions)
globvar_console = ("\n\n"+
globvar_spaces +
globvar_name + " - " +
globvar_year + "\n" +
globvar_spaces + "www.root-1.de\n\n" +
globvar_spaces + "Today: " +
time.strftime("%d-%m-%Y") +
", Time: " +
time.strftime("%H:%M:%S"))
globvar_python_directory = "AFM_thumbs"
globvar_default_config = "Config_default.conf"
globvar_thumb_size_x = 5.0
globvar_thumb_size_y = 6.0
globvar_thumb_text_width = 40
globvar_timepassed_1 = ("\n" +
globvar_spaces +
"Overall passed time: ")
globvar_timepassed_2 = "--- %d days --- %d hours --- %d minutes " + \
"--- %0.3f seconds ---\n\n"
# _______________________________________________________________ SPECS Nanonis
SPECS_Nanonis_images_must_exist = ".sxm"
SPECS_Nanonis_spectroscopy_must_exist = ".dat"
# _______________________________________________________________ Omicron SCALA
Omicron_SCALA_must_exist = ".par"
Omicron_SCALA_forward = ".tf"
Omicron_SCALA_backward = ".tb"
# ____________________________________________________________ Nanotec DULCINEA
Nanotec_DULCINEA_must_exist = ".f.top"
Nanotec_DULCINEA_forward = ".f."
Nanotec_DULCINEA_backward = ".b."
Nanotec_DULCINEA_suffix = ["f.top","f.ch4","f.ch5","f.ch6","f.ch7","f.ch8",
"b.top","b.ch4","b.ch5","b.ch6","b.ch7","b.ch8",
".f.1st.Auxfeed", ".f.2nd.Auxfeed",
".b.1st.Auxfeed", ".b.2nd.Auxfeed"]
# _________________________________________________________________________ RHK
RHK_must_exist = [".SM4", ".sm4"]
RHK_all_directions = ["all", "All", "ALL", "A", "a"]
RHK_forward_direction = ["forward", "Forward", "FORWARD", "for",
"For", "FOR", "f", "F"]
RHK_backward_direction = ["backward", "Backward", "BACKWARD",
"back", "Back", "BACK", "b", "B"]
RHK_message_direction = " --- Some RHK files could be detected! ---\n\n" \
"Choose scan direction: (f)orward" \
", (b)ackward, (a)ll: "
# ____________________________________________________________________ Tooltips
# Arrangement
TT_n_col = "Number of images in a column \n\n\
This option lets you specific how \n\
many images have to be in a column \n\n"
TT_n_row = "Number of images in arow \n\n\
This option lets you specific how \n\
many images have to be in a row \n\n"
TT_rms = "Contrast (times rms value) \n\n\
This option lets you specific the \n\
contrast of the images"
TT_res = "Image resolution factor (in percent) \n\n\
This option lets you specific the \n\
resolution of the images"
TT_qual = "Image quality \n\n\
This option lets you specific the \n\
quality of the images"
# Position
TT_size = "Font size \n\n\
This option lets you specific the \n\
font size of the image text"
TT_dx_pos = "dX position (in percent) \n\n\
This option lets you shift the \n\
image text left or right"
TT_dy_pos = "dY position (in percent) \n\n\
This option lets you shift the \n\
image text up or down"
TT_dw = "dWidth of text (in characters) \n\n\
This option lets you specific the \n\
width of the image text."
# Specification
TT_file_ex = "This option lets you specific which \n\
format should be considered"
TT_master_dir = "This option lets you specific which \n\
folders should be considered. \n\
Should only be used together with the \"All sub-directories\" option"
TT_filename = "This option lets you specific which \n\
files should be considered."
# Param
TT_date = "Include date and time \n\
in the image text"
TT_size_nm = "Include size in nanometer \n\
in the image text"
TT_size_px = "Include size in pixel \n\
in the image text"
TT_off = "Include offset in nanometer \n\
in the image text"
TT_vol = "Includes voltage (Volt) \n\
in the image text"
TT_feed = "Includes feedback\n\
in the image text"
TT_loop = "Includes loop gain\n\
in the image text"
TT_speed = "Include acquisition speed in s/line \n\
in the image text"
TT_amp = "Include amplitude\n\
in the image text"
TT_angle = "Include angle in degree \n\
in the image text"
# Other
TT_thumb_before = "Delete thumbs before all \n\n\
With this option enabled, the thumbnail directory \n\
will be deleted before a pdf thumbnail is created."
TT_thumb_after = "Delete thumbs after all \n\n\
With this option enabled, the thumbnail directory \n\
will be deleted after a pdf thumbnail has been created."
TT_extra_dir = "Extra directory \n\n\
Creates extra WSxM and Gwyddion directories. \n\
Two new directories are created in the directory one level above.\n\
The directory structure(s) of the AFM data is(are) conserved."
TT_pdfs = "Replace existing pdfs \n\n\
Existing pdf files are replaced by new ones."
TT_subdirs = "All sub-directories \n\n\
All subdirectories of the selected directory (Button 'Choose directory')\n\
are also considered. The respective pdf files are placed into the\n\
directory one level above."
TT_png = "Create images in png format \n\n\
Change the image format of the thumbnails from jpeg to png."
TT_spektral = " Include spectras \n\n\
With this option images of spectra are included\n\
into the pdf file."
TT_peek = " Set color scale to peek-peek \n\n\
This option permits setting the color scale of the \n\
images to peek-to-peek values."
TT_minimum_on_zero = " Set minimum value on zero \n\n\
This option permits setting the minimum value of \n\
the images onto zero."
TT_Reich = "Reichling Special Options \n\n\
This option triggers the following features: \n\
- Colour for Kelvin images is set to gray \n\
- One df image is inverted"
# _____________________________________________________________________ For all
ID_topography = r"[Tt]op(ograph(y|ie))?|TOP(OGRAPH(Y|IE))?|[Zz]"
ID_amplitude = r"[Aa]mplitude|AMPLITUDE|[Aa]mpl?\.?|AMPL?\.?"
ID_kelvin = r"[Kk]el(vin)?|KEL(VIN)?"
ID_kelvin_err = r"[Ee]rr(or)?|ERR(OR)?|[Ll]1[Xx]|KELVIN_ERR"
ID_df = r"[Dd][Ff]"
ID_df_fil = r"[Ff]iltered|FILTERED"
ID_dissipation = r"[Dd](issipation)?|DISSIPATION|[Dd]amp|DAMP|[Pp][Ll][Ll]"
ID_excitation = r"[Ee]xcitation|EXCITATION"
ID_ext1 = r"[Ee]xt(ernal)?( )?1|[Ee]XT(ERNALl)?( )?1"
ID_ext2 = r"[Ee]xt(ernal)?( )?2|[Ee]XT(ERNALl)?( )?2"
ID_phase = r"[Pp]ha(se)?|PHA(SE)?"
ID_list = [ID_topography, ID_amplitude, ID_kelvin, ID_kelvin_err, ID_df,
ID_df_fil, ID_dissipation, ID_excitation, ID_ext1, ID_ext2,
ID_phase]
ID_abbreviations = {"Topography" : "Z", "filtered df":"df_fil", "Amplitude":"A",
"Dissipation": "D", "Kelvin Error": "KPFM_err",
"Ext 1": "Ext1", "Ext 2": "Ext2", "Excitation": "A_ext",
"Phase": "Phase", "Kelvin": "KPFM", "DF_DIG": "df",
"EXT": "Ext", "EXT1": "Ext1", "EXT2": "Ext2"}
# ______________________________________________________________________ Colors
# Colors: see http://matplotlib.org/examples/color/colormaps_reference.html
# Note that many other colours still exist, pre-defined!
globvar_ttk_Combobox = 10
globvar_color_options = ["Grey", "Red", "Red2", "Blue", "Blue2", "Green",
"ReiGreen", "Yellow", "Gold",
"Orange", "Purples",
"BlueGreen", "GreenBlu",
"BluePurple", "PurpleBlue", "PupleRed", "RedPurple",
"OrangeRed",
"PurpleBlueGreen",
"Gnuplot", "Gnuplot2", "Ocean", "Rainbow",
"Gist_rainbow", "HSV", "Gist_stern", "Jet",
"Hot", "AFMhot", "Bone", "Gist_heat"]
# This red is very nice and also ...
Color_Red = {'red': ((0.0, 0.0, 0.0),
(0.333, 0.6, 0.6),
(0.666, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0))}
# ... this yellow, ...
Color_Yellow = {'red': ((0.0, 0.0, 0.0),
(0.333, 0.7, 0.7),
(0.666, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.333, 0.8, 0.8),
(0.666, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0))}
# ... this blue, ...
Color_Blue = {'red': ((0.0, 0.0, 0.0),
(0.3, 0.0, 0.0),
(0.7, 0.9, 0.9),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.3, 0.0, 0.0),
(0.7, 0.9, 0.9),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.7, 0.9, 0.9),
(1.0, 1.0, 1.0))}
# ... gold and of course ...
Color_Gold = {'red': ((0.0, 0.0, 0.0),
(0.333, 0.545098039216, 0.545098039216),
(0.666, 0.803921568627, 0.803921568627),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.333, 0.458823529412, 0.458823529412),
(0.666, 0.678431372549, 0.678431372549),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0))}
# ... the famous green colour from the Michael Reichling group.
Color_ReiGreen = {'red': ((0.0, 0.0, 0.0),
(0.381166, 0.0, 0.0),
(0.672646, 0.471014, 0.471014),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.381166, 0.381166, 0.381166),
(0.672646, 0.672646, 0.672646),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.381166, 0.0, 0.0),
(0.672646, 0.0, 0.0),
(1.0, 1.0, 1.0))}
Color_list = ["Greys_r", "Reds_r", Color_Red, "Blues_r", Color_Blue, "Greens_r",
Color_ReiGreen, Color_Yellow, Color_Gold,
"Oranges_r", "Purples_r",
"BuGn_r", "GnBu_r",
"BuPu_r", "PuBu_r", "PuRd_r", "RdPu_r",
"OrRd_r",
"PuBuGn_r",
"gnuplot", "gnuplot2", "ocean", "rainbow",
"gist_rainbow", "hsv", "gist_stern", "jet",
"hot", "afmhot", "bone", "gist_heat"]
globvar_color_dict = {name:color for name, color in \
zip(globvar_color_options, Color_list)}
# ___________________________________________________________________ Fonts
globvar_fonts = ['Courier', 'Courier New', 'Arial', 'FreeSans']
globvar_bad_fonts = ['NotoColorEmoji.ttf']
# ___________________________________________________________________ Classes
class CLASSparameters(object):
def __init__(self, row, col, rms, res, font,
thumbs_before, thumbs_after, peek, minimum_on_zero,
png, date, sizenm,
sizepx, offset, voltage, feedback, gain,
speed, ampl, text_block, text_block_height,
text_size, pdfs, text_x, text_y, angle,
extra_direct, extension, masterdir, filename, jpeg,
channel_names, thumbs, line_fit, plane_fit, invert,
colors, geometry_x, geometry_y, spektra):
self.row = row
self.col = col
self.rms = rms
self.res = res
self.font = font
self.thumbs_before = thumbs_before
self.thumbs_after = thumbs_after
self.peek = peek
self.minimum_on_zero = minimum_on_zero
self.png = png
self.date = date
self.sizenm = sizenm
self.sizepx = sizepx
self.offset = offset
self.voltage = voltage
self.feedback = feedback
self.gain = gain
self.speed = speed
self.ampl = ampl
self.text_block = text_block
self.text_block_height = text_block_height
self.text_size = text_size
self.pdfs = pdfs
self.text_x = text_x
self.text_y = text_y
self.angle = angle
self.extra_direct = extra_direct
self.extension = extension
self.masterdir = masterdir
self.filename = filename
self.jpeg = jpeg
self.channel_names = channel_names
self.thumbs = thumbs
self.line_fit = line_fit
self.plane_fit = plane_fit
self.invert = invert
self.colors = colors
self.geometry_x = geometry_x
self.geometry_y = geometry_y
self.spektra = spektra
class CLASSdir(object):
def __init__(self, working_directory, pdf_path,
thumbnail_directory, data_directory_name):
self.working_directory = working_directory
self.pdf_path = pdf_path
self.thumbnail_directory = thumbnail_directory
self.data_directory_name = data_directory_name
class CLASSdata(object):
__slots__ = ('date', 'x_size', 'y_size', 'x_pixel', 'y_pixel',
'x_off', 'y_off',
'voltage', 'measurement_type', 'feedback',
'gain', 'gain_prop', 'gain_int', 'gain_xy',
'gain_signal', 'gain_z',
'speed', 'amplitude', 'angle', 'scan_updown',
'sweep_f0', 'sweep_phase', 'sweep_A_exec', 'sweep_Q',
'NONE',
'datfile', 'channel', 'unit',
'z_average', 'z_calibration', 'z_factor', 'z_offset', 'z_min',
'z_max', 'res_freq', 'z_amplitude',
'scandir', 'spec_x_unit', 'spec_x_label',
'spec_y_unit', 'spec_y_label', 'spec_y_factor',
'spec_points', 'spec_feedback', 'spec_acquisition',
'spec_delay', 'spec_time', 'spec_position', 'spec_files',
'spec_other')
def __init__(self,
date,
x_size,
y_size,
x_pixel,
y_pixel,
x_off,
y_off,
voltage,
measurement_type,
feedback,
gain,
gain_prop,
gain_int,
gain_xy,
gain_signal,
gain_z,
speed,
res_freq,
amplitude,
angle,
scan_updown,
sweep_f0,
sweep_phase,
sweep_A_exec,
sweep_Q,
#
# From here to end: lists
#
NONE,
datfile,
channel,
unit,
z_average,
z_calibration,
z_factor,
z_offset,
z_min,
z_max,
z_amplitude,
scandir,
spec_x_unit,
spec_x_label,
spec_y_unit,
spec_y_label,
spec_y_factor,
spec_points,
spec_feedback,
spec_acquisition,
spec_delay,
spec_time,
spec_position,
spec_files,
spec_other):
self.date = date
self.x_size = x_size
self.y_size = y_size
self.x_pixel = x_pixel
self.y_pixel = y_pixel
self.x_off = x_off
self.y_off = y_off
self.voltage = voltage
self.measurement_type = measurement_type # SPECS Nanonis
self.feedback = feedback # I, df, etc.
self.gain = gain # SCALA
self.gain_prop = gain_prop # DULCINEA
self.gain_int = gain_int # DULCINEA
self.gain_xy = gain_xy # DULCINEA
self.gain_signal = gain_signal # DULCINEA
self.gain_z = gain_z # DULCINEA
self.speed = speed
self.res_freq = res_freq
self.amplitude = amplitude
self.angle = angle
self.scan_updown = scan_updown # SPECS Nanonis
self.sweep_f0 = sweep_f0 # SPECS Nanonis
self.sweep_phase = sweep_phase # SPECS Nanonis
self.sweep_A_exec = sweep_A_exec # SPECS Nanonis
self.sweep_Q = sweep_Q # SPECS Nanonis
self.NONE = NONE # This is a dummy ...
#
# From here to end: lists
#
self.datfile = datfile
self.channel = channel
self.unit = unit
self.z_average = z_average # float, is set during runtime
self.z_calibration = z_calibration
self.z_factor = z_factor # DULCINEA, not used
self.z_offset = z_offset # SPECS Nanonis
self.z_amplitude = z_amplitude
self.z_min = z_min # DULCINEA, not used
self.z_max = z_max # DULCINEA, not used
self.scandir = scandir
self.spec_x_unit = spec_x_unit
self.spec_x_label = spec_x_label
self.spec_y_unit = spec_y_unit
self.spec_y_label = spec_y_label
self.spec_y_factor = spec_y_factor
self.spec_points = spec_points
self.spec_feedback = spec_feedback
self.spec_acquisition = spec_acquisition
self.spec_delay = spec_delay
self.spec_time = spec_time
self.spec_position = spec_position
self.spec_files = spec_files
self.spec_other = spec_other # This can be used for any properties.
class CLASSLinalg(object):
__slots__ = ('plane_M512', 'plane_M1024',
'plane_x_vec512', 'plane_y_vec512',
'plane_x_vec1024', 'plane_y_vec1024',
'line_M512', 'line_M1024',
'line_x_vec512', 'line_x_vec1024')
def __init__(self, plane_M512, plane_M1024,
plane_x_vec512, plane_y_vec512,
plane_x_vec1024, plane_y_vec1024,
line_M512, line_M1024,
line_x_vec512,line_x_vec1024):
self.plane_M512 = plane_M512
self.plane_M1024 = plane_M1024
self.plane_x_vec512 = plane_x_vec512
self.plane_y_vec512 = plane_y_vec512
self.plane_x_vec1024 = plane_x_vec1024
self.plane_y_vec1024 = plane_y_vec1024
self.line_M512 = line_M512
self.line_M1024 = line_M1024
self.line_x_vec512 = line_x_vec512
self.line_x_vec1024 = line_x_vec1024
# The next 2 classes are used specifically for the RHK routine.
class CLASSRHK_position_counter(object):
def __init__(self, position):
self.position = position
def add(self):
self.position += 1
class CLASSRHK_direction_request(object):
def __init__(self, direction = all):
self.direction = direction
class CLASSRHK_true(object):
def __init__(self, true = False):
self.true = true
globvar_LINALG = CLASSLinalg(None,None,None,None,None,None,None,None,None,None)
# The global variables 'globvar_AFMdata' and 'globvar_ThumbPara' are created!
globvar_AFMdata = CLASSdata(None,None,None,None,None,None,None,None,None,None,
None,None,None,None,None,None,None,None,None,None,
None,None,None,None,None,None,
[],[],[], None, [],[],[],[],[],[],[],
[],[],[],[],[],[],[],[], [], [], [], [], None)
globvar_AFMdir = CLASSdir(None,None,None,None)
globvar_ThumbPara = CLASSparameters(None, None, None, None, None,
False, False, False, False, False, False,
False, False, False, False, False,
False, False, False,
0, 0, 0, False, 0, 0, False,
False, None, None, None, 0,
[], [], [], [], [], [],
[], [], None)
# For RHK
RHK_PositionCounter = CLASSRHK_position_counter(None)
RHK_special = CLASSRHK_true(False)

BIN
AFM_thumbs/Variables.pyc Executable file

Binary file not shown.

568
AFM_thumbs/Variables.py~ Executable file
View File

@@ -0,0 +1,568 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#
#
#
# __________ Change the name and path of the config file ___________ from here
#
#
#
globvar_configfile = "Config_AFM_thumbs.conf"
globvar_configfile_path = "./AFM_thumbs/"
"""
Example for Linux
globvar_configfile_path = "/home/user/bin/AFM_thumbs/"
globvar_configfile = "Config_AFM_thumbs.conf"
Example for Windows
globvar_configfile_path = "C:\Users\Username\Desktop\AFmThumbnails\" \
"AFM_thumbs"
globvar_configfile = "Config_AFM_thumbs.conf"
"""
#
#
#
# _____________________________________________________________________ to here
#
#
#
# ____________________________________________________________ Global variables
# DO NOT CHANGE ANYTHING BELOW, OTHERWISE YOU KNOW WHAT TO DO !
import time
globvar_year = "2016-01-15"
globvar_version = "2.2"
globvar_spaces = " "
globvar_name = "AFM thumbs v" + globvar_version
globvar_bar_title = (globvar_name + " " +
globvar_year)
globvar_note = ("Coordinated by:\n\nClemens Barth\n" +
"(barth@root-1.de)\n\n" +
" and\n\n" +
"Niklas Rethmann (nrethmann@uni-osnabrueck.de)\n\n"+
globvar_year + "\n\n"
"www.root-1.de")
globvar_console = ("\n\n"+
globvar_spaces +
globvar_name +
"" +
globvar_year + "\n" +
globvar_spaces + "www.root-1.de\n" +
globvar_spaces + "Date: " +
time.strftime("%d-%m-%Y") +
", Time: " +
time.strftime("%H:%M:%S"))
globvar_python_directory = "AFM_thumbs"
globvar_default_config = "Config_default.conf"
globvar_thumb_size_x = 5.0
globvar_thumb_size_y = 5.0
globvar_thumb_text_width = 50
globvar_timepassed_1 = ("\n" +
globvar_spaces +
"Overall passed time: ")
globvar_timepassed_2 = "--- %d days --- %d hours --- %d minutes " + \
"--- %0.3f seconds ---\n\n"
# _______________________________________________________________ Omicron SCALA
Omicron_SCALA_must_exist = ".par"
Omicron_SCALA_forward = ".tf"
Omicron_SCALA_backward = ".tb"
# ____________________________________________________________ Nanotec DULCINEA
Nanotec_DULCINEA_must_exist = ".f.top"
Nanotec_DULCINEA_forward = ".f."
Nanotec_DULCINEA_backward = ".b."
Nanotec_DULCINEA_suffix = ["f.top","f.ch4","f.ch5","f.ch6","f.ch7","f.ch8",
"b.top","b.ch4","b.ch5","b.ch6","b.ch7","b.ch8",
".f.1st.Auxfeed", ".f.2nd.Auxfeed",
".b.1st.Auxfeed", ".b.2nd.Auxfeed"]
# _________________________________________________________________________ RHK
RHK_must_exist = [".SM4", ".sm4"]
RHK_all_directions = ["all", "All", "ALL", "A", "a"]
RHK_forward_direction = ["forward", "Forward", "FORWARD", "for",
"For", "FOR", "f", "F"]
RHK_backward_direction = ["backward", "Backward", "BACKWARD",
"back", "Back", "BACK", "b", "B"]
RHK_message_direction = " --- Some RHK files could be detected! ---\n\n" \
"Choose scan direction: (f)orward" \
", (b)ackward, (a)ll: "
# ____________________________________________________________________ Tooltips
# Arrangement
TT_n_col = "Number of images in a column \n\n\
This option lets you specific how \n\
many images have to be in a column \n\n"
TT_n_row = "Number of images in arow \n\n\
This option lets you specific how \n\
many images have to be in a row \n\n"
TT_rms = "Contrast (times rms value) \n\n\
This option lets you specific the \n\
contrast of the images"
TT_res = "Image resolution factor (in percent) \n\n\
This option lets you specific the \n\
resolution of the images"
TT_qual = "Image quality \n\n\
This option lets you specific the \n\
quality of the images"
# Position
TT_size = "Font size \n\n\
This option lets you specific the \n\
font size of the image text"
TT_dx_pos = "dX position (in percent) \n\n\
This option lets you shift the \n\
image text left or right"
TT_dy_pos = "dY position (in percent) \n\n\
This option lets you shift the \n\
image text up or down"
TT_dw = "dWidth of text (in characters) \n\n\
This option lets you specific the \n\
width of the image text."
# Specification
TT_file_ex = "This option lets you specific which \n\
format should be considered"
TT_master_dir = "This option lets you specific which \n\
folders should be considered. \n\
Should only be used together with the \"All sub-directories\" option"
TT_filename = "This option lets you specific which \n\
files should be considered."
# Param
TT_date = "Include date and time \n\
in the image text"
TT_size_nm = "Include size in nanometer \n\
in the image text"
TT_size_px = "Include size in pixel \n\
in the image text"
TT_off = "Include offset in nanometer \n\
in the image text"
TT_vol = "Includes voltage (Volt) \n\
in the image text"
TT_feed = "Includes feedback\n\
in the image text"
TT_loop = "Includes loop gain\n\
in the image text"
TT_speed = "Include acquisition speed in s/line \n\
in the image text"
TT_amp = "Include amplitude\n\
in the image text"
TT_angle = "Include angle in degree \n\
in the image text"
# Other
TT_thumb_before = "Delete thumbs before all \n\n\
With this option enabled, the thumbnail directory \n\
will be deleted before a pdf thumbnail is created."
TT_thumb_after = "Delete thumbs after all \n\n\
With this option enabled, the thumbnail directory \n\
will be deleted after a pdf thumbnail has been created."
TT_extra_dir = "Extra directory \n\n\
Creates extra WSxM and Gwyddion directories. \n\
Two new directories are created in the directory one level above.\n\
The directory structure(s) of the AFM data is(are) conserved."
TT_pdfs = "Replace existing pdfs \n\n\
Existing pdf files are replaced by new ones."
TT_subdirs = "All sub-directories \n\n\
All subdirectories of the selected directory (Button 'Choose directory')\n\
are also considered. The respective pdf files are placed into the\n\
directory one level above."
TT_png = "Create images in png format \n\n\
Change the image format of the thumbnails from jpeg to png."
TT_spektral = " Include spectras \n\n\
With this option images of spectra are included\n\
into the pdf file."
TT_peek = " Set color scale to peek-peek \n\n\
This option permits setting the color scale of the \n\
images to peek-to-peek values."
TT_minimum_on_zero = " Set minimum value on zero \n\n\
This option permits setting the minimum value of \n\
the images onto zero."
TT_Reich = "Reichling Special Options \n\n\
This option triggers the following features: \n\
- Colour for Kelvin images is set to gray \n\
- One df image is inverted"
# _____________________________________________________________________ For all
ID_topography = r"[Tt]op(ograph(y|ie))?|TOP(OGRAPH(Y|IE))?|[Zz]"
ID_amplitude = r"[Aa]mplitude|AMPLITUDE|[Aa]mpl?\.?|AMPL?\.?"
ID_kelvin = r"[Kk]el(vin)?|KEL(VIN)?"
ID_kelvin_err = r"[Ee]rr(or)?|ERR(OR)?|[Ll]1[Xx]"
ID_df = r"[Dd][Ff]"
ID_df_fil = r"[Ff]iltered|FILTERED"
ID_dissipation = r"[Dd](issipation)?|DISSIPATION|[Dd]amp|DAMP|[Pp][Ll][Ll]"
ID_excitation = r"[Ee]xcitation|EXCITATION"
ID_ext1 = r"[Ee]xt(ernal)?( )?1|[Ee]XT(ERNALl)?( )?1"
ID_ext2 = r"[Ee]xt(ernal)?( )?2|[Ee]XT(ERNALl)?( )?2"
ID_phase = r"[Pp]ha(se)?|PHA(SE)?"
ID_list = [ID_topography, ID_amplitude, ID_kelvin, ID_kelvin_err, ID_df,
ID_df_fil, ID_dissipation, ID_excitation, ID_ext1, ID_ext2, ID_phase]
ID_abbreviations = {"Topography" : "Z", "filtered df":"df_fil", "Amplitude":"A",
"Dissipation": "D", "Kelvin Error": "KPFM_err",
"Ext 1": "Ext1", "Ext 2": "Ext2", "Excitation": "A_ext",
"Phase": "Phase", "Kelvin": "KPFM", "DF_DIG": "df",
"EXT": "Ext", "EXT1": "Ext1", "EXT2": "Ext2"}
# ______________________________________________________________________ Colors
# Colors: see http://matplotlib.org/examples/color/colormaps_reference.html
# Note that many other colours still exist, pre-defined!
globvar_ttk_Combobox = 10
globvar_color_options = ["Grey", "Red", "Red2", "Blue", "Blue2", "Green",
"ReiGreen", "Yellow", "Gold",
"Orange", "Purples",
"BlueGreen", "GreenBlu",
"BluePurple", "PurpleBlue", "PupleRed", "RedPurple",
"OrangeRed",
"PurpleBlueGreen",
"Gnuplot", "Gnuplot2", "Ocean", "Rainbow",
"Gist_rainbow", "HSV", "Gist_stern", "Jet",
"Hot", "AFMhot", "Bone", "Gist_heat"]
# This red is very nice and also ...
Color_Red = {'red': ((0.0, 0.0, 0.0),
(0.333, 0.6, 0.6),
(0.666, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0))}
# ... this yellow, ...
Color_Yellow = {'red': ((0.0, 0.0, 0.0),
(0.333, 0.7, 0.7),
(0.666, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.333, 0.8, 0.8),
(0.666, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0))}
# ... this blue, ...
Color_Blue = {'red': ((0.0, 0.0, 0.0),
(0.3, 0.0, 0.0),
(0.7, 0.9, 0.9),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.3, 0.0, 0.0),
(0.7, 0.9, 0.9),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.7, 0.9, 0.9),
(1.0, 1.0, 1.0))}
# ... gold and of course ...
Color_Gold = {'red': ((0.0, 0.0, 0.0),
(0.333, 0.545098039216, 0.545098039216),
(0.666, 0.803921568627, 0.803921568627),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.333, 0.458823529412, 0.458823529412),
(0.666, 0.678431372549, 0.678431372549),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.666, 0.0, 0.0),
(1.0, 1.0, 1.0))}
# ... the green colour from the Michael Reichling group.
Color_ReiGreen = {'red': ((0.0, 0.0, 0.0),
(0.381166, 0.0, 0.0),
(0.672646, 0.471014, 0.471014),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.381166, 0.381166, 0.381166),
(0.672646, 0.672646, 0.672646),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(0.381166, 0.0, 0.0),
(0.672646, 0.0, 0.0),
(1.0, 1.0, 1.0))}
Color_list = ["Greys_r", "Reds_r", Color_Red, "Blues_r", Color_Blue, "Greens_r",
Color_ReiGreen, Color_Yellow, Color_Gold,
"Oranges_r", "Purples_r",
"BuGn_r", "GnBu_r",
"BuPu_r", "PuBu_r", "PuRd_r", "RdPu_r",
"OrRd_r",
"PuBuGn_r",
"gnuplot", "gnuplot2", "ocean", "rainbow",
"gist_rainbow", "hsv", "gist_stern", "jet",
"hot", "afmhot", "bone", "gist_heat"]
globvar_color_dict = {name:color for name, color in \
zip(globvar_color_options, Color_list)}
# ___________________________________________________________________ Fonts
globvar_fonts = ['Courier', 'Courier New', 'Arial', 'FreeSans']
# ___________________________________________________________________ Classes
class CLASSparameters(object):
def __init__(self, row, col, rms, res, font,
thumbs_before, thumbs_after, peek, minimum_on_zero,
png, date, sizenm,
sizepx, offset, voltage, feedback, gain,
speed, ampl, text_block, text_block_height,
text_size, pdfs, text_x, text_y, angle,
extra_direct, extension, masterdir, filename, jpeg,
channel_names, thumbs, line_fit, plane_fit, invert,
colors, geometry_x, geometry_y, spektra):
self.row = row
self.col = col
self.rms = rms
self.res = res
self.font = font
self.thumbs_before = thumbs_before
self.thumbs_after = thumbs_after
self.peek = peek
self.minimum_on_zero = minimum_on_zero
self.png = png
self.date = date
self.sizenm = sizenm
self.sizepx = sizepx
self.offset = offset
self.voltage = voltage
self.feedback = feedback
self.gain = gain
self.speed = speed
self.ampl = ampl
self.text_block = text_block
self.text_block_height = text_block_height
self.text_size = text_size
self.pdfs = pdfs
self.text_x = text_x
self.text_y = text_y
self.angle = angle
self.extra_direct = extra_direct
self.extension = extension
self.masterdir = masterdir
self.filename = filename
self.jpeg = jpeg
self.channel_names = channel_names
self.thumbs = thumbs
self.line_fit = line_fit
self.plane_fit = plane_fit
self.invert = invert
self.colors = colors
self.geometry_x = geometry_x
self.geometry_y = geometry_y
self.spektra = spektra
class CLASSdir(object):
def __init__(self, working_directory, pdf_path,
thumbnail_directory, data_directory_name):
self.working_directory = working_directory
self.pdf_path = pdf_path
self.thumbnail_directory = thumbnail_directory
self.data_directory_name = data_directory_name
class CLASSdata(object):
__slots__ = ('date', 'x_size', 'y_size', 'x_pixel', 'y_pixel',
'x_off', 'y_off',
'voltage', 'feedback',
'gain', 'gain_prop', 'gain_int', 'gain_xy',
'gain_signal', 'gain_z',
'speed', 'amplitude', 'angle', 'NONE',
'datfile', 'channel', 'unit',
'z_average', 'z_calibration', 'z_factor', 'z_min',
'z_max', 'z_amplitude',
'scandir', 'spec_x_unit', 'spec_x_label',
'spec_y_unit', 'spec_y_label', 'spec_y_factor',
'spec_points', 'spec_feedback', 'spec_acquisition',
'spec_delay')
def __init__(self, date, x_size, y_size, x_pixel, y_pixel, x_off, y_off,
voltage, feedback,
gain, gain_prop, gain_int, gain_xy, gain_signal, gain_z,
speed, amplitude, angle, NONE,
datfile, channel, unit,
z_average, z_calibration, z_factor, z_min, z_max, z_amplitude,
scandir, spec_x_unit, spec_x_label,
spec_y_unit, spec_y_label, spec_y_factor,
spec_points, spec_feedback, spec_acquisition, spec_delay):
self.date = date
self.x_size = x_size
self.y_size = y_size
self.x_pixel = x_pixel
self.y_pixel = y_pixel
self.x_off = x_off
self.y_off = y_off
self.voltage = voltage
self.feedback = feedback
self.gain = gain # SCALA
self.gain_prop = gain_prop # DULCINEA
self.gain_int = gain_int # DULCINEA
self.gain_xy = gain_xy # DULCINEA
self.gain_signal = gain_signal # DULCINEA
self.gain_z = gain_z # DULCINEA
self.speed = speed
self.amplitude = amplitude
self.angle = angle
self.NONE = NONE # This is a dummy ...
# From here to end: lists
self.datfile = datfile
self.channel = channel
self.unit = unit
self.z_average = z_average # float, is determined during runtime
self.z_calibration = z_calibration
self.z_factor = z_factor # DULCINEA, not used so far
self.z_amplitude = z_amplitude
self.z_min = z_min # DULCINEA, not used so far
self.z_max = z_max # DULCINEA, not used so far
self.scandir = scandir
self.spec_x_unit = spec_x_unit
self.spec_x_label = spec_x_label
self.spec_y_unit = spec_y_unit
self.spec_y_label = spec_y_label
self.spec_y_factor = spec_y_factor
self.spec_points = spec_points
self.spec_feedback = spec_feedback
self.spec_acquisition = spec_acquisition
self.spec_delay = spec_delay
class CLASSLinalg(object):
__slots__ = ('plane_M512', 'plane_M1024',
'plane_x_vec512', 'plane_y_vec512',
'plane_x_vec1024', 'plane_y_vec1024',
'line_M512', 'line_M1024',
'line_x_vec512', 'line_x_vec1024')
def __init__(self, plane_M512, plane_M1024,
plane_x_vec512, plane_y_vec512,
plane_x_vec1024, plane_y_vec1024,
line_M512, line_M1024,
line_x_vec512,line_x_vec1024):
self.plane_M512 = plane_M512
self.plane_M1024 = plane_M1024
self.plane_x_vec512 = plane_x_vec512
self.plane_y_vec512 = plane_y_vec512
self.plane_x_vec1024 = plane_x_vec1024
self.plane_y_vec1024 = plane_y_vec1024
self.line_M512 = line_M512
self.line_M1024 = line_M1024
self.line_x_vec512 = line_x_vec512
self.line_x_vec1024 = line_x_vec1024
# The next 2 classes are used specifically for the RHK routine.
class CLASSRHK_position_counter(object):
def __init__(self, position):
self.position = position
def add(self):
self.position += 1
class CLASSRHK_direction_request(object):
def __init__(self, direction = all):
self.direction = direction
class CLASSRHK_true(object):
def __init__(self, true = False):
self.true = true
globvar_LINALG = CLASSLinalg(None,None,None,None,None,None,None,None,None,None)
globvar_AFMdata = CLASSdata(None,None,None,None,None,None,None,None,None,None,
None,None,None,None,None,None,None,None, None,
[],[],[], None, [],[],[],[],[],[],[],
[],[],[],[],[],[],[],[])
globvar_AFMdir = CLASSdir(None,None,None,None)
globvar_ThumbPara = CLASSparameters(None, None, None, None, None,
False, False, False, False, False, False,
False, False, False, False, False,
False, False, False,
0, 0, 0, False, 0, 0, False,
False, None, None, None, 0,
[], [], [], [], [], [],
[], [], None)
# For RHK
RHK_PositionCounter = CLASSRHK_position_counter(None)
RHK_special = CLASSRHK_true(False)

25
AFM_thumbs/__init__.py Executable file
View File

@@ -0,0 +1,25 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# This is part of the python program 'AFM_thumbs'. Please, read the
# full licence text and other comments in the file 'AFM_thumbs.py'
#
# Dr. Clemens Barth (barth@root-1.de), project manager.
#
# DO NOT REMOVE THIS PREAMBLE !!!
#

BIN
AFM_thumbs/__init__.pyc Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
AFM_thumbs_Icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

48
Config_AFM_thumbs_noline.log Executable file
View File

@@ -0,0 +1,48 @@
AFM thumbs v2.4 - 2021-02-05
www.root-1.de
Today: 05-02-2021, Time: 14:36:10
Attention: The config file
./Config_AFM_thumbs_noline.conf
does not exist!
The default config file 'AFM_thumbs/Config_default.conf' is now used!
If you have your own config file, put in the correct file name and path
in 'AFM_thumbs/Variables.py' => 'globvar_configfile' and 'globvar_configfile_path'
Config file: /media/cle/Daten/Data/X -- 2021/Programming/Python_AFM_thumbs/AFM_thumbs/Aktuelle_version/AFM_thumbs/Config_default.conf
Directories that will be considered:
/media/cle/Daten/Data/X -- 2021/rawdata/NANONIS/X -- session_demo/2021-01-18
/media/cle/Daten/Data/X -- 2021/rawdata/NANONIS/X -- session_demo/Session_first_time_test
/media/cle/Daten/Data/X -- 2021/rawdata/NANONIS/sessions_Ag001/2021-02-03_cycle_13
/media/cle/Daten/Data/X -- 2021/rawdata/NANONIS/sessions_Ceria/2021-02-01_ceria_10min_550C_10min_1
/media/cle/Daten/Data/X -- 2021/rawdata/NANONIS/sessions_Cu111/2021-01-14_sputtering_cycle_48_b
I'm working in the directory
/media/cle/Daten/Data/X -- 2021/rawdata/NANONIS/X -- session_demo/2021-01-18
right now ...
... SPECS Nanonis spectras are stored as thumbs ...
... SPECS Nanonis images are stored as thumbs ...
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift
Channel not found: OC_M1_Freq._Shift

View File

@@ -0,0 +1,7 @@
[Desktop Entry]
Type=Application
Terminal=true
Name=AFM_thumbs
Icon=/home/<username>/bin/AFM_thumbs/AFM_thumbs_icon.png
Exec=/usr/bin/python /home/<username>/bin/AFM_thumbs/AFM_thumbs.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

View File

@@ -0,0 +1,35 @@
@echo off & setlocal
:: Source: http://www.administrator.de/forum/verkn%C3%BCpfung-auf-desktop-per-batch-anlegen-155061.html
:: Zielpfad
set "zielpfad=%userprofile%\Desktop"
::Name der Verknüpfung (ohne ".lnk")
set "progtitel=AFM_thumbs Starter"
::Speicherort der Programmdatei (wird auch für "Ausführen in:" verwendet)
set "progdir=%cd%"
set "progexe=Windows Batch Starter.bat"
::Kommentar
set "beschreibung=Run AFM_thumbs.py"
::Icon
set "iconpath=%progdir%\AFM_thumbs Icon.ico"
::Bei Bedarf Ordner erstellen:
md "%zielpfad%" 2>nul
md "%progdir%" 2>nul
::temporäres VBScript erzeugen ...
>%temp%\MakeShortCut.vbs echo Set objShell=WScript.CreateObject("Wscript.Shell")
>>%temp%\MakeShortCut.vbs echo Set objShortcut=objShell.CreateShortcut("%zielpfad%\%progtitel%.lnk")
>>%temp%\MakeShortCut.vbs echo objShortcut.TargetPath="%progdir%\%progexe%"
>>%temp%\MakeShortCut.vbs echo objShortcut.Description="%beschreibung%"
>>%temp%\MakeShortCut.vbs echo objShortcut.WorkingDirectory="%progdir%"
>>%temp%\MakeShortCut.vbs echo objShortcut.IconLocation = "C:\Users\Niklas\Documents\Python Scripts\AFM_thumbs_v1.7x_04.10.14\AFM_thumbs Icon.ico"
>>%temp%\MakeShortCut.vbs echo objShortcut.Save
::... ausführen ...
cscript //nologo %temp%\MakeShortCut.vbs
::... und wieder löschen.
del %temp%\MakeShortCut.vbs

View File

@@ -0,0 +1,3 @@
@echo off
cmd /C "python AFM_thumbs.py"