From f17e4e3630b8596a29c67a60fd9442bdf687732c Mon Sep 17 00:00:00 2001
From: "markus.kuehbach" <markus.kuehbach@hu-berlin.de>
Date: Mon, 17 Apr 2023 17:14:50 +0200
Subject: [PATCH 1/4] Updated apmtools container with APTyzer,
 paraprobe-toolbox v0.4, and new tool APAV

---
 docker/apmtools/APT_analyzer.ipynb | 1214 ----------------------------
 docker/apmtools/Cheatsheet.ipynb   |  332 ++++++--
 docker/apmtools/Dockerfile         |  214 ++---
 docker/apmtools/FAIRmatNewLogo.png |  Bin 0 -> 24588 bytes
 docker/apmtools/FAIRmat_S.png      |  Bin 6890 -> 0 bytes
 docker/apmtools/NOMADOasisLogo.png |  Bin 0 -> 12991 bytes
 tools.json                         |    8 +-
 7 files changed, 351 insertions(+), 1417 deletions(-)
 delete mode 100644 docker/apmtools/APT_analyzer.ipynb
 create mode 100644 docker/apmtools/FAIRmatNewLogo.png
 delete mode 100644 docker/apmtools/FAIRmat_S.png
 create mode 100644 docker/apmtools/NOMADOasisLogo.png

diff --git a/docker/apmtools/APT_analyzer.ipynb b/docker/apmtools/APT_analyzer.ipynb
deleted file mode 100644
index a329a8d..0000000
--- a/docker/apmtools/APT_analyzer.ipynb
+++ /dev/null
@@ -1,1214 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "c15820a3",
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [],
-   "source": [
-    "%reset -f\n",
-    "from tkinter import *\n",
-    "from tkinter.ttk import Combobox\n",
-    "from tkinter import messagebox\n",
-    "from tkinter import filedialog\n",
-    "import matplotlib.pyplot as plt\n",
-    "from matplotlib.figure import Figure\n",
-    "from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)\n",
-    "import numpy as np\n",
-    "import apt_importers as apt\n",
-    "import math\n",
-    "from matplotlib import gridspec\n",
-    "import re\n",
-    "from tkinter.filedialog import asksaveasfile\n",
-    "import tkinter.scrolledtext as tkst\n",
-    "import webbrowser\n",
-    "from mpl_toolkits.mplot3d import proj3d\n",
-    "import pandas as pd\n",
-    "import h5py\n",
-    "\n",
-    "def data_for_cylinder_along_z(center_x,center_y,center_z,radius,height_z):\n",
-    "    z = np.linspace(center_z-height_z/2, center_z+height_z/2, 50)\n",
-    "    theta = np.linspace(0, 2*np.pi, 50)\n",
-    "    theta_grid, z_grid=np.meshgrid(theta, z)\n",
-    "    x_grid = radius*np.cos(theta_grid) + center_x\n",
-    "    y_grid = radius*np.sin(theta_grid) + center_y\n",
-    "    return x_grid,y_grid,z_grid\n",
-    "\n",
-    "def gerade(k,x,d):\n",
-    "    return k*x+d\n",
-    "\n",
-    "class APT_analyzer():                                                          # define class object \n",
-    "    def __init__(self,tk):                                                     # initialize when starting tkinter\n",
-    "        self.plot_exist=0\n",
-    "        self.conc_check=0\n",
-    "        self.excess_check=0\n",
-    "        self.invert=0\n",
-    "        self.data_color=['blue','red','green','yellow','purple','black','white','grey','brown'] # colors of cylinder to be seletected\n",
-    "        self.color_cp=['blue','red','green','yellow','purple','black','white','grey','brown']\n",
-    "        self.frame=Frame(tk)                                                   # setting up frame\n",
-    "        self.frame.pack(expand=True,fill=BOTH)                                 # placing frame\n",
-    "        self.canvas_all=Canvas(self.frame,width=1400,height=800,scrollregion=(0,0,1550,850))     #setting up canvas onto frame\n",
-    "        ################# scroll bars vertical and horizontal  ################\n",
-    "        self.hbar=Scrollbar(self.frame,orient=HORIZONTAL)                      # setting up horizontal scrollbar\n",
-    "        self.hbar.pack(side=TOP,fill=X)                                        # placing horizontal scrollbar on the top side\n",
-    "        self.hbar.config(command=self.canvas_all.xview)                        # configurating horizontal scrollbar\n",
-    "        self.vbar=Scrollbar(self.frame,orient=VERTICAL)                        # setting up vertical scrollbar\n",
-    "        self.vbar.pack(side=LEFT,fill=Y)                                       # placing vertical scrollbar on the left side\n",
-    "        self.vbar.config(command=self.canvas_all.yview)                        # configurating vertical scrollbar\n",
-    "        self.canvas_all.config(yscrollcommand=self.vbar.set,xscrollcommand=self.hbar.set)       #configurating canvas\n",
-    "        \n",
-    "\n",
-    "        self.b_page1_loading = Button(self.canvas_all, text=\"1. Load\", command=self.page_1,font=('helvetica',12,'bold')) # button for tip calculation\n",
-    "        self.canvas_all.create_window(75,20,window=self.b_page1_loading)\n",
-    "        \n",
-    "        self.b_page2_visualize = Button(self.canvas_all, text=\"2. Visualize\", command=self.page_2,font=('helvetica',12,'bold')) # button for tip calculation\n",
-    "        self.canvas_all.create_window(180,20,window=self.b_page2_visualize)\n",
-    "        \n",
-    "        self.b_page3_cylinder = Button(self.canvas_all, text=\"3. Calculate\", command=self.page_3,font=('helvetica',12,'bold')) # button for tip calculation\n",
-    "        self.canvas_all.create_window(300,20,window=self.b_page3_cylinder)\n",
-    "\n",
-    "        ############## initiate values #######################################\n",
-    "        #### page 1 ####  \n",
-    "        self.succ=0\n",
-    "        self.utext0=Label(self.canvas_all,text='Welcome to the APT-analyzer!')    # title of segment\n",
-    "        self.utext1=Label(self.canvas_all,text='This open source tool enables you to look at and analyze APT tips ')    # title of segment\n",
-    "        self.utext2=Label(self.canvas_all,text='All you need is a .pos (or .epos) file and a .rrng file')    # title of segment\n",
-    "        self.utext3=Label(self.canvas_all,text='Select the files you want to look at below and press \"Load files\"')    # title of segment\n",
-    "        self.utext4=Label(self.canvas_all,text='------------- Initiate files --------------')    # title of segment\n",
-    "        self.b_pos_file = Button(self.canvas_all,bg='green',fg='white', text=\"Select .pos /.epos file\", command=self.search_pos)        # button for pos file initiation\n",
-    "        self.b_rrng_file = Button(self.canvas_all,bg='green',fg='white', text=\"Select .rrng file\", command=self.search_rrng)             # button for rrng file initiation\n",
-    "        self.b_calc_tip = Button(self.canvas_all, text=\"Load files\", command=self.calculate_tip,bg='blue',fg='white',font=('helvetica',14,'bold')) # button for tip calculation\n",
-    "        self.dtext0=Label(self.canvas_all,text='The loading of the files may take some time.')    # title of segment\n",
-    "        self.dtext1=Label(self.canvas_all,text='When \"Sucessfully loaded files!\" appears underneath the Load button')    # title of segment\n",
-    "        self.dtext2=Label(self.canvas_all,text='then everthing is working as intendet')    # title of segment\n",
-    "        self.dtext3=Label(self.canvas_all,text='and a preview image of the tip should appear on the right')    # title of segment   \n",
-    "        self.dtext4=Label(self.canvas_all,text='You may now go to section 2.Visualize (top middle)')    # title of segment\n",
-    "        self.dtext5=Label(self.canvas_all,text='where you have more options for the visalization')    # title of segment\n",
-    "        self.dtext6=Label(self.canvas_all,text='as well as the ability to set control points and print them')    # title of segment\n",
-    "        self.dtext7=Label(self.canvas_all,text='After that you can go to section 3.Calculate (top right)')    # title of segment\n",
-    "        self.dtext8=Label(self.canvas_all,text='To calculate the concentration profile and excess profile')    # title of segment\n",
-    "        self.dtext9=Label(self.canvas_all,text='of a cylinder area which you can select within the tip')    # title of segment\n",
-    "        self.label_help=Label(self.canvas_all,text='if you need help press this button:')    # title of segment\n",
-    "        self.b_help = Button(self.canvas_all, text=\"help\",bg='orange',fg='black',command=self.help_web,font=('helvetica',14,'bold')) # button for tip calculation\n",
-    "        \n",
-    "        #### page 2 ####\n",
-    "        self.cb_atom = Combobox(tk, values='') \n",
-    "\n",
-    "        self.diss=0\n",
-    "        self.diss2=0\n",
-    "        self.slider_image_size_cv=DoubleVar()\n",
-    "        self.slider_image_size = Scale(self.canvas_all,from_=1,to=5,orient='horizontal',variable=self.slider_image_size_cv,showvalue=0)\n",
-    "        self.label_plot_tip=Label(self.canvas_all,text='------------- plot options ---------------')    # title of segment\n",
-    "        self.label_image_size=Label(self.canvas_all,text='Select image size')                     # label for resolution\n",
-    "        self.label_slider_res=Label(self.canvas_all,text='small')\n",
-    "        self.label_slider_res2=Label(self.canvas_all,text='large')     \n",
-    "        self.slider_image_size.set(3)\n",
-    "        self.b_plot1 = Button(self.canvas_all, text=\"plot tip\", command=self.plot_tip,bg='blue',fg='white',font=('helvetica',14,'bold')) # button for plotting the tip\n",
-    "        self.var_axis=IntVar()\n",
-    "        self.check_axis = Checkbutton(self.canvas_all,text=\"Hide Axes\", onvalue=1, offvalue=0,variable=self.var_axis,font=('helvetica', 10,'bold'))\n",
-    "        self.label_resolution=Label(self.canvas_all,text='Select number of atoms')                     # label for resolution\n",
-    "        self.label_select_atom=Label(self.canvas_all,text='Select atom type')\n",
-    "        self.slider_res_cv=DoubleVar()\n",
-    "        self.label_slider_res3=Label(self.canvas_all,text='small')\n",
-    "        self.label_slider_res4=Label(self.canvas_all,text='large')\n",
-    "        self.slider_res = Scale(self.canvas_all,from_=1,to=5,orient='horizontal',variable=self.slider_res_cv,showvalue=0)\n",
-    "        self.slider_res.set(1)\n",
-    "        self.label_select_atom_size=Label(self.canvas_all,text='Select atom size')\n",
-    "        self.slider_size_cv=DoubleVar()\n",
-    "        self.slider_size = Scale(self.canvas_all,from_=1,to=200,orient='horizontal',variable=self.slider_size_cv,showvalue=0)\n",
-    "        self.label_slider_res5=Label(self.canvas_all,text='small')\n",
-    "        self.label_slider_res6=Label(self.canvas_all,text='large')  \n",
-    "        self.slider_size.set(50)\n",
-    "        self.i_plot=IntVar()\n",
-    "        self.cb_inverse=Checkbutton(self.canvas_all, text='Flip Tip', onvalue=1, offvalue=0, variable=self.i_plot, font=('helvetica', 10,'bold'))   \n",
-    "        self.control=IntVar()\n",
-    "        self.label_control=Checkbutton(self.canvas_all, text='create control points by clicking on screen', onvalue=1, offvalue=0, variable=self.control, font=('helvetica', 10,'bold'))    \n",
-    "        self.text_box = Text(self.canvas_all,height=10, width=35)\n",
-    "        self.b_control_print = Button(self.canvas_all, text=\"print\",bg='green', command=self.save,fg='white',font=('helvetica',12,'bold'))        # button for pos file initiation\n",
-    "        self.b_control_clear = Button(self.canvas_all, text=\"clear\",bg='red', command=self.clear_text,fg='white',font=('helvetica',12,'bold'))        # button for pos file initiation\n",
-    "        self.var_points=IntVar()\n",
-    "        self.check_points = Checkbutton(self.canvas_all,text=\"plot with points\", onvalue=1, offvalue=0,variable=self.var_points,font=('helvetica', 10,'bold'))\n",
-    "        self.b_adjust_cly = Button(self.canvas_all, text=\"adjust cylinder according to points\",bg='yellow',fg='black', command=self.adjust,font=('helvetica',10,'bold'))        # button for pos file initiation     \n",
-    "        self.cb_color_cp = Combobox(tk, values=self.color_cp, width=10) \n",
-    "        self.cb_color_cp.current(0)\n",
-    "        self.var_plane=IntVar()\n",
-    "        self.label_color_cp=Label(self.canvas_all,text='color of control points')  \n",
-    "        self.check_plane = Checkbutton(self.canvas_all,text=\"show fit plane and normal vector\", onvalue=1, offvalue=0,variable=self.var_plane,font=('helvetica', 10,'bold'))\n",
-    "        \n",
-    "        #### page 3 ####\n",
-    "        self.var_cyl=IntVar()\n",
-    "        self.label_conc=Label(self.canvas_all,text='------------ concentration calculation option  ------------')#.place(x=20,y=400)    # title of segment\n",
-    "        self.var_cyl=IntVar()\n",
-    "        self.check_cylinder = Checkbutton(self.canvas_all,text=\"show cylinder for concentration calculation\", onvalue=1, offvalue=0,variable=self.var_cyl,font=('helvetica', 10,'bold'))#.place(x=20,y=220)\n",
-    "        \n",
-    "        self.b_calc_conc = Button(self.canvas_all, text=\"plot concentration\", command=self.calc_con,bg='blue',fg='white',font=('helvetica',12,'bold'))   # button for calculating the concentration of cylinder\n",
-    "        self.b_calc_excess = Button(self.canvas_all, text=\"plot excess\", command=self.calc_excess,bg='blue',fg='white',font=('helvetica',12,'bold'))    # button for calculating the concentration of cylinder\n",
-    "        self.b_plot_cyl = Button(self.canvas_all, text=\"plot cylinder\", command=self.calc_zoom,bg='blue',fg='white',font=('helvetica',13,'bold'))  # button for calculating the concentration of cylinder\n",
-    "        self.b_print_ex = Button(self.canvas_all, text=\"print excess\", command=self.save_excess,bg='green',fg='white',font=('helvetica',13,'bold'))    # button for calculating the concentration of cylinder\n",
-    "        \n",
-    "        self.label_cly_pos=Label(self.canvas_all,text='cylinder center position')\n",
-    "        self.label_cly_x=Label(self.canvas_all,text='x')\n",
-    "        self.cly_x=StringVar(value='0')\n",
-    "        self.entry_cly_x=Entry(self.canvas_all,textvariable=self.cly_x,width=10)        \n",
-    "        self.label_cly_y=Label(self.canvas_all,text='y') \n",
-    "        self.cly_y=StringVar(value='0')\n",
-    "        self.entry_cly_y=Entry(self.canvas_all,textvariable=self.cly_y,width=10)        \n",
-    "        self.label_cly_z=Label(self.canvas_all,text='z')\n",
-    "        self.cly_z=StringVar(value='0')\n",
-    "        self.entry_cly_z=Entry(self.canvas_all,textvariable=self.cly_z,width=10)\n",
-    "        self.label_cly_radius=Label(self.canvas_all,text='radius of cylinder')  \n",
-    "        self.radius=StringVar(value='10')\n",
-    "        self.entry_cly_radius=Entry(self.canvas_all,textvariable=self.radius)        \n",
-    "        self.label_cly_height=Label(self.canvas_all,text='height of cylinder') \n",
-    "        self.height=StringVar(value='30')\n",
-    "        self.entry_cly_height=Entry(self.canvas_all,textvariable=self.height)        \n",
-    "        self.label_cly_beta=Label(self.canvas_all,text='tilt along x-axis')\n",
-    "        self.beta=StringVar(value='0')\n",
-    "        self.entry_cly_beta=Entry(self.canvas_all,textvariable=self.beta)\n",
-    "        self.label_cly_alpha=Label(self.canvas_all,text='tilt along y-axis')\n",
-    "        self.alpha=StringVar(value='0')\n",
-    "        self.entry_cly_alpha=Entry(self.canvas_all,textvariable=self.alpha)\n",
-    "        self.label_color_cyl=Label(self.canvas_all,text='color of the cylinder')   # label for cylinder color\n",
-    "        self.cb_color = Combobox(self.canvas_all, values=self.data_color)\n",
-    "        self.cb_color.current(0)            \n",
-    "        self.label_inter=Label(self.canvas_all,text='Select interval')      # label for resolution\n",
-    "        self.slider_inter_cv=DoubleVar()\n",
-    "        self.label_slider_inter=Label(self.canvas_all,text='small                 large')    # title of segment\n",
-    "        self.slider_inter = Scale(self.canvas_all,from_=1,to=20,orient='horizontal',variable=self.slider_inter_cv,showvalue=0)#Combobox(self.canvas_all, values=self.data_res)                                                            # combobox for resolution\n",
-    "        self.slider_inter.set(15)\n",
-    "        self.b_plot2 = Button(self.canvas_all, text=\"plot tip\", command=self.plot_tip,bg='blue',fg='white',font=('helvetica',13,'bold')) # button for plotting the tip\n",
-    "        self.b_print_conc = Button(self.canvas_all, text=\"print concentration\", command=self.save_conc,bg='green',fg='white',font=('helvetica',13,'bold')) # button for plotting the tip\n",
-    "        self.var_norm=IntVar()\n",
-    "        self.check_norm = Checkbutton(self.canvas_all,text=\"normalize Excess\", onvalue=1, offvalue=0,variable=self.var_norm)\n",
-    "        self.var_switch=IntVar()\n",
-    "        self.check_switch = Checkbutton(self.canvas_all,text=\"set cylinders                  as bulk*\", onvalue=1, offvalue=0,variable=self.var_switch)\n",
-    "        self.label_astrix=Label(self.canvas_all,text='* the conc. of each segment is calculated in relation to the ends')  \n",
-    "        self.data_bulk=['start','end']\n",
-    "        self.cb_bulk = Combobox(tk, values=self.data_bulk, width=4) \n",
-    "        self.cb_bulk.current(0)\n",
-    "        self.text_box_ex = Text(self.canvas_all,height=6, width=25)\n",
-    "        #self.cb_exp=Checkbutton(self.canvas_all, text='create points for excess calculation', onvalue=1, offvalue=0, variable=self.control, font=('helvetica', 10,'bold'))    \n",
-    "        self.label_exp=Label(self.canvas_all,text='For calcuating the excess select 4 points')  \n",
-    "        \n",
-    "        \n",
-    "        ############## setting up page 1 ##################\n",
-    "        self.a1=self.canvas_all.create_window(200,50,window=self.utext0)        \n",
-    "        self.a2=self.canvas_all.create_window(200,70,window=self.utext1)        \n",
-    "        self.a3=self.canvas_all.create_window(200,90,window=self.utext2)        \n",
-    "        self.a4=self.canvas_all.create_window(200,110,window=self.utext3)        \n",
-    "        self.a5=self.canvas_all.create_window(200,140,window=self.utext4)  \n",
-    "        self.a6=self.canvas_all.create_window(120,165,window=self.b_pos_file) \n",
-    "        self.a7=self.canvas_all.create_window(280,165,window=self.b_rrng_file) \n",
-    "        self.a8=self.canvas_all.create_window(200,230,window=self.b_calc_tip)\n",
-    "        self.a9=self.canvas_all.create_window(200,300,window=self.dtext0)        \n",
-    "        self.a10=self.canvas_all.create_window(200,320,window=self.dtext1)  \n",
-    "        self.a11=self.canvas_all.create_window(200,340,window=self.dtext2)   \n",
-    "        self.a12=self.canvas_all.create_window(200,360,window=self.dtext3)   \n",
-    "        self.a13=self.canvas_all.create_window(200,400,window=self.dtext4)        \n",
-    "        self.a14=self.canvas_all.create_window(200,420,window=self.dtext5)        \n",
-    "        self.a15=self.canvas_all.create_window(200,440,window=self.dtext6)\n",
-    "        self.a16=self.canvas_all.create_window(200,460,window=self.dtext7)\n",
-    "        self.a17=self.canvas_all.create_window(200,480,window=self.dtext8)\n",
-    "        self.a18=self.canvas_all.create_window(200,500,window=self.dtext9)\n",
-    "        self.a19=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a20=self.canvas_all.create_window(200,560,window=self.b_help)\n",
-    "        self.a21=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a22=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a23=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a24=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a25=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a26=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a27=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a28=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a29=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a30=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a31=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a32=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a33=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a34=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "            \n",
-    "        ###################### setup figures  #################################                        \n",
-    "        self.fig=Figure(figsize=(17,13))                                       # defining figure size\n",
-    "        self.canvas=FigureCanvasTkAgg(self.fig,master=self.canvas_all)         # setting up canvas for figure\n",
-    "        self.toolbar=NavigationToolbar2Tk(self.canvas, self.canvas_all)        # setting up toolbar for figure\n",
-    "        self.canvas_all.create_window(400,10,window=self.canvas.get_tk_widget(),anchor=N+W,tags='canvas') #placing figure canvas on general canvas\n",
-    "        self.canvas_all.pack(expand=True,fill=BOTH)                            # placing general canvas at the end\n",
-    "        self.E=2                                                               # setting up variable to check if .pos/.epos file is selected\n",
-    "        self.R=2                                                               # setting up variable to check if .rrng file is selected       \n",
-    "              \n",
-    "    def page_1(self):\n",
-    "        self.canvas_all.delete(self.a1,self.a2,self.a3,self.a4,self.a5,self.a6,self.a7,self.a8,self.a9,self.a10,self.a11,self.a12,self.a13,self.a14,self.a15,self.a16,self.a17,self.a18,self.a19,self.a20,self.a21,self.a22,self.a23,self.a24,self.a25,self.a26,self.a27,self.a28,self.a29,self.a30,self.a31,self.a32,self.a33,self.a34)        \n",
-    "        if self.succ==1:self.a_succ=self.canvas_all.create_window(200,260,window=self.label_succ) #placing label on canvas\n",
-    "        if self.R==1:self.aRS=self.canvas_all.create_window(280,190,window=self.label_rrng_selected)\n",
-    "        if self.R==0:self.aR=self.canvas_all.create_window(280,190,window=self.label_rrng_selected)\n",
-    "        if self.E==0:self.aE=self.canvas_all.create_window(120,190,window=self.label_pos_selected)\n",
-    "        if self.E==1:self.aES=self.canvas_all.create_window(120,190,window=self.label_pos_selected)\n",
-    "            \n",
-    "        self.a1=self.canvas_all.create_window(200,50,window=self.utext0)        \n",
-    "        self.a2=self.canvas_all.create_window(200,70,window=self.utext1)        \n",
-    "        self.a3=self.canvas_all.create_window(200,90,window=self.utext2)        \n",
-    "        self.a4=self.canvas_all.create_window(200,110,window=self.utext3)        \n",
-    "        self.a5=self.canvas_all.create_window(200,140,window=self.utext4)  \n",
-    "        self.a6=self.canvas_all.create_window(120,165,window=self.b_pos_file) \n",
-    "        self.a7=self.canvas_all.create_window(280,165,window=self.b_rrng_file) \n",
-    "        self.a8=self.canvas_all.create_window(200,230,window=self.b_calc_tip)\n",
-    "        self.a9=self.canvas_all.create_window(200,300,window=self.dtext0)        \n",
-    "        self.a10=self.canvas_all.create_window(200,320,window=self.dtext1)  \n",
-    "        self.a11=self.canvas_all.create_window(200,340,window=self.dtext2)   \n",
-    "        self.a12=self.canvas_all.create_window(200,360,window=self.dtext3)   \n",
-    "        self.a13=self.canvas_all.create_window(200,400,window=self.dtext4)        \n",
-    "        self.a14=self.canvas_all.create_window(200,420,window=self.dtext5)        \n",
-    "        self.a15=self.canvas_all.create_window(200,440,window=self.dtext6)\n",
-    "        self.a16=self.canvas_all.create_window(200,460,window=self.dtext7)\n",
-    "        self.a17=self.canvas_all.create_window(200,480,window=self.dtext8)\n",
-    "        self.a18=self.canvas_all.create_window(200,500,window=self.dtext9)\n",
-    "        self.a19=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a20=self.canvas_all.create_window(200,560,window=self.b_help)\n",
-    "        self.a21=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a22=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a23=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a24=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a25=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a26=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a27=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a28=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a29=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a30=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a31=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a32=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a33=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        self.a34=self.canvas_all.create_window(200,520,window=self.label_help)\n",
-    "        \n",
-    "    def page_2(self):\n",
-    "        self.canvas_all.delete(self.a1,self.a2,self.a3,self.a4,self.a5,self.a6,self.a7,self.a8,self.a9,self.a10,self.a11,self.a12,self.a13,self.a14,self.a15,self.a16,self.a17,self.a18,self.a19,self.a20,self.a21,self.a22,self.a23,self.a24,self.a25,self.a26,self.a27,self.a28,self.a29,self.a30,self.a31,self.a32,self.a33,self.a34)        \n",
-    "        if self.R==1:self.canvas_all.delete(self.aRS)\n",
-    "        if self.R==0:self.canvas_all.delete(self.aR)\n",
-    "        if self.E==0:self.canvas_all.delete(self.aE)\n",
-    "        if self.E==1:self.canvas_all.delete(self.aES)\n",
-    "        if self.succ==1: self.canvas_all.delete(self.a_succ)\n",
-    "        ############## setting up buttons, Scales, comboboxes, etc. for plot options ###################    \n",
-    "        self.a1=self.canvas_all.create_window(200,50,window=self.label_plot_tip)        \n",
-    "        self.a2=self.canvas_all.create_window(100,80,window=self.label_image_size)        \n",
-    "        self.a3=self.canvas_all.create_window(30,105,window=self.label_slider_res)        \n",
-    "        self.a4=self.canvas_all.create_window(170,105,window=self.label_slider_res2)        \n",
-    "        self.a5=self.canvas_all.create_window(100,105,window=self.slider_image_size)        \n",
-    "        self.a6=self.canvas_all.create_window(250,300,window=self.b_plot1)        \n",
-    "        self.a7=self.canvas_all.create_window(280,170,window=self.check_axis)        \n",
-    "        self.a8=self.canvas_all.create_window(100,145,window=self.label_resolution)        \n",
-    "        self.a9=self.canvas_all.create_window(280,80,window=self.label_select_atom)          \n",
-    "        self.a10=self.canvas_all.create_window(30,170,window=self.label_slider_res3)        \n",
-    "        self.a11=self.canvas_all.create_window(170,170,window=self.label_slider_res4)        \n",
-    "        self.a12=self.canvas_all.create_window(100,170,window=self.slider_res)        \n",
-    "        self.a13=self.canvas_all.create_window(100,210,window=self.label_select_atom_size)        \n",
-    "        self.a14=self.canvas_all.create_window(30,230,window=self.label_slider_res5)        \n",
-    "        self.a15=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a16=self.canvas_all.create_window(100,230,window=self.slider_size)        \n",
-    "        self.a17=self.canvas_all.create_window(280,230,window=self.cb_inverse)        \n",
-    "        self.a18=self.canvas_all.create_window(280,110,window=self.cb_atom)             # putting combobox with element selection on canvas\n",
-    "        self.a19=self.canvas_all.create_window(200,350,window=self.label_control)        \n",
-    "        self.a20=self.canvas_all.create_window(200,450,window=self.text_box)        \n",
-    "        self.a21=self.canvas_all.create_window(100,560,window=self.b_control_print)        \n",
-    "        self.a22=self.canvas_all.create_window(300,560,window=self.b_control_clear)        \n",
-    "        self.a23=self.canvas_all.create_window(200,560,window=self.check_points)  \n",
-    "        self.a24=self.canvas_all.create_window(200,600,window=self.b_adjust_cly)\n",
-    "        self.a25=self.canvas_all.create_window(100,310,window=self.cb_color_cp)\n",
-    "        self.a26=self.canvas_all.create_window(100,290,window=self.label_color_cp)\n",
-    "        self.a27=self.canvas_all.create_window(200,630,window=self.check_plane) \n",
-    "        self.a28=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a29=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a30=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a31=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a32=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a33=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "        self.a34=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n",
-    "    def page_3(self):\n",
-    "        self.canvas_all.delete(self.a1,self.a2,self.a3,self.a4,self.a5,self.a6,self.a7,self.a8,self.a9,self.a10,self.a11,self.a12,self.a13,self.a14,self.a15,self.a16,self.a17,self.a18,self.a19,self.a20,self.a21,self.a22,self.a23,self.a24,self.a25,self.a26,self.a27,self.a28,self.a29,self.a30,self.a31,self.a32,self.a33,self.a34)        \n",
-    "        if self.R==1:self.canvas_all.delete(self.aRS)\n",
-    "        if self.R==0:self.canvas_all.delete(self.aR)\n",
-    "        if self.E==0:self.canvas_all.delete(self.aE)\n",
-    "        if self.E==1:self.canvas_all.delete(self.aES)\n",
-    "        if self.succ==1: self.canvas_all.delete(self.a_succ)\n",
-    "        ###########  setting up buttons, Scales, comboboxes etc. for cylinder selection and concentration calculations  ###################\n",
-    "        self.label_exp=Label(self.canvas_all,text='For calcuating the excess select 4 points') \n",
-    "        self.entry_cly_x=Entry(self.canvas_all,textvariable=self.cly_x,width=10) \n",
-    "        self.entry_cly_y=Entry(self.canvas_all,textvariable=self.cly_y,width=10)\n",
-    "        self.entry_cly_z=Entry(self.canvas_all,textvariable=self.cly_z,width=10)\n",
-    "        self.entry_cly_alpha=Entry(self.canvas_all,textvariable=self.alpha)\n",
-    "        self.entry_cly_beta=Entry(self.canvas_all,textvariable=self.beta)\n",
-    "        \n",
-    "        self.a1=self.canvas_all.create_window(200,50,window=self.label_conc)        \n",
-    "        self.a2=self.canvas_all.create_window(200,90,window=self.check_cylinder)        \n",
-    "        self.a3=self.canvas_all.create_window(100,450,window=self.b_calc_conc)        \n",
-    "        self.a4=self.canvas_all.create_window(100,500,window=self.b_calc_excess)        \n",
-    "        self.a5=self.canvas_all.create_window(300,400,window=self.b_plot_cyl)    \n",
-    "        self.a6=self.canvas_all.create_window(300,500,window=self.b_print_ex) \n",
-    "        self.a7=self.canvas_all.create_window(200,120,window=self.label_cly_pos)    \n",
-    "        self.a8=self.canvas_all.create_window(100,140,window=self.label_cly_x)        \n",
-    "        self.a9=self.canvas_all.create_window(100,170,window=self.entry_cly_x)      \n",
-    "        self.a10=self.canvas_all.create_window(200,140,window=self.label_cly_y)        \n",
-    "        self.a11=self.canvas_all.create_window(200,170,window=self.entry_cly_y)        \n",
-    "        self.a12=self.canvas_all.create_window(300,140,window=self.label_cly_z)        \n",
-    "        self.a13=self.canvas_all.create_window(300,170,window=self.entry_cly_z)\n",
-    "        self.a14=self.canvas_all.create_window(100,200,window=self.label_cly_radius)\n",
-    "        self.a15=self.canvas_all.create_window(100,225,window=self.entry_cly_radius)                       \n",
-    "        self.a16=self.canvas_all.create_window(300,200,window=self.label_cly_height)        \n",
-    "        self.a17=self.canvas_all.create_window(300,225,window=self.entry_cly_height)         \n",
-    "        self.a18=self.canvas_all.create_window(100,255,window=self.label_cly_beta)        \n",
-    "        self.a19=self.canvas_all.create_window(100,280,window=self.entry_cly_beta)        \n",
-    "        self.a20=self.canvas_all.create_window(300,255,window=self.label_cly_alpha)      \n",
-    "        self.a21=self.canvas_all.create_window(300,280,window=self.entry_cly_alpha)             \n",
-    "        self.a22=self.canvas_all.create_window(100,330,window=self.label_color_cyl)        \n",
-    "        self.a23=self.canvas_all.create_window(100,355,window=self.cb_color)        \n",
-    "        self.a24=self.canvas_all.create_window(300,310,window=self.label_inter)        \n",
-    "        self.a25=self.canvas_all.create_window(300,330,window=self.label_slider_inter)        \n",
-    "        self.a26=self.canvas_all.create_window(300,355,window=self.slider_inter)        \n",
-    "        self.a27=self.canvas_all.create_window(100,400,window=self.b_plot2)        \n",
-    "        self.a28=self.canvas_all.create_window(300,450,window=self.b_print_conc)\n",
-    "        self.a29=self.canvas_all.create_window(100,550,window=self.check_norm)\n",
-    "        self.a30=self.canvas_all.create_window(260,550,window=self.check_switch)\n",
-    "        self.a31=self.canvas_all.create_window(220,580,window=self.label_astrix)\n",
-    "        self.a32=self.canvas_all.create_window(280,550,window=self.cb_bulk)\n",
-    "        self.a33=self.canvas_all.create_window(200,610,window=self.label_exp)\n",
-    "        self.a34=self.canvas_all.create_window(200,675,window=self.text_box_ex)\n",
-    "        \n",
-    "    def help_web(self):\n",
-    "        url='https://github.com/areichm/APT_analyzer'\n",
-    "        new=1\n",
-    "        webbrowser.open(url,new=new)\n",
-    "        \n",
-    "    def clear_text(self):    \n",
-    "        self.text_box.delete('1.0', END)\n",
-    "                \n",
-    "    def save(self):\n",
-    "        points=self.text_box.get(1.0,END)\n",
-    "        points=points.split('\\n')\n",
-    "        points=[x for x in points if x!='']\n",
-    "        xyz=[]\n",
-    "        for i in range(0,len(points)):\n",
-    "            points_inner=points[i].split(',')\n",
-    "            for j in points_inner:\n",
-    "                m=j.split('=')\n",
-    "                xyz.append(m[1])\n",
-    "        # with np.unique now contains only the unique data\n",
-    "        data=np.unique(np.array(xyz).reshape(int(len(xyz)/3),3), axis=0)\n",
-    "        # ##MK::sprint 09\n",
-    "        # using here df.to_hdf via pandas needs pandas==1.4.4 with pytables compiled under the hood !\n",
-    "        # pytables however is not directly available as a compiled package via pypi\n",
-    "        # in conda pytables is precompiled inside the conda package already\n",
-    "        # label=('x','y','z')      \n",
-    "        # df=pd.DataFrame(data,columns=label)\n",
-    "        h5File = \"controlpoints.h5\"\n",
-    "        # df.to_hdf(h5File,'data')\n",
-    "        # instead use h5py directly\n",
-    "        h5w = h5py.File(h5File, 'w')\n",
-    "        dst = h5w.create_dataset('/xyz', data=np.asarray(data, np.float32))\n",
-    "        dst.attrs[\"units\"] = \"nm\"\n",
-    "        h5w.close()\n",
-    "        messagebox.showinfo(title='APT_analyzer',message='Control points saved to hdf5 file: \"controlpoints.h5\" inside the APT-analyzer folder.')\n",
-    "\n",
-    "    def save_conc(self):\n",
-    "        if self.conc_check==0:messagebox.showinfo(title='APT_analyzer',message='please plot concentration first')\n",
-    "        else: \n",
-    "            self.df_con.to_csv('APT_analyzer_concentration.csv')\n",
-    "            messagebox.showinfo(title='APT_analyzer',message='Control points saved to csv file: \"APT_analyzer_concentration.csv\" inside the APT-analyzer folder.')\n",
-    "            \n",
-    "    def save_excess(self):\n",
-    "        if self.excess_check==0:messagebox.showinfo(title='APT_analyzer',message='please plot excess first')\n",
-    "        else: \n",
-    "            self.df_ex.to_csv('APT_analyzer_excess.csv')\n",
-    "            messagebox.showinfo(title='APT_analyzer',message='Control points saved to csv file: \"APT_analyzer_excess.csv\" inside the APT-analyzer folder.')\n",
-    "                      \n",
-    "    def adjust(self):                   # adjust cylinder according to controlpoints\n",
-    "        self.var_cyl.set(1)\n",
-    "        XX=[]                           # setting up arrays\n",
-    "        YY=[]\n",
-    "        ZZ=[]\n",
-    "        points=self.text_box.get(1.0,END)   # get text from text box\n",
-    "        points=points.split('\\n')           # split the text into each row\n",
-    "        points=[x for x in points if x!=''] # remove any rows that dont contain information\n",
-    "        for i in range(0,len(points)):      # loop over all rows\n",
-    "                points_inner=points[i].split(',')   # split each row into parts of each coordinates\n",
-    "                xyz2=[]\n",
-    "                for j in points_inner:               # loop over all values inside row\n",
-    "                    m=j.split('=')                   # isolate actual number\n",
-    "                    xyz2.append(m[1])                # save number\n",
-    "                XX.append(float(xyz2[0]))            # save x,y and z coordinate\n",
-    "                YY.append(float(xyz2[1]))\n",
-    "                if self.i_plot.get()==0:ZZ.append(float(xyz2[2]))\n",
-    "                if self.i_plot.get()==1:ZZ.append(-float(xyz2[2]))      # if inverse tip is selected reverse z coordinate\n",
-    "        \n",
-    "        if len(XX)>=3:                               # if 3 or more control points are chosen\n",
-    "                center_x=round(sum(XX)/len(XX),3)             # calculate center in x, y and z\n",
-    "                center_y=round(sum(YY)/len(YY),3)\n",
-    "                if self.i_plot.get()==0:center_z=round(sum(ZZ)/len(ZZ),3)\n",
-    "                if self.i_plot.get()==1:center_z=round(-sum(ZZ)/len(ZZ),3)\n",
-    "                self.cly_x=StringVar(value=center_x)                    #save the center as coordinates for cylinder\n",
-    "                self.cly_y=StringVar(value=center_y)\n",
-    "                self.cly_z=StringVar(value=center_z)\n",
-    "                tmp_C=[]\n",
-    "                for i in range(len(XX)):\n",
-    "                    tmp_C.append([XX[i],YY[i],ZZ[i]])                              #write x,y and z into one matrix and transpose it below\n",
-    "                C=np.array(tmp_C).T\n",
-    "                svd=np.linalg.svd(C - np.mean(C, axis=1, keepdims=True))           # using singular value decomposition to find fit\n",
-    "                left=svd[0]                                                        # upper line has to substract out the centroid first\n",
-    "                fit=left[:,-1]\n",
-    "                normal=np.array([fit[0],fit[1],fit[2]])\n",
-    "                norm=np.linalg.norm(normal)\n",
-    "                n_n=normal/norm                                                    # select fitted values\n",
-    "                aa=np.arcsin(-n_n[1])\n",
-    "                bb=math.atan2(n_n[0],n_n[2])     # this is done by applying rotation matrix in reverse order onto normal verctor\n",
-    "                                                 # and then solving the equation for alpha and beta\n",
-    "                #al=round(math.degrees(aa),4)    # that rotate the normal vector into x=0 and y=0\n",
-    "                #if normal[2]<0:al=round(math.degrees(-aa),4)\n",
-    "                al=round(math.degrees(aa),4)\n",
-    "                be=round(math.degrees(bb),4)\n",
-    "                self.alpha=StringVar(value=al)                                     # then transforming into degree and  \n",
-    "                self.beta=StringVar(value=be)                                      # saving alpha and beta values into entry field\n",
-    "        else: messagebox.showinfo(title='APT_analyzer',message='Choose at least 3 control points')  # if less than 3 points are selected show message\n",
-    "                \n",
-    "    def search_pos(self):                                                      # function for searching for pos/epos file\n",
-    "        if self.E==0:self.canvas_all.delete(self.aE)\n",
-    "        if self.E==1:self.canvas_all.delete(self.aES)\n",
-    "        self.filename=filedialog.askopenfilename()                             # getting file from search\n",
-    "        S='.POS' in self.filename                                              # checking if .POS is in the filename\n",
-    "        ES='.EPOS' in self.filename                                            # checking if .EPOS is in the filename\n",
-    "        s='.pos' in self.filename                                              # checking if .pos is in the filename\n",
-    "        es='.epos' in self.filename                                            # checking if .epos is in the filename\n",
-    "        if S or s is True:                                                     # if .POS or .pos was selected\n",
-    "            self.label_pos_selected=Label(text='pos file selected')            # create label for pos\n",
-    "            self.aE=self.canvas_all.create_window(120,190,window=self.label_pos_selected) #placing label on canvas\n",
-    "            self.E=0                                                           # set variable for later recognition\n",
-    "            if self.succ==1: self.canvas_all.delete(self.a_succ) \n",
-    "            self.succ=0\n",
-    "        elif ES or es is True:                                                 # if .EPOS or .epos was selected\n",
-    "            self.label_pos_selected=Label(text='epos file selected')           # creating label for epos\n",
-    "            self.aES=self.canvas_all.create_window(120,190,window=self.label_pos_selected) #put label on canvas\n",
-    "            self.E=1                                                           # set variable for later recognition\n",
-    "            if self.succ==1: self.canvas_all.delete(self.a_succ) \n",
-    "            self.succ=0\n",
-    "        else:                                                                  # if any other filetype was selected\n",
-    "            messagebox.showinfo(title='APT_analyzer',message='select .pos or .epos file. Warning: Notation has to be either .pos /.epos or .POS / .EPOS')\n",
-    "            self.filename=[]                                                   # leave filename empty\n",
-    "            self.E=2                                                           # set variable back to 2\n",
-    "            \n",
-    "    def search_rrng(self):                                                     # function for searching for rrng file\n",
-    "        if self.R==1:self.canvas_all.delete(self.aRS)\n",
-    "        if self.R==0:self.canvas_all.delete(self.aR)\n",
-    "        self.filename2=filedialog.askopenfilename()                            # getting file from search\n",
-    "        S='.RRNG' in self.filename2                                            # checking if .RRNG is in the filename\n",
-    "        s='.rrng' in self.filename2                                            # checking if .rrng is in the filename\n",
-    "        SR='.RNG' in self.filename2\n",
-    "        sr='.rng' in self.filename2\n",
-    "        if S or s is True:                                                     # if .RRNG or .rrng was selected\n",
-    "            self.label_rrng_selected=Label(text='.rrng file selected')         # create label for rrng\n",
-    "            self.aR=self.canvas_all.create_window(280,190,window=self.label_rrng_selected) #placing label on canvas\n",
-    "            self.R=0                                                           # setting variable for later recognition\n",
-    "            if self.succ==1: self.canvas_all.delete(self.a_succ) \n",
-    "            self.succ=0\n",
-    "        elif SR or sr is True:\n",
-    "            self.label_rrng_selected=Label(text='.rng file selected')         # create label for rrng\n",
-    "            self.aRS=self.canvas_all.create_window(280,190,window=self.label_rrng_selected) #placing label on canvas\n",
-    "            self.R=1 \n",
-    "            if self.succ==1: self.canvas_all.delete(self.a_succ) \n",
-    "            self.succ=0\n",
-    "        else:                                                                  # if no correct file was selected\n",
-    "            messagebox.showinfo(title='APT_analyzer',message='select .rrng file. Warning: Notation has to be either .rrng or .RRNG')\n",
-    "            self.filename2=[]                                                   # leaving filename empty\n",
-    "            self.R=2                                                           # set variable back to 2\n",
-    "        \n",
-    "    def calculate_tip(self):                                                   # function for reading and converting the pos and rrng file and creating the tip\n",
-    "        if self.E==2:messagebox.showinfo(title='APT_analyzer',message='no file .pos/.epos file selected')   # checking if no  pos/epos file is selected (E=2)\n",
-    "        elif self.R==2:messagebox.showinfo(title='APT_analyzer',message='no file .rrng file selected')    # checking if no  rrng file is selected (R=2)\n",
-    "        else:                                                                    # if pos/epos and rrng file is selected\n",
-    "            with open(self.filename, 'rb') as f:                                   # opening pos/epos data from file1\n",
-    "                data = f.read()                                                    # reading pos/epos data from file1\n",
-    "            data_rrng=self.filename2                                               # reading rrng data from file2\n",
-    "            if self.E==0:pos=apt.read_pos(data)                                    # converting pos data if pos file was selected (E==0)\n",
-    "            elif self.E==1:pos=apt.read_epos(data)                                 # converting epos data if epos file was selected (E==1)\n",
-    "            if self.R==0:rrngs=apt.read_rrng(data_rrng)                           # converting rrng data\n",
-    "            elif self.R==1:rrngs=apt.read_rng(data_rrng)\n",
-    "            self.tip=apt.label_ions(pos, rrngs)                                    # label ions using apt_importers functions\n",
-    "            self.ele=apt.unique(list(self.tip['comp']))                            # determining how many unique elements in tip using apt_importers functions\n",
-    "            string=['all']                                                         # setting up strings for atom selection combobox\n",
-    "            for i in range (0,len(self.ele)):                                      # loop over all unique elements\n",
-    "                string.append(self.ele[i])                                         # creating strings with all unique elements\n",
-    "            self.data_atom=(string)                                                # data for combobox containing all unique elements + 'all' at start\n",
-    "            self.cb_atom = Combobox(tk, values=self.data_atom)                     # creating combobox with unique elements data \n",
-    "            self.atom=1\n",
-    "        \n",
-    "            self.cb_atom.current(0)                                                # setting initial value of combobox to 'all'  \n",
-    "            self.fig.clear()                                                   # if plot single was selected clear all previous plots\n",
-    "            self.canvas_all.delete('message') \n",
-    "            self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[2,1],wspace=0.5,hspace=0.5,height_ratios=[2,1]) #adjust the size of the figure compared to (111)\n",
-    "            self.ax=self.fig.add_subplot(self.spec[0],projection='3d')\n",
-    "            N=5000\n",
-    "            u_ele=self.ele\n",
-    "            x=np.array(self.tip['x'])[::N]                                         # select x cooridant (only take every Nth atom to plot later)\n",
-    "            y=np.array(self.tip['y'])[::N]                                         # select y cooridant from tip data\n",
-    "            z=np.array(self.tip['z'])[::N]                                         # select z cooridant from tip data\n",
-    "            c=np.array(self.tip['colour'])[::N]                                    # select the colour column in the tip data\n",
-    "            label=np.array(self.tip['comp'])[::N]                                  # select the composition column in the tip data\n",
-    "            for i in range(0,len(u_ele)):                                          # loop that goes over every different elements\n",
-    "                e=label==u_ele[i]                                                 # seperation of the elements\n",
-    "                x_new=x[e]                                                        # select the x values of each element indiviually\n",
-    "                y_new=y[e]\n",
-    "                z_new=z[e]\n",
-    "                c_new=c[e]\n",
-    "                self.ax.scatter3D(x_new,y_new,z_new,c=c_new,label=u_ele[i],s=1)  # scatter plot each element seperatly and assign label\n",
-    "                x_N=len(x) \n",
-    "                self.ax.set_title('preview (number of atoms={:.0f},     1/{:.0f} of all atoms)'.format(x_N,N))                                                   # assigne x_N value to show the number of plotted atoms in title\n",
-    "            self.canvas.draw_idle()\n",
-    "            apt.set_axes_equal(self.ax)                                            # function for setting the axes equal for 3d plot\n",
-    "            self.ax.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))#, fontsize=7)                                                        # show legends of each element   \n",
-    "            self.ax.set_xlabel('X-axis',fontweight='bold')                     # label x axis\n",
-    "            self.ax.set_ylabel('Y-axis',fontweight='bold')                # label y axis\n",
-    "            self.ax.set_zlabel('Z-axis',fontweight='bold')                     # label z axis\n",
-    "            self.label_succ=Label(text='Sucessfully loaded files!')         # create label for rrng\n",
-    "            self.a_succ=self.canvas_all.create_window(200,260,window=self.label_succ) #placing label on canvas\n",
-    "            self.succ=1\n",
-    "    \n",
-    "    def clear(self):                                                           # function for clearing canvas\n",
-    "        self.fig.clear()                                                       # clearing canvas\n",
-    "        self.canvas.draw_idle()                                                # drawing \n",
-    "        self.canvas_all.delete('message')                                      # deleting message about concentration data\n",
-    "        \n",
-    "    def plot_tip(self):                                                        # function about plotting tip\n",
-    "        if self.plot_exist==1:                                                 # if plot already exists get the parameters of old plot\n",
-    "            azim=self.ax.azim                                                  # get azimutal angle of old plot\n",
-    "            elev=self.ax.elev\n",
-    "            xlim=self.ax.get_xlim()                                           # get x,y and z limit of old plot\n",
-    "            ylim=self.ax.get_ylim()\n",
-    "            zlim=self.ax.get_zlim()\n",
-    "        if self.i_plot.get()==0:self.invert=0                                 # if inversion checkbox is unmarked set value=0\n",
-    "        else: self.invert=1                                                   # if inversion checkbox is marked set value=1\n",
-    "            \n",
-    "        color_zyl=str(self.cb_color.get())                                    # get color of cylinder from color entry box\n",
-    "        color_cp=str(self.cb_color_cp.get())\n",
-    "        self.canvas_all.delete('message')                                      # clearing message about concentration data\n",
-    "        Z= self.cb_atom.get()                                                  # getting variable from combobox of atom selection\n",
-    "        M = self.slider_res.get()                                              # getting variable from combobox of resolution selection\n",
-    "        SS=self.slider_size.get()                                              # getting variable from combobox of atom size selection\n",
-    "        S=float(SS)/10                                                         # transforming entry into float and deviding by 10 so values 0.1 to 1 are also included\n",
-    "        image_size=self.slider_image_size.get()\n",
-    "        image_size=float(image_size)**2\n",
-    "        u_ele=self.ele\n",
-    "        self.fig.clear()                                                   # if plot single was selected clear all previous plots\n",
-    "        self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.1,hspace=0.1,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n",
-    "        self.ax=self.fig.add_subplot(self.spec[0],projection='3d')         # make new figure with size depending on the image size slider\n",
-    "        if self.plot_exist==1:                                             # if plot already exist set old parameters of plot as new ones\n",
-    "            self.ax.view_init(elev=elev,azim=azim)                         # set azimuthal angle and elevation of old plot as new one\n",
-    "            self.ax.set_xlim3d(xlim[0],xlim[1])                            # set x,y and z limit of old plot as new one\n",
-    "            self.ax.set_ylim3d(ylim[0],ylim[1])\n",
-    "            if self.i_plot.get()==0 and self.invert==0:self.ax.set_zlim3d(zlim[0],zlim[1])  # depending on if the plot should be inverted or not\n",
-    "            if self.i_plot.get()==1 and self.invert==1:self.ax.set_zlim3d(zlim[0],zlim[1])  # reset the z limit of new plot to center it again\n",
-    "        self.plot_exist=1                                                      # set plot exist as one in order to mark that plot exists\n",
-    "        n=len(np.array(self.tip['x']))                                         # get the number of atoms\n",
-    "        N=int(50000/(10**M))                                                   # calc N (the number how many atoms should be plotted)\n",
-    "        if N==0:N=1\n",
-    "        \n",
-    "        x=np.array(self.tip['x'])[::N]                                         # select x cooridant (only take every Nth atom to plot later)\n",
-    "        y=np.array(self.tip['y'])[::N]                                         # select y cooridant from tip data\n",
-    "        z=np.array(self.tip['z'])[::N]                                         # select z cooridant from tip data\n",
-    "        c=np.array(self.tip['colour'])[::N]                                    # select the colour column in the tip data\n",
-    "        label=np.array(self.tip['comp'])[::N]                                  # select the composition column in the tip data\n",
-    "\n",
-    "        max_x=max(x)\n",
-    "        min_x=min(x)\n",
-    "        max_z=max(z)\n",
-    "        min_z=min(z)\n",
-    "        max_y=max(y)\n",
-    "        min_y=min(y)\n",
-    "        for i in range(0,len(u_ele)):                                          # loop that goes over every different elements\n",
-    "            e=label==u_ele[i]                                                 # seperation of the elements\n",
-    "            x_new=x[e]                                                        # select the x values of each element indiviually\n",
-    "            y_new=y[e]\n",
-    "            z_new=z[e]\n",
-    "            c_new=c[e]     \n",
-    "            if self.i_plot.get()==1: z_new=-z_new                                          # if inverse tip is selected change the sign of the z coordinates\n",
-    "            if Z=='all':                                                      # if all was selected plot all of them together\n",
-    "                X=np.array([x,y,z]).T \n",
-    "                c_new[c_new=='#FFFFFF']='#000000'\n",
-    "                self.ax.scatter(x_new,y_new,z_new,c=c_new,label=u_ele[i],s=S,zorder = 1,depthshade = False,picker=True)  # scatter plot each element seperatly and assign label\n",
-    "                x_N=len(x) \n",
-    "                self.ax.set_title('number of atoms={:.0f},     1/{:.0f} of all atoms'.format(x_N,N))                                                   # assigne x_N value to show the number of plotted atoms in title\n",
-    "            elif u_ele[i]==Z:                                                 # if a certain element was selected in combobox for element selection\n",
-    "                X=np.array([x_new,y_new,z_new]).T                             # putting all \n",
-    "                c_new[c_new=='#FFFFFF']='#000000'\n",
-    "                self.ax.scatter(X[:,0],X[:,1],X[:,2],c=c_new,label=u_ele[i],s=S,zorder = 1, depthshade = False,picker=True)  #scatter plot each element seperatly and assign label         \n",
-    "                x_N=len(x_new)                                                 # assigne x_N only to show the number of plotted atoms of selected element \n",
-    "                self.ax.set_title('number of atoms={:.0f},     1/{:.0f} of all atoms of this type'.format(x_N,N))                                                   \n",
-    "        apt.set_axes_equal(self.ax)                                            # function for setting the axes equal for 3d plot\n",
-    "        self.ax.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))#, fontsize=7)                                                       # show legends of each element\n",
-    "        if self.var_axis.get()==0:                                             # if show axis was selected\n",
-    "            self.ax.set_xlabel('X-axis',fontweight='bold')                     # label x axis\n",
-    "            self.ax.set_ylabel('Y-axis',fontweight='bold')                     # label y axis\n",
-    "            self.ax.set_zlabel('Z-axis',fontweight='bold')                     # label z axis\n",
-    "        elif self.var_axis.get()==1:                                           # if show axis was not selected\n",
-    "            self.ax.set_axis_off()                                             # dont show axis\n",
-    "        \n",
-    "        if self.var_cyl.get()==1:                                              # if show clyinder was selected\n",
-    "            x_pos=self.cly_x.get()                                            # get x value from x entry box\n",
-    "            if x_pos=='': x_pos=0\n",
-    "            else:x_pos = float(x_pos)\n",
-    "            y_pos =self.cly_y.get()                                           # get y value from y entry box\n",
-    "            if y_pos=='': y_pos=0\n",
-    "            else:y_pos = float(y_pos)\n",
-    "            z_pos = self.cly_z.get()                                          # get z value from z entry box\n",
-    "            if z_pos=='': z_pos=0\n",
-    "            else:z_pos = float(z_pos) \n",
-    "            if self.i_plot.get()==1:      z_pos = -z_pos                      # if inverse tip is selected inverse the z coordinates of the cylinder              \n",
-    "            height = float(self.height.get())                                 # get height value from height entry box\n",
-    "            alpha = float(self.alpha.get())                                   # get tilt along y value from alpha entry box\n",
-    "            beta = float(self.beta.get())                                     # get tilt along x value from beta entry box\n",
-    "            r = float(self.radius.get())                                      # get radius value from radius entry box \n",
-    "            theta=np.linspace(0,2*np.pi,201)                                  # create linspace variable for plotting the circle\n",
-    "            alpha=math.radians(alpha)                                         # transform alpha from deg in rad\n",
-    "            beta=math.radians(beta)                                           # transfrom beta from deg in rad\n",
-    "            Xc,Yc,Zc=data_for_cylinder_along_z(0,0,0,r,height)  # calculating cylinder\n",
-    "            Z=np.array([Xc,Yc,Zc]).T\n",
-    "            matrix_l=np.array([(np.cos(beta),                   np.sin(alpha)*np.sin(beta),        np.cos(alpha)*np.sin(beta)),\n",
-    "                               (0,                              np.cos(alpha),                     -np.sin(alpha)),\n",
-    "                               (-np.sin(beta),                  np.sin(alpha)*np.cos(beta),        np.cos(alpha)*np.cos(beta))])\n",
-    "            pro=[]\n",
-    "            for j in range(0,len(Z)):\n",
-    "                 for i in range (0,len(Z[j])):\n",
-    "                         pro.append(matrix_l.dot(Z[i][j]))  \n",
-    "            pro=np.array(pro)                \n",
-    "            Z_new=pro.reshape(50,50,3).T\n",
-    "            self.ax.plot_surface(Z_new[0]+x_pos,Z_new[1]+y_pos,Z_new[2]+z_pos,alpha=0.4,color=color_zyl) # plotting cylinder\n",
-    "            apt.set_axes_equal(self.ax)\n",
-    "            \n",
-    "        if self.var_points.get()==1:\n",
-    "            XX=[]\n",
-    "            YY=[]\n",
-    "            ZZ=[]\n",
-    "            points=[]\n",
-    "            points=self.text_box.get(1.0,END)\n",
-    "            points=points.split('\\n')\n",
-    "            points=[x for x in points if x!='']\n",
-    "            for i in range(0,len(points)):\n",
-    "                points_inner=points[i].split(',')\n",
-    "                xyz2=[]\n",
-    "                for j in points_inner:\n",
-    "                    m=j.split('=')\n",
-    "                    xyz2.append(m[1])\n",
-    "                x2=float(xyz2[0])\n",
-    "                y2=float(xyz2[1])\n",
-    "                z2=float(xyz2[2])\n",
-    "                XX.append(x2)\n",
-    "                YY.append(y2)\n",
-    "                ZZ.append(z2)\n",
-    "                if self.i_plot.get()==1:z2=-z2                                          # if inverse tip is selected\n",
-    "                self.ax.scatter3D(x2,y2,z2,marker='+',color=color_cp,s=S*100)\n",
-    "            if len(XX)>=3 and self.var_plane.get()==1:\n",
-    "                center_x=sum(XX)/len(XX)\n",
-    "                center_y=sum(YY)/len(YY)\n",
-    "                center_z=sum(ZZ)/len(ZZ)\n",
-    "                self.cly_x=StringVar(value=center_x)\n",
-    "                self.cly_y=StringVar(value=center_y)\n",
-    "                self.cly_z=StringVar(value=center_z)\n",
-    "                tmp_C=[]\n",
-    "                for i in range(len(XX)):\n",
-    "                    tmp_C.append([XX[i],YY[i],ZZ[i]])\n",
-    "                C=np.array(tmp_C).T\n",
-    "                svd=np.linalg.svd(C - np.mean(C, axis=1, keepdims=True))\n",
-    "                left=svd[0]\n",
-    "                fit=left[:,-1]\n",
-    "                #print('solution: %f x +%f y +%f z = 0' %(fit[0],fit[1],fit[2]))\n",
-    "                normal=np.array([fit[0],fit[1],fit[2]])   \n",
-    "                r=5\n",
-    "                self.ax.plot([center_x,center_x+r*normal[0]],[center_y,center_y+r*normal[1]],[center_z,center_z+r*normal[2]],color='r',linewidth=5)\n",
-    "                xlim=self.ax.get_xlim()\n",
-    "                ylim=self.ax.get_ylim()\n",
-    "                X,Y=np.meshgrid(np.arange(xlim[0],xlim[1]),np.arange(ylim[0],ylim[1]))\n",
-    "                Z=np.zeros(X.shape)\n",
-    "                for r in range(X.shape[0]):\n",
-    "                    for c in range(X.shape[1]):\n",
-    "                        #Z[r,c]=fit[0]*X[r,c]+fit[1]*Y[r,c]+fit[2]\n",
-    "                        Z[r,c]=-(fit[0]*X[r,c]+fit[1]*Y[r,c])/fit[2]\n",
-    "                #self.ax.plot([cpx,fit[0]],[cpy,fit[1]],[cpz,-1])\n",
-    "                self.ax.plot_wireframe(X+center_x,Y+center_y,Z+center_z,color='k')\n",
-    "        self.canvas.draw_idle()  \n",
-    "  \n",
-    "        def distance(point, event):\n",
-    "#         Return distance between mouse position and given data point\n",
-    "#         Args:point (np.array): np.array of shape (3,), with x,y,z in data coords event (MouseEvent): mouse event (which contains mouse position in .x and .xdata)\n",
-    "#         Returns:distance (np.float64): distance (in screen coords) between mouse pos and data point          \n",
-    "             assert point.shape == (3,), \"distance: point.shape is wrong: %s, must be (3,)\" % point.shape  \n",
-    "             x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], self.ax.get_proj())   # Project 3d data space to 2d data space\n",
-    "             x3, y3 = self.ax.transData.transform((x2, y2))                                        # Convert 2d data space to 2d screen space\n",
-    "             return np.sqrt ((x3 - event.x)**2 + (y3 - event.y)**2)                                # calculate distance\n",
-    "    \n",
-    "        def onclick(event):\n",
-    "            distances = [distance (X[i,0:3], event) for i in range(X.shape[0])]                                              # use function distance to evaluate the closests index to mouse click\n",
-    "            index=np.argmin(distances)                                                                                       # select the closest index\n",
-    "            self.ax.scatter(X[index, 0], X[index, 1], X[index, 2],marker='+',color=color_cp,s=S*100)                         # plot controlpoint at closest index point\n",
-    "            text='x='+str(np.round(X[index, 0],4))+', y='+str(np.round(X[index, 1],4))+', z='+str(np.round(X[index, 2],4))   # write x,y,z coordinates into text file\n",
-    "            if self.i_plot.get()==1:text='x='+str(np.round(X[index, 0],4))+', y='+str(np.round(X[index, 1],4))+', z='+str(-np.round(X[index, 2],4))\n",
-    "            self.text_box.insert(END,text)                                                                                   # insert text file in textbox\n",
-    "            self.text_box.insert(END,'\\n')                                                                                   # make sure next control point is next row\n",
-    "            self.canvas.draw_idle()\n",
-    "                \n",
-    "        if self.control.get()==1: \n",
-    "            if self.diss==1:self.fig.canvas.mpl_disconnect(self.cid)\n",
-    "            self.cid=self.fig.canvas.mpl_connect('button_press_event',onclick)\n",
-    "            self.diss=1\n",
-    "        elif self.control.get()==0 and self.diss==1: \n",
-    "            self.fig.canvas.mpl_disconnect(self.cid)\n",
-    "            self.diss=0\n",
-    "          \n",
-    "    def calc_con(self):                                                        # function for calculating the concentration\n",
-    "        if self.diss2==1:self.fig.canvas.mpl_disconnect(self.cid) \n",
-    "        self.plot_exist=0\n",
-    "        self.print_con=[]\n",
-    "        self.print_con2=[]\n",
-    "        self.canvas_all.delete('message') \n",
-    "        start_end=self.cb_bulk.get()\n",
-    "        atom= self.cb_atom.get()\n",
-    "        u_ele_real=self.ele\n",
-    "        image_size=self.slider_image_size.get()\n",
-    "        image_size=float(image_size)/2\n",
-    "        self.fig.clear()\n",
-    "        self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.5,hspace=0.5,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n",
-    "        self.ax1=self.fig.add_subplot(self.spec[0])\n",
-    "        self.ax1.set_xlabel('z position of cylinder')\n",
-    "        self.ax1.set_ylabel('concentration [%]')\n",
-    "        x_real=np.array(self.tip['x'])\n",
-    "        y_real=np.array(self.tip['y'])\n",
-    "        z_real=np.array(self.tip['z'])\n",
-    "        if self.i_plot.get()==1:                                     # atoms z coordinatines inversion\n",
-    "            z_real = -z_real\n",
-    "        c_real=np.array(self.tip['colour'])\n",
-    "        label_real=np.array(self.tip['comp'])\n",
-    "        inter=float(self.slider_inter.get()/20)\n",
-    "        height = float(self.height.get())\n",
-    "        alpha = float(self.alpha.get())\n",
-    "        beta = float(self.beta.get())\n",
-    "        r = float(self.radius.get())\n",
-    "        x_pos = float(self.cly_x.get())\n",
-    "        y_pos = float(self.cly_y.get())\n",
-    "        z_pos = float(self.cly_z.get())\n",
-    "        if self.i_plot.get()==1:                                     # cylinder z coordinatines inversion\n",
-    "            z_pos = -z_pos\n",
-    "        z_start=-height/2\n",
-    "        z_end=height/2\n",
-    "        alpha=math.radians(-alpha)\n",
-    "        beta=math.radians(-beta)\n",
-    "        ###################   tilt and move zylinder ######################################\n",
-    "        pro=[]\n",
-    "        Z=np.array([x_real-x_pos,y_real-y_pos,z_real-z_pos]).T\n",
-    "        M_ROT1=[(1,      0,                  0     ),            # rotational matrix along the x-direction\n",
-    "                (0,  np.cos(alpha),  -np.sin(alpha)),\n",
-    "                (0,  np.sin(alpha),    np.cos(alpha))]\n",
-    "\n",
-    "        M_ROT2=[(np.cos(beta),      0,       np.sin(beta)),     # rotational matrix along the y-direction\n",
-    "                (0,                  1,            0      ),\n",
-    "                (-np.sin(beta),      0,       np.cos(beta))]\n",
-    "        matrix_l=np.array(M_ROT1).dot(M_ROT2)\n",
-    "        for j in range(0,len(Z)):\n",
-    "                    pro.append(matrix_l.dot(Z[j])) \n",
-    "        Z_new=np.array(pro)\n",
-    "        x_real=Z_new[:,0]\n",
-    "        y_real=Z_new[:,1]\n",
-    "        z_real=Z_new[:,2]\n",
-    "        ######################################################################### \n",
-    "        xy=((x_real)**2+(y_real)**2)**(1/2)                                    # cirlce constraint for atoms       \n",
-    "        circle=xy<=r                                                           # only select atoms inside of circle\n",
-    "        message='concentration: \\n'                                            # initialize the message displayed on the right side of the plot\n",
-    "        for m in range(0,len(u_ele_real)):                                     # loop over each individual elements\n",
-    "            plot_z=[]                                                          # x component of concentration plots \n",
-    "            Num=[]                                                             # Number of atoms inside the circle and intervals (for concentration calculation)\n",
-    "            Num_all=[]                                                         # total number of atoms (of each element) to calculate the % contribution of each\n",
-    "            e=label_real[circle]==u_ele_real[m]                                # seperation of the elements\n",
-    "            z_circle=z_real[circle]                                            # only selec the atoms with circle constraint\n",
-    "            z_p=z_circle[e]                                                    # only select the atoms wth circle constraint of specific element\n",
-    "            c_circle=c_real[circle]\n",
-    "            c_p=c_circle[e]\n",
-    "            for j in range (0,int((z_end-z_start)/inter)+1):                     # loop of intervals\n",
-    "                init=z_p>=z_start+j*inter                                      # starting condition of interval for each element\n",
-    "                init_all=z_circle>=z_start+j*inter                             # starting condition of interval for all elements together\n",
-    "                z_all2=z_circle[init_all]                                      # selecting atoms which fulfill starting constraint for all elements\n",
-    "                z_p2=z_p[init]                                                 # selecting atoms which fulfill the starting constraint for each individual element\n",
-    "                init2=z_p2<=z_start+(j*inter+inter)                            # ending constraint of interval\n",
-    "                init2_all=z_all2<=z_start+(j*inter+inter)                      # ending constraint of interval for all elements\n",
-    "                z_all3=z_all2[init2_all]                                       # selecting atoms which also fulfill ending constraint for all elements\n",
-    "                z_p3=z_p2[init2]                                               # selecting atom which also fulfill ending constraint for each individual elements\n",
-    "                Num_all.append(len(z_all3))                                    # append the number of atoms which fulfill both contraints\n",
-    "                Num.append(len(z_p3))                                          # append the number of atoms which fulfill both constraints for each individual element\n",
-    "                plot_z.append(z_start+j*inter)#+inter/2)                       # append the x-coordinate for the concentration plot\n",
-    "            a=np.array(Num,dtype=float)                                        # transform total number of atoms for each individual element into array of floats\n",
-    "            b=np.array(Num_all,dtype=float)                                    # transform total number of atoms into array of floats\n",
-    "            if self.var_switch.get()==1: \n",
-    "                if start_end=='start':b=np.array(Num_all[0])\n",
-    "                last=len(np.array(Num_all))-1    \n",
-    "                if start_end=='end':b=np.array(Num_all[last])\n",
-    "                if b==0:messagebox.showinfo(title='APT_analyzer',message='Reference bulk concentration is 0')\n",
-    "            self.conc=100*np.divide(a,b, out=np.zeros_like(a), where=b!=0)     # calculate concentration, if total amount of atoms == 0, result is 0\n",
-    "            message=message+u_ele_real[m]                                      # append element type into message\n",
-    "            message=message+': maximal value: '                                # add text to message\n",
-    "            message=message+str(round(max(self.conc),2))                            # add maximum of concentration to message\n",
-    "            message=message+' minimal value: '                                 # add text to message\n",
-    "            message=message+str(round(min(self.conc),2))                            # add minimum of concentration to message\n",
-    "            message=message+'\\n'                                               # add line split to message  \n",
-    "            if atom=='all':                                                       # seperate if atom select checkbox 'all' is selected\n",
-    "                if c_p[0]=='#FFFFFF':c_p[0]='#000000'                                        # if color of particles is white change it to black so it can be seen with white background\n",
-    "                self.ax1.plot(plot_z,self.conc,c_p[0],label=u_ele_real[m])                 # plot the concentration of each element individually\n",
-    "                self.print_con2.append(u_ele_real[m])\n",
-    "                self.print_con.append(self.conc)\n",
-    "            elif u_ele_real[m]==atom:                                             # if certain element is selected in checkbox\n",
-    "                if c_p[0]=='#FFFFFF':c_p[0]='#000000'\n",
-    "                self.ax1.plot(plot_z,self.conc,c_p[0],label=u_ele_real[m])                 # only plot selected element from the select atom checkbox\n",
-    "                self.print_con2.append(u_ele_real[m])\n",
-    "                self.print_con.append(self.conc)\n",
-    "        self.print_con2.append('z_cyl')\n",
-    "        plot_z2=plot_z.copy()\n",
-    "        plot_z2=np.array(plot_z2).reshape(np.shape(np.array(self.conc)))\n",
-    "        self.print_con.append(plot_z2)\n",
-    "        self.df_con=pd.DataFrame(np.array(self.print_con).T,columns=self.print_con2)\n",
-    "        self.ax1.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))\n",
-    "        self.ax1.set_title('concentration of elements along cylinder / intervalsize=%1.2f' %inter)\n",
-    "        self.canvas.draw_idle()\n",
-    "        self.message=Text(height = 20,width = 50,relief=FLAT)\n",
-    "        self.message.insert(END, message)\n",
-    "        self.message.configure(state='disabled')\n",
-    "        image_ratio=image_size/2.5\n",
-    "        place_factor=0.2\n",
-    "        place_value=1450-place_factor*(1450-image_ratio*1450)\n",
-    "        self.canvas_all.create_window(place_value,300,window=self.message,tags='message')\n",
-    "        self.conc_check=1\n",
-    "        \n",
-    "        \n",
-    "        \n",
-    "    def calc_excess(self):\n",
-    "        self.plot_exist=0\n",
-    "        self.print_ex=[]\n",
-    "        self.print_ex2=[]\n",
-    "        self.canvas_all.delete('message')  \n",
-    "        atom= self.cb_atom.get()      \n",
-    "        color_zyl=str(self.cb_color.get())\n",
-    "        u_ele_real=self.ele        \n",
-    "        image_size=self.slider_image_size.get()\n",
-    "        image_size=float(image_size)/2\n",
-    "        self.fig.clear()\n",
-    "        self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.5,hspace=0.5,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n",
-    "        self.ax1=self.fig.add_subplot(self.spec[0])\n",
-    "        self.ax1.set_xlabel('z position of cylinder')\n",
-    "        self.ax1.set_ylabel('Total amount of atoms')\n",
-    "        x_real=np.array(self.tip['x'])\n",
-    "        y_real=np.array(self.tip['y'])\n",
-    "        z_real=np.array(self.tip['z'])                             # atoms z coordinatines inversion\n",
-    "        if self.i_plot.get()==1:\n",
-    "            z_real=-z_real\n",
-    "        c_real=np.array(self.tip['colour'])\n",
-    "        label_real=np.array(self.tip['comp'])\n",
-    "        inter=float(self.slider_inter.get()/20)\n",
-    "        height = float(self.height.get())\n",
-    "        alpha = float(self.alpha.get())\n",
-    "        beta = float(self.beta.get())\n",
-    "        r = float(self.radius.get())\n",
-    "        x_pos = float(self.cly_x.get())\n",
-    "        y_pos = float(self.cly_y.get())\n",
-    "        z_pos = float(self.cly_z.get())\n",
-    "        if self.i_plot.get()==1:                                   # cylinder z coordinatines inversion\n",
-    "            z_pos=-z_pos\n",
-    "        z_start=-height/2\n",
-    "        z_end=height/2\n",
-    "        alpha=math.radians(-alpha)                               # transfroms radius into radians\n",
-    "        beta=math.radians(-beta)                                 # - because otherwise it tilts the cylinder in the wrong direction (dont know why)\n",
-    "        ###################   tilt and move zylinder ######################################\n",
-    "        pro=[]\n",
-    "        Z=np.array([x_real-x_pos,y_real-y_pos,z_real-z_pos]).T\n",
-    "        M_ROT1=[(1,      0,                  0     ),            # rotational matrix along the x-direction\n",
-    "                (0,  np.cos(alpha),  -np.sin(alpha)),\n",
-    "                (0,  np.sin(alpha),    np.cos(alpha))]\n",
-    "\n",
-    "        M_ROT2=[(np.cos(beta),      0,       np.sin(beta)),     # rotational matrix along the y-direction\n",
-    "                (0,                  1,            0      ),\n",
-    "                (-np.sin(beta),      0,       np.cos(beta))]\n",
-    "        matrix_l=np.array(M_ROT1).dot(M_ROT2)\n",
-    "        for j in range(0,len(Z)):\n",
-    "                    pro.append(matrix_l.dot(Z[j])) \n",
-    "        Z_new=np.array(pro)\n",
-    "        x_real=Z_new[:,0]\n",
-    "        y_real=Z_new[:,1]\n",
-    "        z_real=Z_new[:,2]\n",
-    "        ######################################################################### \n",
-    "        xy=((x_real)**2+(y_real)**2)**(1/2)\n",
-    "        circle=xy<=r\n",
-    "        for m in range(0,len(u_ele_real)):\n",
-    "            plot_z=[]\n",
-    "            excess=[]\n",
-    "            ex=0\n",
-    "            e=label_real[circle]==u_ele_real[m]               #seperation of the atoms \n",
-    "            z_circle=z_real[circle]\n",
-    "            z_p=z_circle[e]\n",
-    "            c_circle=c_real[circle]\n",
-    "            c_p=c_circle[e]\n",
-    "            for j in range (0,int((z_end-z_start)/inter)+1):\n",
-    "                init=z_p>=z_start+j*inter   \n",
-    "                z_p2=z_p[init]\n",
-    "                init2=z_p2<=z_start+(j*inter+inter)\n",
-    "                z_p3=z_p2[init2]\n",
-    "                ex+=len(z_p3)\n",
-    "                excess.append(ex)\n",
-    "                plot_z.append(z_start+j*inter)#+inter/2)   \n",
-    "            if self.var_norm.get()==1:excess=np.array(excess)/(max(excess))\n",
-    "            if atom=='all':\n",
-    "                if c_p[0]=='#FFFFFF':c_p[0]='#000000'\n",
-    "                self.ax1.plot(plot_z,excess,c_p[0],label=u_ele_real[m])\n",
-    "                excess_save=excess.copy()\n",
-    "                self.print_ex2.append(u_ele_real[m])\n",
-    "                self.print_ex.append(np.array(excess))\n",
-    "            elif u_ele_real[m]==atom:\n",
-    "                if c_p[0]=='#FFFFFF':c_p[0]='#000000'\n",
-    "                self.ax1.plot(plot_z,excess,c_p[0],label=u_ele_real[m]) \n",
-    "                excess_save=excess.copy()\n",
-    "                self.print_ex2.append(u_ele_real[m])\n",
-    "                self.print_ex.append(np.array(excess)) \n",
-    "        self.print_ex2.append('z_cyl')\n",
-    "        plot_z2=plot_z.copy()\n",
-    "        plot_z2=np.array(plot_z2).reshape(np.shape(np.array(excess)))\n",
-    "        self.print_ex.append(plot_z2)\n",
-    "        self.df_ex=pd.DataFrame(np.array(self.print_ex).T,columns=self.print_ex2)\n",
-    "        self.ax1.set_title('Excess (total atom number of elements along cylinder) / intervalsize=%1.2f ' %inter)\n",
-    "        self.ax1.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))\n",
-    "        \n",
-    "        points_ex=self.text_box_ex.get(1.0,END)   # get text from text box\n",
-    "        if points_ex!='\\n':\n",
-    "            points_ex=points_ex.split('\\n')           # split the text into each row\n",
-    "            points_ex=[x for x in points_ex if x!=''] # remove any rows that dont contain information\n",
-    "            XX=[]\n",
-    "            YY=[]\n",
-    "            for i in range(0,len(points_ex)):      # loop over all rows\n",
-    "                    points_inner=points_ex[i].split(',')   # split each row into parts of each coordinates\n",
-    "                    xy2=[]\n",
-    "                    for j in points_inner:               # loop over all values inside row\n",
-    "                        m=j.split('=')                   # isolate actual number\n",
-    "                        xy2.append(m[1])                # save number\n",
-    "                    XX.append(float(xy2[0]))            # save x,y and z coordinate\n",
-    "                    YY.append(float(xy2[1]))\n",
-    "            if len(XX)==4:\n",
-    "                k1=(YY[0]-YY[1])/(XX[0]-XX[1])\n",
-    "                k3=(YY[2]-YY[3])/(XX[2]-XX[3])\n",
-    "                d1=YY[1]-k1*XX[1]\n",
-    "                d3=YY[3]-k3*XX[3]\n",
-    "                x=np.array([-height/2,height/2])\n",
-    "                y1=gerade(np.array(k1),x,np.array(d1))\n",
-    "                y3=gerade(np.array(k3),x,np.array(d3))\n",
-    "                diff=[]\n",
-    "                for i in range(0,len(excess_save)):\n",
-    "                    upper_line=gerade(np.array(k3),plot_z[i],np.array(d3))\n",
-    "                    lower_line=gerade(np.array(k1),plot_z[i],np.array(d1))  \n",
-    "                    diff.append(np.abs((upper_line-excess_save[i])-(excess_save[i]-lower_line)))\n",
-    "                plot_z=np.array(plot_z)\n",
-    "                x_found=plot_z[diff==min(diff)]\n",
-    "                y_excess_u=gerade(np.array(k3),x_found,np.array(d3))\n",
-    "                y_excess_l=gerade(np.array(k1),x_found,np.array(d1))\n",
-    "                excess_atom_value=y_excess_u[0]-y_excess_l[0]\n",
-    "                excess_value=excess_atom_value/(np.pi*r**2)\n",
-    "                self.ax1.plot([x_found,x_found],[y_excess_l,y_excess_u])\n",
-    "                self.ax1.plot(x,y1,color=color_zyl)\n",
-    "                self.ax1.plot(x,y3,color=color_zyl)\n",
-    "                self.ax1.scatter(XX,YY,color='black',marker='x')\n",
-    "                self.ax1.annotate(\" 1\", (XX[0], YY[0]))\n",
-    "                self.ax1.annotate(\" 2\", (XX[1], YY[1]))\n",
-    "                self.ax1.annotate(\" 3\", (XX[2], YY[2]))\n",
-    "                self.ax1.annotate(\" 4\", (XX[3], YY[3]))\n",
-    "                self.output = Text(height = 10,width = 50,relief=FLAT)\n",
-    "                image_ratio=image_size/2.5\n",
-    "                place_factor=0.25\n",
-    "                place_value=650-place_factor*(650-image_ratio*650)\n",
-    "                self.canvas_all.create_window(650,place_value,window=self.output,tags='message')\n",
-    "                message2='Calculated with the following 4 points: \\n'\n",
-    "                message2=message2+'point 1: x = '+str(XX[0])+'   y = '+str(YY[0])+'\\n'\n",
-    "                message2=message2+'point 2: x = '+str(XX[1])+'   y = '+str(YY[1])+'\\n'\n",
-    "                message2=message2+'point 3: x = '+str(XX[2])+'   y = '+str(YY[2])+'\\n'\n",
-    "                message2=message2+'point 4: x = '+str(XX[3])+'   y = '+str(YY[3])+'\\n'+'\\n'\n",
-    "                message2=message2+'the interfacial excess atoms = '+str(np.round(excess_atom_value,3))+' atoms'+'\\n'\n",
-    "                message2=message2+'the interfacial excess = '+str(np.round(excess_value,3))+' atoms/nm²'\n",
-    "                self.output.insert(END, message2)\n",
-    "                self.output.configure(state='disabled')\n",
-    "                self.canvas.draw_idle()    \n",
-    "            elif len(XX)>=4:messagebox.showinfo(title='APT_analyzer',message='Too many fit points selected. Reduce to 4 points to fit excess.')\n",
-    "        def onclick(event):\n",
-    "            x=np.round(event.xdata,2)\n",
-    "            y=np.round(event.ydata,2)\n",
-    "            self.ax1.scatter(x,y,color='black',marker='x')\n",
-    "            text='x='+str(x)+', y='+str(y)\n",
-    "            self.text_box_ex.insert(END,text)\n",
-    "            self.text_box_ex.insert(END,'\\n')\n",
-    "            self.canvas.draw_idle()   \n",
-    "        if self.diss2==1:self.fig.canvas.mpl_disconnect(self.cid)    \n",
-    "        self.cid=self.fig.canvas.mpl_connect('button_press_event',onclick)\n",
-    "        self.diss2=1\n",
-    "        self.canvas.draw_idle()  \n",
-    "        self.excess_check=1\n",
-    "                    \n",
-    "    def calc_zoom(self):     \n",
-    "        self.plot_exist=0\n",
-    "        self.canvas_all.delete('message')   \n",
-    "        image_size=self.slider_image_size.get()\n",
-    "        image_size=float(image_size)**2\n",
-    "        self.fig.clear()\n",
-    "        self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.5,hspace=0.5,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n",
-    "        self.ax2=self.fig.add_subplot(self.spec[0],projection='3d')\n",
-    "        atom= self.cb_atom.get()\n",
-    "        M = self.slider_res.get()\n",
-    "        SS=self.slider_size.get()\n",
-    "        S=float(SS)/10\n",
-    "        u_ele_real=self.ele\n",
-    "        n=len(np.array(self.tip['x']))\n",
-    "        N_plot=int(50000/(10**M))\n",
-    "        if N_plot==0:N_plot=1\n",
-    "        x_real=np.array(self.tip['x'])\n",
-    "        y_real=np.array(self.tip['y'])    \n",
-    "        z_real=np.array(self.tip['z'])\n",
-    "        if self.i_plot.get()==1:                                # atoms z coordinatines inversion\n",
-    "            z_real = -z_real\n",
-    "        c_real=np.array(self.tip['colour'])\n",
-    "        label_real=np.array(self.tip['comp'])\n",
-    "        height = float(self.height.get())\n",
-    "        alpha = -float(self.alpha.get())\n",
-    "        beta = -float(self.beta.get())\n",
-    "        r = float(self.radius.get())\n",
-    "        x_pos = float(self.cly_x.get())\n",
-    "        y_pos = float(self.cly_y.get())\n",
-    "        z_pos = float(self.cly_z.get())\n",
-    "        if self.i_plot.get()==1:                                # cylinder z coordinatines inversion\n",
-    "            z_pos = -z_pos\n",
-    "        color_zyl=str(self.cb_color.get())\n",
-    "        z_start=-height/2\n",
-    "        z_end=height/2\n",
-    "        alpha=math.radians(alpha)\n",
-    "        beta=math.radians(beta)\n",
-    "        ###################   tilt and move zylinder ######################################\n",
-    "        pro=[]\n",
-    "        Z=np.array([x_real-x_pos,y_real-y_pos,z_real-z_pos]).T\n",
-    "        M_ROT1=[(1,      0,                  0     ),            # rotational matrix along the x-direction\n",
-    "                (0,  np.cos(alpha),  -np.sin(alpha)),\n",
-    "                (0,  np.sin(alpha),    np.cos(alpha))]\n",
-    "\n",
-    "        M_ROT2=[(np.cos(beta),      0,       np.sin(beta)),     # rotational matrix along the y-direction\n",
-    "                (0,                  1,            0      ),\n",
-    "                (-np.sin(beta),      0,       np.cos(beta))]\n",
-    "        matrix_l=np.array(M_ROT1).dot(M_ROT2)\n",
-    "        for j in range(0,len(Z)):\n",
-    "                    pro.append(matrix_l.dot(Z[j])) \n",
-    "        Z_new=np.array(pro)\n",
-    "        x_real=Z_new[:,0]\n",
-    "        y_real=Z_new[:,1]\n",
-    "        z_real=Z_new[:,2]\n",
-    "        #########################################################################   \n",
-    "        xy=((x_real)**2+(y_real)**2)**(1/2)\n",
-    "        circle=xy<=r\n",
-    "        for m in range(0,len(u_ele_real)):\n",
-    "            e=label_real[circle]==u_ele_real[m]               #seperation of the atoms \n",
-    "            z_circle=z_real[circle]\n",
-    "            x_circle=x_real[circle]\n",
-    "            y_circle=y_real[circle]\n",
-    "            c_circle=c_real[circle]\n",
-    "            z_p=z_circle[e]  \n",
-    "            x_p=x_circle[e] \n",
-    "            y_p=y_circle[e]\n",
-    "            c_p=c_circle[e]\n",
-    "            init_plot=z_p>=z_start\n",
-    "            x_pl2=x_p[init_plot]\n",
-    "            y_pl2=y_p[init_plot]\n",
-    "            z_pl2=z_p[init_plot]\n",
-    "            c_pl2=c_p[init_plot]\n",
-    "            init_plot2=z_pl2<=z_end    \n",
-    "            x_pl3=x_pl2[init_plot2]\n",
-    "            y_pl3=y_pl2[init_plot2]\n",
-    "            z_pl3=z_pl2[init_plot2]\n",
-    "            c_pl3=c_pl2[init_plot2]\n",
-    "            if atom=='all':\n",
-    "                c_pl3[c_pl3=='#FFFFFF']='#000000'\n",
-    "                x_N=len(x_real[::N_plot])\n",
-    "                self.ax2.scatter3D(x_pl3[::N_plot],y_pl3[::N_plot],z_pl3[::N_plot],c=c_pl3[::N_plot],label=u_ele_real[m],s=S)\n",
-    "                self.ax2.set_title('number of atoms={:.0f},     1/{:.0f} of all atoms'.format(x_N,N_plot)) \n",
-    "            elif u_ele_real[m]==atom:\n",
-    "                c_pl3[c_pl3=='#FFFFFF']='#000000'\n",
-    "                x_N=len(x_pl3[::N_plot])\n",
-    "                self.ax2.scatter3D(x_pl3[::N_plot],y_pl3[::N_plot],z_pl3[::N_plot],c=c_pl3[::N_plot],label=u_ele_real[m],s=S)\n",
-    "                self.ax2.set_title('number of atoms={:.0f},     1/{:.0f} of all atoms of this type'.format(x_N,N_plot))                  \n",
-    "        if self.var_axis.get()==0: \n",
-    "            #self.ax2.set_title('number of atoms=%i' %x_N)\n",
-    "            self.ax2.set_xlabel('X-axis',fontweight='bold')\n",
-    "            self.ax2.set_ylabel('Y-axis',fontweight='bold')\n",
-    "            self.ax2.set_zlabel('Z-axis',fontweight='bold')\n",
-    "        elif self.var_axis.get()==1:\n",
-    "            self.ax2.set_axis_off()         \n",
-    "        apt.set_axes_equal(self.ax2)   \n",
-    "        self.ax2.legend() \n",
-    "        if self.var_cyl.get()==1:\n",
-    "            x_pos = float(self.cly_x.get())\n",
-    "            y_pos = float(self.cly_y.get())\n",
-    "            z_pos = float(self.cly_z.get())\n",
-    "            height = float(self.height.get())\n",
-    "            alpha = float(self.alpha.get())\n",
-    "            beta = float(self.beta.get())\n",
-    "            r = float(self.radius.get())\n",
-    "            color_zyl=str(self.cb_color.get())\n",
-    "            theta=np.linspace(0,2*np.pi,201)\n",
-    "            z_start=-height/2\n",
-    "            z_end=height/2\n",
-    "            alpha=math.radians(alpha)\n",
-    "            beta=math.radians(beta)\n",
-    "        \n",
-    "            y_circle=r*np.cos(theta)\n",
-    "            x_circle=r*np.sin(theta)\n",
-    "            z_circle_s=np.ones(201)*z_start\n",
-    "            z_circle_e=np.ones(201)*z_end\n",
-    "\n",
-    "            x_line1=np.ones(201)*r\n",
-    "            x_line2=np.ones(201)*-r\n",
-    "            y_line=np.ones(201)*0\n",
-    "            z_line=np.linspace(z_start,z_end,201)\n",
-    "            lw=5\n",
-    "            self.ax2.plot(x_line1,y_line,z_line,color_zyl,linewidth=lw)\n",
-    "            self.ax2.plot(x_line2,y_line,z_line,color_zyl,linewidth=lw)\n",
-    "            self.ax2.plot(x_circle,y_circle,z_circle_s,color_zyl,linewidth=lw)  \n",
-    "            self.ax2.plot(x_circle,y_circle,z_circle_e,color_zyl,linewidth=lw) \n",
-    "        self.canvas.draw_idle() \n",
-    "\n",
-    "tk = Tk()                                                                      # tkinter\n",
-    "tk.title(\"APT analyzer\")                                                       # select title of tool\n",
-    "tk.geometry('1100x700')                                                        # select size of tool\n",
-    "tt=APT_analyzer(tk)                                                            # select tool              \n",
-    "tk.mainloop()                                                                  # start tool"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "2b4bf9ed-bc19-456f-99b6-c0cfe5691b57",
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3 (ipykernel)",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.9.12"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/docker/apmtools/Cheatsheet.ipynb b/docker/apmtools/Cheatsheet.ipynb
index cd86404..0ce2bf2 100644
--- a/docker/apmtools/Cheatsheet.ipynb
+++ b/docker/apmtools/Cheatsheet.ipynb
@@ -5,7 +5,7 @@
    "id": "88054eb2",
    "metadata": {},
    "source": [
-    "![FAIRmat](FAIRmat_S.png)"
+    "<img src=\"NOMADOasisLogo.png\" alt=\"Drawing\" style=\"height: 149px;\"/>&emsp;&emsp;<img src=\"FAIRmatNewLogo.png\" alt=\"Drawing\" style=\"height: 149px;\"/>"
    ]
   },
   {
@@ -21,17 +21,44 @@
    "id": "4091c1e2",
    "metadata": {},
    "source": [
-    "The apmtools container offers functionalities to work, i.e. perform data analyses<br>\n",
+    "The apmtools container offers functionalities to work and perform data analyses<br>\n",
     "with reconstructed and ranged datasets from atom probe microscopy experiments.<br>\n",
     "\n",
-    "This container includes two tools for processing of atom probe data:\n",
-    "* The **Leoben APT_analyzer** by Alexander Reichmann et al.\n",
-    "* The **paraprobe-toolbox** by Markus Kühbach et al.\n",
+    "This container includes three tools:\n",
+    "* **APTyzer** by Alexander Reichmann et al. https://github.com/areichm/APTyzer\n",
+    "* **paraprobe-toolbox** by Markus Kühbach et al. https://gitlab.com/paraprobe/paraprobe-toolbox\n",
+    "* **APAV** by Jesse Smith et al. https://gitlab.com/jesseds/apav\n",
     "\n",
-    "Each tool comes with a tutorial-style example.\n",
+    "Each tool comes shipped with tutorial-style examples.\n",
     "***"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "id": "e7afeb96-16a6-4d5a-9986-7aacfc9980f4",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "<div class=\"alert alert-block alert-info\">\n",
+    "Having APTyzer, APAV, and paraprobe-toolbox configured in one container comes with the benefit<br>\n",
+    "that one can switch between using these tools or couple them together via an e.g. jupyter notebook.\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fd044275-1ce9-4fea-bbe8-9903c3620a18",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "<div class=\"alert alert-block alert-info\">\n",
+    "Containers of the Nomad Remote Tools Hub (NORTH) are configured such that they have access to the data in the uploads section of the Oasis instance.<br>\n",
+    "Individual examples which exemplify how to use the tools in the apmtools container may have to be unpacked/decompressed before their first use.\n",
+    "</div>"
+   ]
+  },
   {
    "cell_type": "markdown",
    "id": "69238a64",
@@ -39,29 +66,31 @@
     "tags": []
    },
    "source": [
-    "# Getting started with the Leoben APT_analyzer"
+    "# Getting started with APTyzer"
    ]
   },
   {
    "cell_type": "markdown",
-   "id": "6e324fa1",
+   "id": "4aa12615-4734-4802-b6b9-407d6f1797bd",
    "metadata": {},
    "source": [
-    "The Leoben APT_analyzer is a Python-based tool with a GUI which can be used to display tomographic<br>\n",
-    "reconstructions for performing composition and interfacial excesses analyses. The tool is maintained<br>\n",
-    "by Alexander Reichmann at the Montanuniversität Leoben.<br>\n",
-    "\n",
-    "First you should navigate into the respective directory of the tool.<br>"
+    "<div class=\"alert alert-block alert-info\">\n",
+    "Computational requirements: Examples with dataset with a few million ions like most used below should be processable even on a computer with a single core and say at least 4GB main memory.\n",
+    "</div>"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "5fd98af7",
+   "cell_type": "markdown",
+   "id": "6e324fa1",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "! cd /home/atom_probe_tools/leoben_apt_analyzer"
+    "APTyzer is a Python-based tool with a graphical user interface (GUI) which can be used for displaying of a tomographically<br>\n",
+    "reconstructed atom probe dataset thus enabling composition and interfacial excesses analyses. APTyzer can also be used for<br>\n",
+    "preparing the meshing of single interface patches (grain or phase boundaries) via setting control points manually.<br>\n",
+    "These points can be exported and loaded with the paraprobe-toolbox. APTyzer is maintained by Alexander Reichmann,<br>\n",
+    "who is a PhD student with Lorenz Romaner at the Montanuniversität Leoben, Austria.<br>\n",
+    "\n",
+    "To use the tool you should navigate into the respective sub-directory.<br>"
    ]
   },
   {
@@ -69,7 +98,17 @@
    "id": "1aa22278",
    "metadata": {},
    "source": [
-    "### Step 1: Enter the leoben_apt_analyzer sub-directory via the explorer panel on the left side"
+    "### Step 1: Navigate into the respective sub-directory via the explorer panel on the left side"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5fd98af7",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "! cd /home/atom_probe_tools/aptyzer"
    ]
   },
   {
@@ -77,7 +116,7 @@
    "id": "cc1408cc-45ec-40c6-90cb-dcec5f900619",
    "metadata": {},
    "source": [
-    "### Step 2: Download an example dataset to get started with the leoben_apt_analyzer"
+    "### Step 2: Download and unpack an example dataset to get started"
    ]
   },
   {
@@ -87,7 +126,23 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "! cd /home/atom_probe_tools/leoben_apt_analyzer && wget https://www.zenodo.org/record/6794809/files/aut_leoben_leitner.tar.gz && tar -xvf aut_leoben_leitner.tar.gz"
+    "! cd /home/atom_probe_tools/aptyzer && wget https://www.zenodo.org/record/6794809/files/aut_leoben_leitner.tar.gz && tar -xvf aut_leoben_leitner.tar.gz"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1d7b6c36-5967-46be-835d-3678c4ef8865",
+   "metadata": {},
+   "source": [
+    "### Step 3: Start APTyzer by executing the APT_analyzer.ipynb in a new browser tab"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "65cc8b4d-3f83-49fd-94f8-4309852499de",
+   "metadata": {},
+   "source": [
+    "Open the aptyzer.ipynb via the JupyterLab side bar (on the left side). Clicking through this notebook will start the graphical user interface."
    ]
   },
   {
@@ -95,7 +150,6 @@
    "id": "8cea07f1-ccc5-40f4-881a-f9fec8a3f206",
    "metadata": {},
    "source": [
-    "### Step 3: Start the apt_analyzer by executing the leoben_apt_analyzer.ipynb in a new browser tab\n",
     "### Step 4: Run the tool using the POS and RRNG with the aut_leoben_leitner example dataset."
    ]
   },
@@ -104,13 +158,13 @@
    "id": "051121d5-f318-42a7-81d8-a11349401e4c",
    "metadata": {},
    "source": [
-    "There is a detailed tutorial (cheatsheet.pdf) for the APT_analyzer in the sub-directory of the tool.<br>\n",
-    "\n",
-    "The APT_analyzer enables to export manually selected control points to support building computational<br>\n",
-    "geometry models of interfaces. These control points can be exported to an HDF5 file and this file be<br>\n",
-    "used as input for the paraprobe-toolbox. Specifically, the control points can be used to instruct<br>\n",
-    "paraprobe-nanochem to attempt an automatic modelling of an interface.\n",
-    "\n",
+    "There is a detailed tutorial (tutorial.pdf) how to use APTyzer for arbitary datasets. The tool offers export functionalities<br>\n",
+    "for manually selected control points to support building computational geometry models of interfaces.<br>\n",
+    "These control points can be exported to an HDF5 file and this file can be used for example as input for the<br>\n",
+    "paraprobe-nanochem tool from the paraprobe-toolbox.<br>\n",
+    "A respective tutorial how to achieve this is available in the paraprobe-toolbox teaching material<br>\n",
+    "and here specifically the aut_leoben_leitner example. This tutorial will show how to use the<br>\n",
+    "control points and create an automatically meshed model for an interface in the dataset.<br>\n",
     "***"
    ]
   },
@@ -124,20 +178,42 @@
     "# Getting started with paraprobe-toolbox"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "id": "144832aa-b357-406c-84ad-d410d27bd8c0",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "<div class=\"alert alert-block alert-info\">\n",
+    "Computational requirements: Examples with dataset with a few million ions like most used below should be processable even on a computer with a single core<br>\n",
+    "and four GB main memory. Having multiple CPU cores can be useful as the tools of the paraprobe-toolbox use multi-threading for most of the<br>\n",
+    "numerical and geometrical analyses.<br>\n",
+    "Making guarantees about the maximum data set sizes (in terms of number of ions) is difficult as it strongly depends on which type of analyses are performed<br>\n",
+    "and how these are parameterized. Noteworthy to mention is that even the largest examples at the time of writing this cheatsheet which are available in the<br>\n",
+    "paraprobe-toolbox were processable with a laptop with 32GB main memory in total. Examples with a few million ions consumed not more than one to eight GB.<br>\n",
+    "</div>"
+   ]
+  },
   {
    "cell_type": "markdown",
    "id": "ec70f493",
    "metadata": {},
    "source": [
-    "The paraprobe-toolbox is a collection of software tools for applying computational geometry tasks on tomographic<br>\n",
-    "reconstructions of atom probe data to extract and characterize microstructural features. The tool is developed<br>\n",
-    "by <a href=\"https://arxiv.org/abs/2205.13510\">Markus Kühbach et al.</a>. The tool is instructed via a jupyter notebook which documents a script of analysis steps.<br>\n",
+    "The paraprobe-toolbox is a collection of software tools for applying computational geometry tasks on point cloud data<br>\n",
+    "such as tomographic reconstructions of atom probe data to extract and characterize microstructural features.<br>\n",
+    "The tool is developed by <a href=\"https://arxiv.org/abs/2205.13510\">Markus Kühbach et al.</a>. The tool is instructed via a jupyter notebook which documents<br>\n",
+    "how to chain via scripting different analysis steps. Apart from this, it is possible to use the tools via<br>\n",
+    "Python scripting to perform e.g. batch processing on computer clusters.<br>\n",
     "\n",
-    "During the workflow atom probe data are processable with multiple computational steps.<br>\n",
-    "Each step uses a different scientific speciality tool. These use CPU parallelization and performance libraries.<br>\n",
-    "The jupyter notebooks enable users to script the steps of the workflow to automate many steps of the<br>\n",
-    "data analysis in a reproducible and documented way including iso-surface computations, parameter<br>\n",
-    "studies, mesh processing, and writing reports or creating plots automatically.<br>"
+    "Tools of the paraprobe-toolbox are chained into computational workflows. Each step uses a different scientific<br>\n",
+    "speciality tool. All these tools have *paraprobe* as a prefix in their executable name.<br>\n",
+    "The tools use CPU parallelization and specific libraries of the computational geometry or other specialists'<br>\n",
+    "communities. The jupyter notebooks enable users to achieve a complete automation of their<br>\n",
+    "data analyses (if this is desired). Internally, each tools keeps track of input and output files via<br>\n",
+    "hashes and time stamps to enable provenance tracking and support repeatable and reproducible research.<br>\n",
+    "All results are openly accessible and documented via so-called <a href=\"https://fairmat-experimental.github.io/nexus-fairmat-proposal\">NeXus application definitions (see the NORTH/apmtools pages).</a><br>\n",
+    "Such workflows can include parameter studies, mesh processing, writing of reports, and creation of plots.<br>"
    ]
   },
   {
@@ -147,14 +223,16 @@
     "tags": []
    },
    "source": [
-    "### Step 1: Enter the paraprobe-toolbox/teaching/example_analyses sub-directory using the jupyter explorer panel to the left."
+    "### Step 1: Enter the paraprobe-toolbox/teaching/example_analyses sub-directory via the explorer panel to the left."
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
    "id": "f6461c64-cbcd-4d0a-8be3-850205382a71",
-   "metadata": {},
+   "metadata": {
+    "tags": []
+   },
    "outputs": [],
    "source": [
     "# analysis results are stored here:\n",
@@ -170,13 +248,11 @@
    "id": "bce1299f-24fb-4ffc-99d3-99aac8921136",
    "metadata": {},
    "source": [
-    "Reconstruction and ranging data (i.e. POS, ePOS, APT, RNG, RRNG, NXS) to be consumed by paraprobe should be stored in *teaching/example_data*<br>\n",
-    "Analyses with relevant IPYNB jupyter notebooks should be stored in *teaching/example_analyses*\n",
+    "Reconstruction and ranging data (i.e. POS, ePOS, APT, RNG, RRNG, NXS) to be consumed by paraprobe-toolbox should be stored in *teaching/example_data*.<br>\n",
+    "Analyses with relevant jupyter notebooks should be stored in *teaching/example_analyses*.\n",
     "\n",
-    "**Using NeXus:** the tools have been modified to enable now reading also data from NeXus/HDF5 files\n",
-    "which have been created<br>\n",
-    "with the NXapm application definition (see <a href=\"https://fairmat-experimental.github.io/nexus-fairmat-proposal\">nexus-fairmat-proposal</a> and here specifically<br>\n",
-    "the section about atom probe for more details)."
+    "The tools use NeXus data schemas and HDF5 files. The specification of these files is documented in the so-called<br>\n",
+    "<a href=\"https://fairmat-experimental.github.io/nexus-fairmat-proposal\">nexus-fairmat-proposal</a> (see specifically the NORTH/apmtools pages)."
    ]
   },
   {
@@ -184,15 +260,7 @@
    "id": "670cc82a-2ea2-4a48-bded-793b15e2f58f",
    "metadata": {},
    "source": [
-    "### Step 2: Unpack one of the example datasets or use a NeXus/HDF5 file from your upload section."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "31c88293-1cc5-48dd-9f3a-ada16de9ac65",
-   "metadata": {},
-   "source": [
-    "Individual examples have to be unpacked/decompressed before you can use them.<br>"
+    "### Step 2: Unpack the example datasets or use a NeXus/HDF5 file from your uploads section."
    ]
   },
   {
@@ -202,7 +270,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "! cd /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/usa_portland_wang && tar -xvf usa_portland_wang.tar.gz"
+    "! cd /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/usa_portland_wang && tar -xvf usa_portland_wang.tar.gz\n",
+    "! cd /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/aut_leoben_leitner && tar -xvf aut_leoben_leitner.tar.gz"
    ]
   },
   {
@@ -210,15 +279,15 @@
    "id": "c409e217-e14a-4bba-a07e-e16753288bd8",
    "metadata": {},
    "source": [
-    "Alternatively, **If you have already a NeXus/HDF5 file in your upload section you can also use this file.**<br>\n",
-    "In order to do so you can move that file into one of the example_data analysis section inside<br>\n",
-    "the container. This works because the container is configured such that the directory which<br>\n",
-    "represents the upload section is mounted into the container and accessible via the config section.<br>"
+    "Alternatively, NeXus/HDF5 files in your uploads section can also be used. In order to do so, you can move<br>\n",
+    "the respective file(s) into one of the example_data analysis sections inside the container.<br>\n",
+    "This works because the container is configured such that the directory which represents<br>\n",
+    "the uploads section is mounted into the apmtools container and is accessible via config directory.<br>"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": null,
    "id": "22c54c6b-fe0d-4e47-9247-4d5f42761134",
    "metadata": {},
    "outputs": [],
@@ -231,7 +300,7 @@
    "id": "4fa357bd-7e4a-4c78-afeb-cc4debe34f48",
    "metadata": {},
    "source": [
-    "### Step 3: Explore the usage of the tool via jupyter notebooks. Start with the unpacked example usa_portland_wang."
+    "### Step 3: Start with the unpacked example usa_portland_wang."
    ]
   },
   {
@@ -239,8 +308,15 @@
    "id": "8c8865e7-70e9-4309-93c3-5eaf73e2d2e0",
    "metadata": {},
    "source": [
-    "Each example comes with a detailed jupyter notebook which guides through the analysis. This notebook documents the workflow<br>\n",
-    "and instructs it by orchestrating the interaction between python tools, C/C++ tools, HDF5, and H5Web for visualization."
+    "Each example of the paraprobe-toolbox comes with a detailed jupyter notebook which guides through the analysis.<br>\n",
+    "Especially the usa_portland_wang and the aut_leoben_leitner (see connection to APTyzer tool) examples<br>\n",
+    "show the multi-faceted analysis features of the tools in the paraprobe-toolbox.<br>\n",
+    "These examples show how Python and C/C++ applications work together with NeXus, HDF5, and H5Web<br>\n",
+    "to provide tools which can be flexibly be coupled to other open-source atom probe software and<br>\n",
+    "used to complement analyses which have been achieved with commercial software like APSuite/IVAS.<br>\n",
+    "More complex examples with customizable jupyter notebooks are available in the documentation<br>\n",
+    "of the tool https://paraprobe-toolbox.readthedocs.io/en/latest/.<br>\n",
+    "***"
    ]
   },
   {
@@ -248,11 +324,133 @@
    "id": "80d09ac1-e56d-4923-9ba3-9e869d368a51",
    "metadata": {},
    "source": [
-    "The tool is described in further details in various places https://arxiv.org/abs/2205.13510 and<br>\n",
-    "https://gitlab.com/paraprobe/paraprobe-toolbox <br>\n",
-    "The notebooks exemplify how individual tools of the toolbox interact.\n",
+    "# Getting started with APAV"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bfec8daa-59c3-47b9-a0af-8f03afd5c9a6",
+   "metadata": {},
+   "source": [
+    "<div class=\"alert alert-block alert-info\">\n",
+    "Computational requirements: Examples with dataset with a few million ions like most used below should be processable even on a computer with a single core and say at least 4GB main memory.<br>\n",
+    "Having multiple CPU cores can be useful as APAV uses multi-threading for some costly numerical analyses.\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c10fcef1-e82f-4400-af22-f6df70687faf",
+   "metadata": {},
+   "source": [
+    "APAV (Atom Probe Analysis and Visualization) is a Python package for analysis and visualization of atom probe tomography datasets.<br>\n",
+    "The tool is developed by <a href=\"https://joss.theoj.org/papers/10.21105/joss.04862\">Jesse Smith et al.</a>. Complementary to the design of the paraprobe-toolbox functionalities,<br>\n",
+    "APAV can be chained into workflows via e.g. a jupyter notebook. A particular functional strength and focus of APAV<br>\n",
+    "has been ranging and handling of so-called multi-hit events via a graphical user interface via Python.<br>\n",
+    "\n",
+    "APAV has a detailed documentation https://apav.readthedocs.io/en/latest/index.html."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b75f60d5-3151-4986-9222-ddaeb1fa7e5f",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "<div class=\"alert alert-block alert-info\">\n",
+    "Jesse Smith has also made available example data which can be used for learning the multi-hit event analyses capabilities of APAV. If these files are not available <a href=\"https://doi.org/10.5281/zenodo.6794809\">via this Zenodo repository (version >9)</a>,<br>\n",
+    "users are requested to inspect the respective file share location from the revision of the APAV JOSS paper <a href=\"https://github.com/openjournals/joss-reviews/issues/4862\">see the comment from jdasm from November 30, 2022 here</a><br>\n",
+    "The respective GBCO dataset relevant here is especially this one R5038_00333-v02.epos.  <a href=\"https://doi.org/10.1017/S1431927621012794\">Scientific details can be found here</a>.\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f88501b0-a4bd-427d-b303-a45a3556ab35",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### Step 1: Enter the apav sub-directory via the explorer panel to the left."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "474644bb-75fd-4514-bab5-8d9d30e46610",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "! ls /home/atom_probe_tools/apav"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ba59fb6e-2b63-4e95-99f7-75248c2a4f79",
+   "metadata": {},
+   "source": [
+    "### Step 2: Use available files in community-specific formats from your uploads section or download the above-mentioned examples from APAV."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f65c621e-05f5-45ca-9a01-4cbd3206bc55",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "The APAV documentation details which formats are supported."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "9e3fb02c-1706-4864-a27c-06aaadc5c11b",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### Step 3: Start a new jupyter-notebook and use it to compose your own analysis workflow."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "57c641c2-748c-4c8a-a2f1-4d9428f141a5",
+   "metadata": {},
+   "source": [
+    "The APAV documentation can support you with starting your own analyses.\n",
     "***"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a27bbf75-8a2a-4df3-8096-f942afc5e656",
+   "metadata": {},
+   "source": [
+    "# Version, funding, feedback\n",
+    "* **APTyzer** https://github.com/areichm/APTyzer 887b82f\n",
+    "* **paraprobe-toolbox** https://gitlab.com/paraprobe/paraprobe-toolbox 78a394dc\n",
+    "* **APAV** https://pypi.org/project/APAV v1.4.0\n",
+    "* **NeXus** https://fairmat-experimental.github.io/nexus-fairmat-proposal latest\n",
+    "\n",
+    "Last revision: Markus Kühbach, 2023/04/17\n",
+    "\n",
+    "<a href=\"https://www.fairmat-nfdi.eu/fairmat/\">FAIRmat</a> is a consortium on research data management which is part of the German NFDI.<br>\n",
+    "The project is funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) – project 460197019.\n",
+    "\n",
+    "If you spot issues with this container or you would like to suggest how we can improve the apmtools container:<br>\n",
+    "Please contact the respective maintainer of this container."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ff8b1235-d4c8-4ce0-9013-d1d87b7191df",
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
@@ -271,7 +469,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.12"
+   "version": "3.9.16"
   }
  },
  "nbformat": 4,
diff --git a/docker/apmtools/Dockerfile b/docker/apmtools/Dockerfile
index 559ea7f..b073c41 100644
--- a/docker/apmtools/Dockerfile
+++ b/docker/apmtools/Dockerfile
@@ -1,7 +1,7 @@
 # recipe to create the nomad-remote-tools-hub apmtools container via a dockerfile
 FROM gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/webtop
 
-# # for testing the container locally without running in oauth errors
+# for testing the container locally without running in oauth errors
 # FROM ghcr.io/linuxserver/webtop:amd64-ubuntu-openbox-version-e1079163
 # # found that newest system python is 3.8.something
 # # rest should come only from and be managed through (mini)conda not pip!
@@ -16,67 +16,62 @@ FROM gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/webtop
 
 USER root
 
-# query version afterwards like so dpkg -s <packagename> | grep '^Version:'
-# OS dependencies, low-level system libraries
-RUN apt-get update
-RUN apt-get install -y git=1:2.25.1-1ubuntu3.5 \
-  && apt-get install -y m4=1.4.18-4 \
-  && apt-get install -y file=1:5.38-4 \
-  && apt-get install -y wget=1.20.3-1ubuntu2 \
-  && apt-get install -y mesa-common-dev=21.2.6-0ubuntu0.1~20.04.2 \
-  && apt-get install -y libglu1-mesa-dev=9.0.1-1build1 \
-  && apt-get install -y build-essential=12.8ubuntu1.1 \
-  && apt-get install -y mpich=3.3.2-2build1 \
-  && apt-get install -y libgmp-dev=2:6.2.0+dfsg-4 \
-  && apt-get install -y libmpfr-dev=4.0.2-1 \
-  && rm -rf /var/lib/apt/lists/* \
-  && mkdir -p /home \
+RUN mkdir -p /home \
   && mkdir -p /home/atom_probe_tools \
-  && wget https://repo.anaconda.com/miniconda/Miniconda3-py39_4.12.0-Linux-x86_64.sh \
-  && mv Miniconda3-py39_4.12.0-Linux-x86_64.sh miniconda3_py3.9_4.12.0_linux_x86_64.sh \
-  && chmod +x miniconda3_py3.9_4.12.0_linux_x86_64.sh \
-  && bash ./miniconda3_py3.9_4.12.0_linux_x86_64.sh -b -p /usr/local/miniconda3 \
-  && rm -f miniconda3_py3.9_4.12.0_linux_x86_64.sh
+  && mkdir -p /home/atom_probe_tools/apav \
+  && mkdir -p /home/atom_probe_tools/aptyzer
 
-# future improvements should use --no-install-recommends to safe space further, but for mpich this created problems when building paraprobe
+COPY Cheatsheet.ipynb FAIRmatNewLogo.png NOMADOasisLogo.png /home/atom_probe_tools/
+ENV PATH=/usr/local/miniconda3/bin:/home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/cmake/cmake-3.26.3/localinstallation/bin:$PATH
 
-COPY Cheatsheet.ipynb FAIRmat_S.png APT_analyzer.ipynb /home/atom_probe_tools/
-
-# add all relevant environment variables that required for building the 
-# container make sure to reflect eventual changes of the cmake version
-ENV PATH=/usr/local/miniconda3/bin:/home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/cmake/cmake-3.22.2/localinstallation/bin:$PATH
+# query version afterwards like so dpkg -s <packagename> | grep '^Version:'
+# OS dependencies, low-level system libraries, --fix-missing, rm -rf /var/lib/apt/lists/*
+# future improvements should use --no-install-recommends to safe space further, but for mpich this created problems when building paraprobe-toolbox
 
-RUN mkdir -p /home \
+RUN cd ~ \
+  && apt update \
+  && apt install -y curl=7.68.0-1ubuntu2.18 \
+  && curl -sL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh \
+  && chmod +x nodesource_setup.sh \
+  && ./nodesource_setup.sh \
+  && apt install -y nodejs=18.16.0-deb-1nodesource1 \
+  && apt install -y m4=1.4.18-4 file=1:5.38-4 git=1:2.25.1-1ubuntu3.10 wget=1.20.3-1ubuntu2 mesa-common-dev=21.2.6-0ubuntu0.1~20.04.2 libglu1-mesa-dev=9.0.1-1build1 build-essential=12.8ubuntu1.1 mpich=3.3.2-2build1 libgmp-dev=2:6.2.0+dfsg-4ubuntu0.1 libmpfr-dev=4.0.2-1 libssl-dev=1.1.1f-1ubuntu2.17 hwloc=2.1.0+dfsg-4 \
+  && wget https://repo.anaconda.com/miniconda/Miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
+  && mv Miniconda3-py38_23.1.0-1-Linux-x86_64.sh miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
+  && chmod +x miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
+  && bash ./miniconda3-py38_23.1.0-1-Linux-x86_64.sh -b -p /usr/local/miniconda3 \
+  && rm -f miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
   && cd /home \
   && conda config --add channels conda-forge \
   && conda config --set channel_priority strict \
-  && conda install python ipykernel=6.15.3 gitpython=3.1.27 nomkl=1.0 pandas=1.4.4 ase=3.22.1 radioactivedecay=0.4.15 scikit-learn=1.1.2 silx=1.0.0 jupyterlab=3.4.7 nodejs=18.9.0 \
-  && pip install jupyterlab_h5web[full]==6.0.1 \
+  && conda install -c conda-forge nomkl=1.0 jupyterlab-h5web=7.0.0 jupyterlab=3.6.3 hdbscan=0.8.29 gitpython=3.1.31 nodejs=18.15.0 ase=3.19.0 radioactivedecay=0.4.17 pandas=2.0.0 sphinx=6.1.3 \
   && conda clean -afy \
-  && mkdir -p /home/atom_probe_tools \
-  && mkdir -p /home/atom_probe_tools/leoben_apt_analyzer \
-  && git clone https://github.com/areichm/APT_analyzer.git \
-  && cd APT_analyzer \
-  && git checkout 6ee93ca6052c221ae335cbaa2a218911024301fa \
-  && cp APT_analyzer_tutorial.pdf /home/atom_probe_tools/leoben_apt_analyzer/cheatsheet.pdf \
-  && cp /home/atom_probe_tools/APT_analyzer.ipynb /home/atom_probe_tools/leoben_apt_analyzer/leoben_apt_analyzer.ipynb \
-  && cp LICENSE /home/atom_probe_tools/leoben_apt_analyzer/LICENSE \
-  && cp README.md /home/atom_probe_tools/leoben_apt_analyzer/README.md \
-  && cp apt_importers.py /home/atom_probe_tools/leoben_apt_analyzer/apt_importers.py \
-  && cd .. \
-  && rm -rf APT_analyzer \
-  && rm /home/atom_probe_tools/APT_analyzer.ipynb \
+  && cd /home \
+  && python3 -m pip install --upgrade pip \
+  && python3 -m pip install ecdf==0.7.0 pytictoc==1.5.2 ifes-apt-tc-data-modeling==0.0.6 python-docs-theme==2023.3.1 \
+  && cd /home \
+  && cd /home/atom_probe_tools/apav \
+  && python3 -m pip install apav==1.4.0 \
+  && cd /home/atom_probe_tools \
+  && git clone https://github.com/areichm/APTyzer.git \
+  && cd APTyzer \
+  && git checkout 887b82f \
+  && cp APTyzer_V_1_2o.ipynb /home/atom_probe_tools/aptyzer/aptyzer.ipynb \
+  && cp LICENSE /home/atom_probe_tools/aptyzer/LICENSE \
+  && cp README.md /home/atom_probe_tools/aptyzer/README.md \
+  && cp Tutorial_APTyzer_V1_2.pdf /home/atom_probe_tools/aptyzer/tutorial.pdf \
+  && rm -rf /home/atom_probe_tools/APTyzer \
   && cd /home/atom_probe_tools \
   && git clone https://gitlab.com/paraprobe/paraprobe-toolbox.git \
   && cd paraprobe-toolbox \
-  && git checkout b95be8c9e79f044fd8716ffe5d2b7adf4e14208d \
+  && git checkout 78a394dc \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p cmake \
   && cd cmake \
-  && wget https://cmake.org/files/v3.22/cmake-3.22.2.tar.gz \
-  && tar -xvf cmake-3.22.2.tar.gz \
-  && rm -rf cmake-3.22.2.tar.gz \
-  && cd cmake-3.22.2 \
+  && wget https://cmake.org/files/v3.26/cmake-3.26.3.tar.gz \
+  && tar -xvf cmake-3.26.3.tar.gz \
+  && rm -rf cmake-3.26.3.tar.gz \
+  && cd cmake-3.26.3 \
   && mkdir -p localinstallation \
   && chmod +x bootstrap \
   && ./bootstrap --prefix="$PWD/localinstallation/" -- -DCMAKE_USE_OPENSSL=OFF 2>&1 | tee PARAPROBE.CMake.Bootstrap.STDOUTERR.txt \
@@ -85,37 +80,18 @@ RUN mkdir -p /home \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p hdf5 \
   && cd hdf5 \
-  && wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.13/hdf5-1.13.2/src/CMake-hdf5-1.13.2.tar.gz \
-  && gunzip CMake-hdf5-1.13.2.tar.gz \
-  && tar -xvf CMake-hdf5-1.13.2.tar \
-  && rm -rf CMake-hdf5-1.13.2.tar \
-  && cd CMake-hdf5-1.13.2 \
+  && wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.14/hdf5-1.14.0/src/CMake-hdf5-1.14.0.tar.gz \
+  && tar -xvf CMake-hdf5-1.14.0.tar.gz \
+  && rm -rf CMake-hdf5-1.14.0.tar.gz \
+  && cd CMake-hdf5-1.14.0 \
   && ./build-unix.sh 2>&1 | tee PARAPROBE.Hdf5.Build.STDOUTERR.txt \
-  && ./HDF5-1.13.2-Linux.sh --include-subdir --skip-license 2>&1 | tee PARAPROBE.Hdf5.Install.STDOUTERR.txt \
+  && ./HDF5-1.14.0-Linux.sh --include-subdir --skip-license 2>&1 | tee PARAPROBE.Hdf5.Install.STDOUTERR.txt \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p boost \
   && cd boost \
-  && wget https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.gz \
-  && tar -xvf boost_1_80_0.tar.gz \
-  && rm -f boost_1_80_0.tar.gz \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
-  && mkdir -p fftw \
-  && cd fftw \
-  && wget https://www.fftw.org/fftw-3.3.10.tar.gz \
-  && tar -xvf fftw-3.3.10.tar.gz \
-  && rm -f fftw-3.3.10.tar.gz \
-  && cd fftw-3.3.10 \
-  && mkdir -p localinstallation \
-  && ./configure --prefix="$PWD/localinstallation/" --enable-float --enable-sse 2>&1 | tee PARAPROBE.FFTW.Configure.STDOUTERR.txt \
-  && make -j4 2>&1 | tee PARAPROBE.FFTW.Make4.STDOUTERR.txt \
-  && make check 2>&1 | tee PARAPROBE.FFTW.MakeCheck.STDOUTERR.txt \
-  && make install 2>&1 | tee PARAPROBE.FFTW.MakeInstall.STDOUTERR.txt \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
-  && mkdir -p tetgen \
-  && cd tetgen \
-  && tar -xvf tetgen1.6.0.tar.gz \
-  && cd tetgen1.6.0 \
-  && make -j4 tetlib 2>&1 | tee PARAPROBE.TetGen.Make4.STDOUTERR.txt \
+  && wget https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz \
+  && tar -xvf boost_1_81_0.tar.gz \
+  && rm -f boost_1_81_0.tar.gz \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p eigen \
   && cd eigen \
@@ -125,80 +101,54 @@ RUN mkdir -p /home \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p cgal \
   && cd cgal \
-  && wget https://github.com/CGAL/cgal/releases/download/v5.5/CGAL-5.5.tar.xz \
-  && tar -xvf CGAL-5.5.tar.xz \
-  && rm -f CGAL-5.5.tar.xz \
+  && wget https://github.com/CGAL/cgal/releases/download/v5.5.2/CGAL-5.5.2.tar.xz \
+  && tar -xvf CGAL-5.5.2.tar.xz \
+  && rm -f CGAL-5.5.2.tar.xz \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p voroxx \
   && cd voroxx \
   && git clone https://github.com/chr1shr/voro.git \
   && cd voro \
   && git checkout 56d619faf3479313399516ad71c32773c29be859 \
-  && cd .. \
-  && mv voro voro++-0.4.6 \
   && cd /home/atom_probe_tools/paraprobe-toolbox \
-  && sed -i 's|set(MYPROJECTPATH "<<YOURPATH>>")|set(MYPROJECTPATH \"'"$PWD"'\/\")|g' /home/atom_probe_tools/paraprobe-toolbox/code/PARAPROBE.Dependencies.cmake \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-utils/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-utils/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-ranger/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-ranger/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && cp paraprobe_ranger /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_ranger \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-surfacer/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-surfacer/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && cp paraprobe_surfacer /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_surfacer \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-distancer/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-distancer/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && cp paraprobe_distancer /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_distancer \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-tessellator/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-tessellator/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && cp paraprobe_tessellator /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_tessellator \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-nanochem/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-nanochem/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && cp paraprobe_nanochem /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_nanochem \
-  && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-intersector/build \
-  && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-intersector/build \
-  && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \
-  && make -j4 \
-  && cp paraprobe_intersector /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_intersector \
-  && chmod +x /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_* \
+  && sed -i 's|set(MYPROJECTPATH "<<YOURPATH>>/paraprobe-toolbox")|set(MYPROJECTPATH \"'"$PWD"'\/\")|g' code/PARAPROBE.Dependencies.cmake \
   && cd /home/atom_probe_tools/paraprobe-toolbox \
-  && rm -f PARAPROBE.Step*.sh \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-clusterer \
+  && chmod +x PARAPROBE.Step05.Build.Tools.sh \
+  && ./PARAPROBE.Step05.Build.Tools.sh \
+  && chmod +x PARAPROBE.Step06.Install.Tools.sh \
+  && ./PARAPROBE.Step06.Install.Tools.sh \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/boost \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/cgal \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/chrono \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/eigen \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/hdf5 \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/hornus2017 \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/lewiner2002 \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/voroxx \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-utils/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-ranger/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-selector/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-surfacer/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-distancer/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-tessellator/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-spatstat/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-nanochem/build \
+  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-intersector/build \
   && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-crystalstructure \
   && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-miscellaneous \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-spatstat \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/ \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_analyses/aus_sydney_rielli_primig \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_analyses/aut_leoben_mendez_martin \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_analyses/ger_berlin_kuehbach_fairmat \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/aus_sydney_rielli_primig \
-  && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/aut_leoben_mendez_martin \
   && chown -R ${PUID}:${PGID} /home \
   && chown -R ${PUID}:${PGID} /usr/local/miniconda3
 
+# all rm -rf statements should only be used during container build when we do not like
+# to have a version which can be recompiled inside the container
 # as the entire C/C++ executables for all thirdparty dependencies are linked
-# statically the entire thirdparty/mandatory can be deleted
+# statically the entire thirdparty/mandatory is deleted during the container build
+# which  freezes the state of each paraprobe tool but has the disadvantage that the
+# tools can then not be recompiled from inside the container
 
 COPY 02-exec-cmd /config/custom-cont-init.d/02-exec-cmd
 
 ENV HOME=/home/atom_probe_tools
 WORKDIR $HOME
 
-# further optimization for the future could be to copy the content from conda bin and lib over like done in
-# https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/-/blob/develop/docker/nionswift/Dockerfile
-# but there might be more low level dependencies from h5web so this is currently not used
-
-# for running this container standalone e.g.
-# docker run -p 3000:8888 <<imagename>>
\ No newline at end of file
+# for running this container standalone e.g. docker run -p 3000:8888 <<imagename>>
\ No newline at end of file
diff --git a/docker/apmtools/FAIRmatNewLogo.png b/docker/apmtools/FAIRmatNewLogo.png
new file mode 100644
index 0000000000000000000000000000000000000000..aba8697486c07a914800f7519a978306e12d5637
GIT binary patch
literal 24588
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
Hu0mjf!SIX5

literal 0
HcmV?d00001

diff --git a/docker/apmtools/FAIRmat_S.png b/docker/apmtools/FAIRmat_S.png
deleted file mode 100644
index 43c597e6f09d0850fd1b7c646a481d7c8f0ef3f4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 6890
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

diff --git a/docker/apmtools/NOMADOasisLogo.png b/docker/apmtools/NOMADOasisLogo.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5f82fd462e34ef25e8e93ba6aa834a212d001dc
GIT binary patch
literal 12991
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
B-E;r|

literal 0
HcmV?d00001

diff --git a/tools.json b/tools.json
index f416bd9..047db2d 100644
--- a/tools.json
+++ b/tools.json
@@ -134,7 +134,7 @@
     },
     "apmtools": {
         "short_description": "An example for analyzing atom probe data.",
-        "description": "Miscellaneous tools from the atom probe community:\nCurrently the Leoben APT_analyzer and the paraprobe-toolbox.",
+        "description": "Miscellaneous tools from the atom probe community:\nCurrently APTyzer, paraprobe-toolbox, and APAV.\nA JupyterLab instance will start which has a detailed Cheatsheet notebook for getting started.",
         "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/apmtools-webtop",
         "privileged": true,
         "icon": "jupyter_logo.svg",
@@ -148,7 +148,7 @@
     },
     "fiji": {
         "short_description": "ImageJ and Fiji for image processing",
-        "description": "ImageJ and Fiji with amongst others several electron-microscopy specific plug-ins",
+        "description": "ImageJ and Fiji with amongst others several electron-microscopy specific plug-ins.\nA JupyterLab instance will start which has a detailed Cheatsheet notebook for getting started.",
         "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/fiji-webtop",
         "privileged": true,
         "icon": "jupyter_logo.svg",
@@ -162,7 +162,7 @@
     },
     "frwr": {
         "short_description": "Inline electron holography by C. Koch",
-        "description": "FRWR3 in-line holography/focus series reconstruction code",
+        "description": "FRWR3 in-line holography/focus series reconstruction code.",
         "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/frwr-webtop",
         "privileged": true,
         "icon": "jupyter_logo.svg",
@@ -176,7 +176,7 @@
     },
     "abtem": {
         "short_description": "Electronic structure supported image simulation for transmission electron microscopy.",
-        "description": "VESTA, GPAW, and abTEM configured in one container for simulating images and diffraction patterns in transmission electron microscopy",
+        "description": "VESTA, GPAW, and abTEM configured in one container for simulating images and diffraction patterns in transmission electron microscopy.\nA JupyterLab instance will start which has a detailed Cheatsheet notebook for getting started.",
         "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/abtem-webtop",
         "privileged": true,
         "icon": "jupyter_logo.svg",
-- 
GitLab


From 5abf70b9fd82c9867d2cfb27ad5945ff1aeb637f Mon Sep 17 00:00:00 2001
From: "markus.kuehbach" <markus.kuehbach@hu-berlin.de>
Date: Fri, 28 Apr 2023 16:41:24 +0200
Subject: [PATCH 2/4] Updated apmtools with consistent ifes library for pre1

---
 docker/apmtools/Dockerfile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docker/apmtools/Dockerfile b/docker/apmtools/Dockerfile
index b073c41..4c2cbcd 100644
--- a/docker/apmtools/Dockerfile
+++ b/docker/apmtools/Dockerfile
@@ -48,7 +48,7 @@ RUN cd ~ \
   && conda clean -afy \
   && cd /home \
   && python3 -m pip install --upgrade pip \
-  && python3 -m pip install ecdf==0.7.0 pytictoc==1.5.2 ifes-apt-tc-data-modeling==0.0.6 python-docs-theme==2023.3.1 \
+  && python3 -m pip install ecdf==0.7.0 pytictoc==1.5.2 ifes-apt-tc-data-modeling==0.0.7 python-docs-theme==2023.3.1 \
   && cd /home \
   && cd /home/atom_probe_tools/apav \
   && python3 -m pip install apav==1.4.0 \
@@ -64,7 +64,7 @@ RUN cd ~ \
   && cd /home/atom_probe_tools \
   && git clone https://gitlab.com/paraprobe/paraprobe-toolbox.git \
   && cd paraprobe-toolbox \
-  && git checkout 78a394dc \
+  && git checkout 7ed2695896b6ace73696ab67b8d922ea6db21fe8 \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p cmake \
   && cd cmake \
-- 
GitLab


From ffd6158ce42ff914009b601d4c9b77e29e6e8ad7 Mon Sep 17 00:00:00 2001
From: "markus.kuehbach" <markus.kuehbach@hu-berlin.de>
Date: Wed, 3 May 2023 11:21:00 +0200
Subject: [PATCH 3/4] bumped ifes_apt_tc_data_modeling to 0.0.8

---
 docker/apmtools/Cheatsheet.ipynb | 24 ++++++++++++++++++++++--
 docker/apmtools/Dockerfile       |  6 +++---
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/docker/apmtools/Cheatsheet.ipynb b/docker/apmtools/Cheatsheet.ipynb
index 0ce2bf2..07614ea 100644
--- a/docker/apmtools/Cheatsheet.ipynb
+++ b/docker/apmtools/Cheatsheet.ipynb
@@ -395,6 +395,26 @@
     "### Step 2: Use available files in community-specific formats from your uploads section or download the above-mentioned examples from APAV."
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f9bf1d28-abff-4628-aaa8-cb61f796e412",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import shutil"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5d092aaf-663d-4ef3-9ac7-5fc6762d785f",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "! cd /home/atom_probe_tools/apav && wget https://www.zenodo.org/record/77885531/files/apm_sprint14_apav_usa_denton_smith.zip && shutil.unpack_archive(\"apm_sprint14_apav_usa_denton_smith.zip\")"
+   ]
+  },
   {
    "cell_type": "markdown",
    "id": "f65c621e-05f5-45ca-9a01-4cbd3206bc55",
@@ -431,7 +451,7 @@
    "source": [
     "# Version, funding, feedback\n",
     "* **APTyzer** https://github.com/areichm/APTyzer 887b82f\n",
-    "* **paraprobe-toolbox** https://gitlab.com/paraprobe/paraprobe-toolbox 78a394dc\n",
+    "* **paraprobe-toolbox** https://gitlab.com/paraprobe/paraprobe-toolbox e349fd3 (v0.4)\n",
     "* **APAV** https://pypi.org/project/APAV v1.4.0\n",
     "* **NeXus** https://fairmat-experimental.github.io/nexus-fairmat-proposal latest\n",
     "\n",
@@ -469,7 +489,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.16"
+   "version": "3.8.16"
   }
  },
  "nbformat": 4,
diff --git a/docker/apmtools/Dockerfile b/docker/apmtools/Dockerfile
index 4c2cbcd..09b9330 100644
--- a/docker/apmtools/Dockerfile
+++ b/docker/apmtools/Dockerfile
@@ -48,7 +48,7 @@ RUN cd ~ \
   && conda clean -afy \
   && cd /home \
   && python3 -m pip install --upgrade pip \
-  && python3 -m pip install ecdf==0.7.0 pytictoc==1.5.2 ifes-apt-tc-data-modeling==0.0.7 python-docs-theme==2023.3.1 \
+  && python3 -m pip install ecdf==0.7.0 pytictoc==1.5.2 ifes-apt-tc-data-modeling==0.0.8 python-docs-theme==2023.3.1 \
   && cd /home \
   && cd /home/atom_probe_tools/apav \
   && python3 -m pip install apav==1.4.0 \
@@ -64,7 +64,7 @@ RUN cd ~ \
   && cd /home/atom_probe_tools \
   && git clone https://gitlab.com/paraprobe/paraprobe-toolbox.git \
   && cd paraprobe-toolbox \
-  && git checkout 7ed2695896b6ace73696ab67b8d922ea6db21fe8 \
+  && git checkout e349fd34d7cfcb4282c2f3f61c69f9e5659f68e6 \
   && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \
   && mkdir -p cmake \
   && cd cmake \
@@ -151,4 +151,4 @@ COPY 02-exec-cmd /config/custom-cont-init.d/02-exec-cmd
 ENV HOME=/home/atom_probe_tools
 WORKDIR $HOME
 
-# for running this container standalone e.g. docker run -p 3000:8888 <<imagename>>
\ No newline at end of file
+# for running this container standalone e.g. docker run -p 3000:8888 <<imagename>>
-- 
GitLab


From 050392186abd739661f7e510456c9d53b4d86dda Mon Sep 17 00:00:00 2001
From: "markus.kuehbach" <markus.kuehbach@hu-berlin.de>
Date: Wed, 3 May 2023 14:37:53 +0200
Subject: [PATCH 4/4] fixed git and libssl-dev after checking successful
 compilation of image on nomad-util.esc mpcdf machine

---
 docker/apmtools/Dockerfile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docker/apmtools/Dockerfile b/docker/apmtools/Dockerfile
index 09b9330..bd71db8 100644
--- a/docker/apmtools/Dockerfile
+++ b/docker/apmtools/Dockerfile
@@ -35,7 +35,7 @@ RUN cd ~ \
   && chmod +x nodesource_setup.sh \
   && ./nodesource_setup.sh \
   && apt install -y nodejs=18.16.0-deb-1nodesource1 \
-  && apt install -y m4=1.4.18-4 file=1:5.38-4 git=1:2.25.1-1ubuntu3.10 wget=1.20.3-1ubuntu2 mesa-common-dev=21.2.6-0ubuntu0.1~20.04.2 libglu1-mesa-dev=9.0.1-1build1 build-essential=12.8ubuntu1.1 mpich=3.3.2-2build1 libgmp-dev=2:6.2.0+dfsg-4ubuntu0.1 libmpfr-dev=4.0.2-1 libssl-dev=1.1.1f-1ubuntu2.17 hwloc=2.1.0+dfsg-4 \
+  && apt install -y m4=1.4.18-4 file=1:5.38-4 git=1:2.25.1-1ubuntu3.11 wget=1.20.3-1ubuntu2 mesa-common-dev=21.2.6-0ubuntu0.1~20.04.2 libglu1-mesa-dev=9.0.1-1build1 build-essential=12.8ubuntu1.1 mpich=3.3.2-2build1 libgmp-dev=2:6.2.0+dfsg-4ubuntu0.1 libmpfr-dev=4.0.2-1 libssl-dev=1.1.1f-1ubuntu2.18 hwloc=2.1.0+dfsg-4 \
   && wget https://repo.anaconda.com/miniconda/Miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
   && mv Miniconda3-py38_23.1.0-1-Linux-x86_64.sh miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
   && chmod +x miniconda3-py38_23.1.0-1-Linux-x86_64.sh \
-- 
GitLab