Code snippets and examples

Useful code blocks to copy+paste

Labelled, kwarped E-k image

Here we load a 2D image, kwarp it (correcting for a tilt offset) and then plot it. The pesto function drawHighSymmetryLabels handles the high symmetry

GM,GX = 0.952,0.673
hv = 48.75

scan = pesto.loadSpectrum("example_data/CII0031New Region2031.ibw",beQuiet=True)
scan = pesto.kwarp(scan,tilt_offset=7.2)

fig,ax=plt.subplots(figsize=(6,5))
ax.set_title("CII0031 ({:.1f}eV HPOL, 20K)".format(hv),y=1.07)
pesto.quickPlot(scan,axis=ax,hv=hv)
ax.set_xlim([-0.6,1.35])
highSymmetryPoints=[["$\overline{\Gamma}$",0],["$\overline{M}$",GM],["$\overline{M}$",-GM]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)
plt.show()
_images/snippets_labelled_Ek.png

E-k image next to its second derivative

import scipy,copy

GK=1.326
GM=1.148
KM=0.663

scan = pesto.kwarp(pesto.loadSpectrum("snippets/TaC0005New Region1005.ibw",beQuiet=True),tilt_offset=21.5,polar_offset=0,beQuiet=True)
hv = 40

fig,axes=plt.subplots(figsize=(11,5),ncols=2)
plt.suptitle("TaC0005 ({}eV HPOL, T=19K)".format(hv))

ax=axes[0]
pesto.quickPlot(scan,axis=ax,hv=hv)
highSymmetryPoints=[["$\overline{\Gamma}$",0],["$\overline{K}$",GK],["$\overline{M}$",GK+KM]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

ax=axes[1]
tempSpectrum=copy.deepcopy(scan)
tempSpectrum['data']=scipy.ndimage.uniform_filter1d(tempSpectrum['data'], 14, 0) #
tempSpectrum['data'] = np.diff(tempSpectrum['data'], n=2,axis=0)
pesto.quickPlot(tempSpectrum,axis=ax,hv=hv,cmax=25,cmin=-25,cmap='gray_r')
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

plt.tight_layout()
plt.show()
_images/snippets_Ek_secondDerivative.png

Labelled constant energy surface

fig,ax = plt.subplots(figsize=(5,5))

PT2_22 = pesto.kwarp(pesto.loadSpectrum("snippets/PtTe20022.zip",beQuiet=True),beQuiet=True)

Ef = 89.9-pesto.ANALYZER_WORKFUNCTION
GK=1.041
Eb = 0

ax.add_patch(matplotlib.patches.RegularPolygon((0,0), numVertices=6, radius=GK, orientation=math.radians(0),linestyle='-',color='tab:blue',fill=False,lw=1))
slice = pesto.getSlice(spectrum=scan_kwarped,axis=0,axisValue=Ef-Eb,sliceIntegration=0.03,normalized=True)
pesto.quickPlot(slice,axis=ax)
ax.set_ylim([-1.2,1.2])
ax.set_title("Eb = {:.1f}eV".format(Eb))

plt.show()
_images/snippets_esurface.png

Or if you want several cuts side by side:

fig,axes = plt.subplots(figsize=(14,5),ncols=3)

PT2_22 = pesto.kwarp(pesto.loadSpectrum("snippets/PtTe20022.zip",beQuiet=True),beQuiet=True)

Ef = 89.9-pesto.ANALYZER_WORKFUNCTION
GK=1.041
Eb = 0

for index,Eb in enumerate([0.0,0.35,0.7]): #Specify which Eb cuts we want
                ax=axes[index]
                ax.add_patch(matplotlib.patches.RegularPolygon((0,0), numVertices=6, radius=GK, orientation=math.radians(0),linestyle='-',color='tab:blue',fill=False,lw=1))
                slice = pesto.getSlice(spectrum=scan_kwarped,axis=0,axisValue=Ef-Eb,sliceIntegration=0.03,normalized=True)
                pesto.quickPlot(slice,axis=ax)
                ax.set_ylim([-1.2,1.2])
                ax.set_title("Eb = {:.1f}eV".format(Eb))

plt.tight_layout()
plt.show()
_images/snippets_multiple_esurfaces.png

Photon energy scans

If the monochromator energy calibration is off but you’ll be content with a simple linear correction, you would do it like this:

scan = pesto.loadSpectrum("scan.ibw")
corrected_hvAxis = [hv*1.0005 for ii,hv in enumerate(scan['Axis'][2])] #Iteratively tweak the scaling factor as needed
scan_warped=pesto.kwarp(scan,corrected_hvAxis=corrected_hvAxis)
pesto.explorer(scan_warped)

You should be able to see in the energy vs.

Here we extract a constant energy surface, and beside it we plot the E-k image integrated over all photon energies. On that image we indicate where the energy surface is taken.

GK=1.041

hvscan = pesto.kwarp(pesto.loadSpectrum("snippets/PBT26New Region2026.ibw"))

# ---- Extract summation of all photon energies
hv_sum_image = pesto.getSlice(hvscan,axis=2,axisValue=66,sliceIntegration=999,beQuiet=True)

# ---- Extract constant binding energy slice
EbSlice=-0.75
eSurface = pesto.getSlice(hvscan,axis=0,axisValue=4.4-EbSlice,sliceIntegration=0.1,beQuiet=True)

fig,axis=plt.subplots(figsize=(12,6),ncols=2)

ax=axis[0]
pesto.quickPlot(eSurface,axis=ax)

#Optional - draw high symmetry lines
ax.axhline(y=0,ls='--')
ax.axhline(y=GK,ls='--')
ax.axhline(y=-GK,ls='--')

#Optional - label high symmetry lines
tform = matplotlib.transforms.blended_transform_factory(ax.transAxes,ax.transData)
ax.text(y=GK,x=1.05,s='$\overline{K}$',va='center', ha='center',transform=tform)
ax.text(y=-GK,x=1.05,s='$\overline{K}$',va='center', ha='center',transform=tform)
ax.text(y=0,x=1.05,s='$\overline{\Gamma}$',va='center', ha='center',transform=tform)

ax.set_ylim([-1.2,1.2])
ax.set_xlim([None,107])

ax=axis[1]
pesto.quickPlot(hv_sum_image,axis=ax,cmax=60000)
ax.set_ylim([3,-0.1])
ax.set_xlim([-1.3,1.3])
ax.axhline(y=-EbSlice,ls='--',color='tab:red')
highSymmetryPoints=[["$\overline{K}$",-GK],["$\overline{\Gamma}$",0],["$\overline{K}$",GK]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

plt.tight_layout()
plt.show()
_images/snippets_hv_surface.png

Sometimes for these scans it can be helpful to normalize. A simple approach to this is to pick a k region where the intensity is supposed to be uniform, and normalize to that. Here the first plot (which can be suppressed) shows in red where the normalization slice is taken:

GK=1.041

hvscan = pesto.kwarp(pesto.loadSpectrum("snippets/PBT26New Region2026.ibw"))

# ---- Extract summation of all photon energies
hv_sum_image = pesto.getSlice(hvscan,axis=2,axisValue=66,sliceIntegration=999,beQuiet=True)
# If the work function defined in SES is not correct, we'll need to shift the Eb scale to bring Ef up to zero

# ---- Extract constant binding energy slice
EbSlice=-0.75
eSurface = pesto.getSlice(hvscan,axis=0,axisValue=4.4-EbSlice,sliceIntegration=0.1,beQuiet=True)

# ---- Extract the line profile we will use for normalization
profile = pesto.getProfile(spectrum=eSurface,samplingAxis='x',yAxisRange=[0.24,0.27],xAxisRange=[0,999],beQuiet=False)
eSurface['dataNormalized']=np.zeros(np.shape(eSurface['data']))

for index,element in enumerate(profile['data']):
                                if element>0: eSurface['dataNormalized'][:,index]=[ii/element for ii in eSurface['data'][:,index]]
                                else: pass
eSurface['data']=eSurface['dataNormalized']


fig,axis=plt.subplots(figsize=(12,6),ncols=2)

ax=axis[0]
pesto.quickPlot(eSurface,axis=ax,cmax=0.25)

#Optional - draw high symmetry lines
ax.axhline(y=0,ls='--')
ax.axhline(y=GK,ls='--')
ax.axhline(y=-GK,ls='--')

#Optional - label high symmetry lines
tform = matplotlib.transforms.blended_transform_factory(ax.transAxes,ax.transData)
ax.text(y=GK,x=1.05,s='$\overline{K}$',va='center', ha='center',transform=tform)
ax.text(y=-GK,x=1.05,s='$\overline{K}$',va='center', ha='center',transform=tform)
ax.text(y=0,x=1.05,s='$\overline{\Gamma}$',va='center', ha='center',transform=tform)

ax.set_ylim([-1.2,1.2])
ax.set_xlim([None,107])

ax=axis[1]
pesto.quickPlot(hv_sum_image,axis=ax,cmax=60000)
ax.set_ylim([3,-0.1])
ax.set_xlim([-1.3,1.3])
ax.axhline(y=-EbSlice,ls='--',color='tab:red')
highSymmetryPoints=[["$\overline{K}$",-GK],["$\overline{\Gamma}$",0],["$\overline{K}$",GK]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

plt.tight_layout()
plt.show()
_images/snippets_hv_surface_normalized.png

Extract arbitrary k-path from a 3D map

import matplotlib.gridspec as gridspec  #Needed for stacking images together
import math

# Define high symmetry points for the cuts to go to/from
# You may find it easier to just provide [kx,ky] coordinate pairs as read off from something like pesto.explorer
GM=0.952
GX=0.673
G = [0,0]
M = [0,GM]
X1=[GX/math.sqrt(2),GX/math.sqrt(2)]
X2=[-GX/math.sqrt(2),GX/math.sqrt(2)]

# Extract the cuts
hidePreviews=False
CII42_GX = pesto.getSliceArbitrary(spectrum = CII42_kwarped,startPoint=G,endPoint=X2,sliceIntegration=0.05,beQuiet=hidePreviews,previewEnergy=43.484)
CII42_XM=pesto.getSliceArbitrary(spectrum = CII42_kwarped,startPoint=X2,endPoint=M,sliceIntegration=0.05,beQuiet=hidePreviews,previewEnergy=43.484)
CII42_MG=pesto.getSliceArbitrary(spectrum = CII42_kwarped,startPoint=M,endPoint=G,sliceIntegration=0.05,beQuiet=hidePreviews,previewEnergy=43.484)

# Stack the cuts together side-by-side

hv = 48.75
fig = plt.figure(figsize=(12.5,6))
gs = gridspec.GridSpec(1, 3, width_ratios=[GX,GX,GM], height_ratios=[1])
gs.update(wspace = 0, hspace = 0)

ax = fig.add_subplot(gs[0])
pesto.quickPlot(CII42_GX,axis=ax,hv=hv)
ax.set_xticks([])
ax.set_ylim([2,-0.1])
ax.set_xlabel("")
highSymmetryPoints=[["$\overline{\Gamma}$",0]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

ax = fig.add_subplot(gs[1])
pesto.quickPlot(CII42_XM,axis=ax,hv=hv)
ax.set_ylabel("")
ax.set_xlabel("")
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylim([2,-0.1])
highSymmetryPoints=[["$\overline{X_2}$",0]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

ax = fig.add_subplot(gs[2])
pesto.quickPlot(CII42_MG,axis=ax,hv=hv)
ax.set_ylabel("")
ax.set_xlabel("")
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylim([2,-0.1])
highSymmetryPoints=[["$\overline{M}$",0],["$\overline{\Gamma}$",CII42_MG['Axis'][1][-1]]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)
plt.show()
_images/snippets_kpath.png

Here’s another example from a hexagonal symmetry sample:

import matplotlib.gridspec as gridspec

scan = pesto.loadSpectrum("example_data/PBT0007.zip",beQuiet=True)
scan_kwarped = pesto.kwarp(scan,beQuiet=True)

hv = 90.33
Ef = hv-pesto.ANALYZER_WORKFUNCTION

GM,GK,KM=0.967,1.117,0.559

G = [0,0]
M1 = [GM/2,(KM+(GK-KM)/2)]
M2 = [GM,0]
K1 = [GM,KM]
K2 = [0,GK]

# Extract the cuts
hidePreviews=False
PBT_GM = pesto.getSliceArbitrary(spectrum = scan_kwarped,startPoint=G,endPoint=M1,sliceIntegration=0.05,beQuiet=hidePreviews,previewEnergy=Ef-0.05)
PBT_MK = pesto.getSliceArbitrary(spectrum = scan_kwarped,startPoint=M2,endPoint=K1,sliceIntegration=0.05,beQuiet=hidePreviews,previewEnergy=Ef-0.05)
PBT_KG = pesto.getSliceArbitrary(spectrum = scan_kwarped,startPoint=K2,endPoint=G,sliceIntegration=0.05,beQuiet=hidePreviews,previewEnergy=Ef-0.05)

fig = plt.figure(figsize=(13,6))
gs = gridspec.GridSpec(1, 3, width_ratios=[GM,KM,GK], height_ratios=[1])
gs.update(wspace = 0, hspace = 0)

ax = fig.add_subplot(gs[0])
pesto.quickPlot(PBT_GM,axis=ax,hv=hv)
ax.set_xticks([])
ax.set_ylim([None,-0.1])
ax.set_xlabel("")
highSymmetryPoints=[["$\overline{\Gamma}$",0]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

ax = fig.add_subplot(gs[1])
pesto.quickPlot(PBT_MK,axis=ax,hv=hv)
ax.set_ylabel("")
ax.set_xlabel("")
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylim([None,-0.1])
highSymmetryPoints=[["$\overline{M}$",0]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)

ax = fig.add_subplot(gs[2])
pesto.quickPlot(PBT_KG,axis=ax,hv=hv)
ax.set_ylabel("")
ax.set_xlabel("")
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylim([None,-0.1])
highSymmetryPoints=[["$\overline{K}$",0],["$\overline{\Gamma}$",scan_kwarped['Axis'][1][-1]]]
pesto.drawHighSymmetryLabels(points=highSymmetryPoints,axis=ax)
plt.show()
_images/snippets_kpath2.png

EDC series from a temperature dependence dataset

# Define what files to use and what temperatures they correspond to
fileIndices=[70,71,72,73,74,75,76,77,78,79,80]
temperatures=[24,57,85,125,155,190,218,247,270,294,330]
fileNames = ["example_data/FGT00{}Ek_1450{}.ibw".format(fileIndex,fileIndex) for fileIndex in fileIndices]

# Load them into memory
spectra = [pesto.kwarp(pesto.loadSpectrum(filename,regionIndex=1,beQuiet=True),tilt_offset=0.7,beQuiet=True) for filename in fileNames]

# Extract EDCs
hv = 145.33
centerK,kWidth = 0.86, 0.1
EbStart,EbEnd = 1.5, -0.2
EkStart = hv-pesto.ANALYZER_WORKFUNCTION-EbStart
EkEnd = hv-pesto.ANALYZER_WORKFUNCTION-EbEnd

EDCs=[pesto.getProfile(spectrum=spectrum,samplingAxis='y',xAxisRange=[centerK-kWidth,centerK+kWidth],yAxisRange=[EkStart,EkEnd],beQuiet=True) for spectrum in spectra]

# Normalize the EDCs to have the same value at high binding energy, and also apply an offset to space out the traces vertically
for index,EDC in enumerate(EDCs):
    EDC['data']-=min(EDC['data'])
    EDC['data']=EDC['data']/EDC['data'][0]
    EDC['data']=EDC['data']-(0.1*index)

# Plot EDC series
fig,ax = plt.subplots(figsize=[6,6])
ax.set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, len(EDCs)))))

for spectrumIndex,EDC in enumerate(EDCs):
    pesto.quickPlot(EDC,axis=ax,hv=hv,lw=1.5,label="{}K".format(temperatures[spectrumIndex]))

ax.set_yticks([])
plt.legend(prop={'size': 9},loc='lower left')
plt.show()

# Plot a few E-k images showing where the EDCs are taken
fig,axes = plt.subplots(figsize=[12,4],ncols=4)
temperaturesToPlot=[24,85,155,218]
indicesToPlot = [pesto.indexOfClosestValue(temperatures,temperatureToPlot) for temperatureToPlot in temperaturesToPlot]

for axisIndex,spectrumIndex in enumerate(indicesToPlot):
    ax = axes[axisIndex]
    pesto.quickPlot(spectrum=spectra[spectrumIndex],axis=ax,hv=hv)
    ax.axvline(x=centerK+kWidth,color='black',ls='--')
    ax.axvline(x=centerK-kWidth,color='black',ls='--')
    ax.set_ylim([1.5,-0.2])
    ax.set_xlim([-0.5,2])
    ax.text(0.93, 0.93, "{}K".format(temperatures[spectrumIndex]), horizontalalignment='right', transform=ax.transAxes)
plt.tight_layout()
plt.show()
_images/snippets_EDC_series.png

Labelled XPS spectra

This uses the ‘XPS=True’ argument of quickPlot to produce the plot, which collapses all angles down. The peak label function simply identifies the highest intensity within the range you have specified.

hv = 460

spectrum = pesto.loadSpectrum("example_data/Cr0007New Region1.ibw",beQuiet=True)
fig,ax=plt.subplots(figsize=(8,5))

pesto.quickPlot(spectrum,axis=ax,hv=hv,XPS=True)

ax.set_xlim([400,-5])
ax.set_ylim([0,1.5e4])

pesto.XPS.addPeakLabel(ax,spectrum,hv,xrange=[50,100],label='Cr3s')
pesto.XPS.addPeakLabel(ax,spectrum,hv,xrange=[250,290],label='C1s')
pesto.XPS.addPeakLabel(ax,spectrum,hv,xrange=[40,45],label='Cr3p')
pesto.XPS.addPeakLabel(ax,spectrum,hv,xrange=[100,120],label='Cr2p (2hv)')

ax.set_title("Cr0007 (hv={:.1f}eV)".format(hv))
plt.show()
_images/snippets_labelled_XPS.png

Compare multiple XPS spectra

Here we are comparing core levels from two different locations on the sample. The quickPlotXPS function is not suitable for more complicated operations like normalizing before plotting, so we need to collapse it down to a 1D trace ourselves with getProfile

scans=[]
scans.append(["Termination 1",pesto.loadSpectrum("example_data/FGT0052XPS_overview052.ibw",beQuiet=True)])
scans.append(["Termination 2",pesto.loadSpectrum("example_data/CII0045XPS_160eV045.ibw",beQuiet=True)])

hv = 160

fig,ax=plt.subplots(figsize=(8,5))

for scan in scans:
        label,spectrum = scan[0],scan[1]
        EDC = pesto.normalize(pesto.getProfile(spectrum=spectrum,samplingAxis='y',xAxisRange=[-15,15],yAxisRange=[0,999],beQuiet=True))
        pesto.quickPlot(EDC,axis=ax,hv=160,label=label)

ax.set_xlabel('Binding energy (eV)')
ax.set_ylabel('Intensity')
ax.legend()
ax.set_xlim([60,25])

pesto.XPS.addPeakLabel(axis=ax,spectrum=EDC,hv=hv,xrange=[50,60],label='Fe3p')
pesto.XPS.addPeakLabel(axis=ax,spectrum=EDC,hv=hv,xrange=[35,45],label='Te4d')

plt.show()
_images/snippets_compare_XPS.png

Contrast image from a spatial map

These code blocks are tedious to generate, so you would typically not do it by hand. Within pesto.explorer you have a button that will automatically generate this for you. After that you just need to make any minor formatting adjustments you like.

from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar

spectrum=scan
scaleBarLength_um=30
point = [-1.045,271.585]
fig,axes=matplotlib.pyplot.subplots(figsize=(9,4),ncols=2)

ax=axes[1]
ROI_Angle,ROI_AngleIntegration = 3.772,1.93
ROI_Energy,ROI_EnergyIntegration = 78.649,0.38
ROI_AngleStart,ROI_AngleStop=ROI_Angle-ROI_AngleIntegration/2,ROI_Angle+ROI_AngleIntegration/2
ROI_EnergyStart,ROI_EnergyStop=ROI_Energy-ROI_EnergyIntegration/2,ROI_Energy+ROI_EnergyIntegration/2
ROI2_Angle,ROI2_AngleIntegration = 0.356,1.93
ROI2_Energy,ROI2_EnergyIntegration = 76.966,0.38
ROI2_AngleStart,ROI2_AngleStop=ROI2_Angle-ROI2_AngleIntegration/2,ROI2_Angle+ROI2_AngleIntegration/2
ROI2_EnergyStart,ROI2_EnergyStop=ROI2_Energy-ROI2_EnergyIntegration/2,ROI2_Energy+ROI2_EnergyIntegration/2

image = pesto.getFrameFrom4DScan(spectrum=spectrum,axes=['X','Y'],axisValues=point)
pesto.quickPlot(image,axis=ax)
ROI=matplotlib.patches.Rectangle((ROI_AngleStart,ROI_EnergyStart), height=ROI_EnergyIntegration, width=ROI_AngleIntegration,linestyle='-',color='tab:red',fill=False)
ax.add_patch(ROI)
ROI2=matplotlib.patches.Rectangle((ROI2_AngleStart,ROI2_EnergyStart), height=ROI2_EnergyIntegration, width=ROI2_AngleIntegration,linestyle='-',color='black',fill=False)
ax.add_patch(ROI2)
axes[0].set_title('Relative intensity (red/black ROI)')
map = pesto.spatialMap__RelativeIntensityContrastImage(spectrum,ROI_Angle,ROI_AngleIntegration,ROI_Energy,ROI_EnergyIntegration,ROI2_Angle,ROI2_AngleIntegration,ROI2_Energy,ROI2_EnergyIntegration)
ax=axes[0]
image=pesto.quickPlot(map,axis=ax,cmap='cividis',returnIm=True)
fig.colorbar(image,ax=ax)
x,y=point[0],point[1]
dx=abs(spectrum['Axis'][2][1]-spectrum['Axis'][2][0])
dy=abs(spectrum['Axis'][3][1]-spectrum['Axis'][3][0])
ax.axvline(x=x,ls='--')
ax.axhline(y=y,ls='--')
ROI=matplotlib.patches.Rectangle((x-(dx/2),y-(dy/2)), height=dy, width=dx,linestyle='-',color='tab:red',fill=False,lw=2)
ax.add_patch(ROI)

scalebar = AnchoredSizeBar(ax.transData,scaleBarLength_um/1000, '{}um'.format(scaleBarLength_um), 'lower right',pad=0.3,color='white',frameon=False,size_vertical=0.003)
ax.add_artist(scalebar)
plt.tight_layout()
plt.show()
_images/snippets_spatialMap.png