Gatan | AMETEKSkip to Main Content
No options found

DigitalMicrograph drift data - Fit

Python Script

Fit or filter drift-measurement data measured from stacks in DigitalMicrograph.

Preview

#Script for fitting or filtering drift measurement data
# measured from stacks in GMS. 
#The script overwrites the original data, so be sure 
# to make a copy of the data first (Edit:Duplicate Image)

#Requires Scipy and matplotlib. 
#To install packages like scipy, see instructions in GMS Help:Python:Installation and Configuration:Additional Packages

#Code written by Ben Miller. Last Updated 2020-06

import numpy as np
if (DM.IsScriptOnMainThread() == False):
	print( ' MatplotLib and scipy scripts require to be run on the main thread.',
		'\n Uncheck the "Execute on Background Thread"',
		'checkbox at the bottom of the Script Window' )
	exit()
import scipy
from scipy.optimize import curve_fit
import scipy.signal as ss
import scipy.ndimage.filters as sf
import sys
sys.argv.extend(['-a', ' '])
import matplotlib.pyplot as plt

#User Input Section XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#Accepted FunTypes: 'Poly1' 'Poly3' 'Poly5' 'FilterSG'
#				    'FilterMed' 'FilterSmooth'
#Poly1 is a 1st degree polynomial
#FilterSG is a Savitzky-Golay Filter
#FilterMed is a median filter
#FilterSmooth is a Gaussian Smoothing (lowpass) filter
plot_external = 0
FunType = 'FilterSG'

#Set breakpoints (as a list in brackets) 
# this will filter sections independently
#set breakpoint to just before any sudden (real) jump
bp = []

#Set Filtering Parameters
#filterwindow=1 means window extends 1 pixel on either side: len(window)=3
filterwindow = 4
#savitzky_golay_order=2 means 2nd-order polynomial
savitzky_golay_order = 2
#gauss_sigma=1 means standard deviation for gaussian filter=1
gauss_sigma = 2

#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

#Use front-most image, and get the data as numpy array
Im0 = DM.GetFrontImage()
name0 = Im0.GetName()
data_cal = Im0.GetIntensityScale()  
img0_array = Im0.GetNumArray()#*data_cal
del Im0
#Create new array
img_array = np.copy(img0_array)
num_curves, sizex = img_array.shape
xdata = np.linspace(1, 2, sizex)

#If FunType entered by user is a filter, perform filtering
if FunType.find('Filter')>=0:
	#Define Filter Function Depending on Function Type Specified by User
	if FunType=='FilterSG':
		img_array[:,:]=ss.savgol_filter(img_array,
										filterwindow*2+1,savitzky_golay_order)
	elif FunType=='FilterMed':
		img_array[:,:]=ss.medfilt(img_array, kernel_size=(1,filterwindow*2+1))
	elif FunType=='FilterSmooth':
		img_array[:,:]=sf.gaussian_filter1d(img_array,
								gauss_sigma,axis=1, mode='nearest', truncate=3)
	else: 
		print('\n FunType: ' + FunType + ' is undefined. \n')	
#Otherwise, perform fitting
else:
	#For each breakpoint, fit the data leading up to that breakpoint
	#Add start and end as breakpoints
	bp.append(sizex)
	bp.insert(0,0)
	
	for i, point in enumerate(bp):
		#Skip First breakpoint, which is 0
		if i==0:
			continue 
		bp0=bp[i-1]
		bp1=bp[i]
		#Define Function Depending on Function Type Specified by User
		if FunType=='Poly1':
			def Fun(xvar,avar,bvar):
				return(avar*xvar+bvar)
		elif FunType=='Poly3':
			def Fun(x_var,a_var,b_var,c_var):
				return (a_var*x_var**2+b_var*x_var+c_var)
		elif FunType=='Poly5':
			def Fun(xvar,avar,bvar,cvar,dvar,evar):
				return (avar*xvar**4+bvar*xvar**3+cvar*xvar**2+dvar*xvar+evar)
		else:
			print('\n FunType: ' + FunType + ' is undefined. \n')
		# Fit Data using Function 
		j=0
		while j < num_curves:
			popt, pcov = curve_fit(Fun,xdata[bp0:bp1],img_array[j,bp0:bp1])
			img_array[j,bp0:bp1]=Fun(xdata[bp0:bp1],*popt)
			j+=1	


def plot2centered(ax,data,title,label):
	
	#plot center-lines and data
	ax.axvline(0,color='0.75')
	ax.axhline(0,color='0.75')
	ax.plot(data[0,:],data[1,:], label=label)
	#adjust axes
	limit = 1.1*max(np.linalg.norm(data,axis=0))
	ax.axis('scaled')
	ax.axis([-limit, limit, -limit, limit])
	#add labels
	plt.xlabel('Drift (nm)',fontsize=14)
	plt.ylabel('Drift (nm)',fontsize=14)
	plt.title(title,fontsize=12)
	#display finished plot
	
#Create new image and display it as a lineplot
imageDoc = DM.NewImageDocument("")
img1 = DM.CreateImage(img_array)
newname = (name0+" Fit Using: "+FunType)
img1.SetName(newname)
img1.SetIntensityScale(data_cal) 
imgdsp = imageDoc.AddImageDisplay(img1, 3)
lpdsp=DM.GetLinePlotImageDisplay(imgdsp)
lpdsp.SetSliceDrawingStyle(0, 1)
imageDoc.Show()
del img1

if(plot_external):
	fig, ax = plt.subplots()
	plot2centered(ax,img_array,newname,"Fit Data")
	plot2centered(ax,img0_array,newname,"Original Data")
	ax.legend()
	plt.show()