Files
nappMATLAB-toolbox/beamtime/nappPlot.m
T
bartels-rausch 00d34110db MAJOR UPDATE: Add support for Specs .xy files from offline XPS (Soleil/Luca)
Both Scienta (.ibw) and SpecsLab (.xy) raw files capture multidimensional XPS data but use different terminology to structure it. Scienta uses "Region Iterations" and "Sequence Iterations". SpecsLab organizes data by "Groups" or "Regions" (different elemental energy sweeps), "Scans" (time-resolved repetitions), and "Curves". Scienta Region Iterations are automatically averaged to improve the signal-to-noise ratio, while Scienta Sequence Iterations and SpecsLab Scans are  preserved to keep the time-resolved data. For SpecsLab files specifically, distinct Regions are split into separate table rows. Ultimately, the preserved time-resolved data is saved in the table's image variable as a 2D matrix ([Energy bins × Sequence iterations/Scans]).

File type handling: Added .xy as a recognized XPS format. Currently, the script differentiates data types strictly by file extension (NEXAFS: .h5, XPS: .ibw and .xy). This extension-based differentiation needs to be improved in future updates.

Metadata parsing: Implemented global header scanning for .xy files to correctly extract instrument parameters (Acquisition Mode, Lens Mode, Slit, Workfunction) located before the first region block.

Timezone alignment: Added timestamp conversion for .xy files from UTC to local time (Europe/Zurich) to ensure synchronization with LabView logs.

Region separation: Modified .xy parsing to append a _RegX suffix to filenames. This correctly splits single .xy files that contain multiple elements or energy sweeps into distinct table rows so they can be processed individually.

Import efficiency: Added an originalFileName variable. The script now cross-references the input DataTable and skips files that have already been imported to reduce execution time on re-runs.

Testing status: Processing of .xy data has currently only been tested and debugged with nappGenerateSpectra and nappPlot. Compatibility with other functions in the suite remains untested.
2026-03-12 10:08:47 +01:00

910 lines
43 KiB
Matlab

function hdl = nappPlot(DataTable,varargin)
%NAPPLOT Plot photoelectron spectra and NEXAFS images from a data table.
% hdl = NAPPLOT(DataTable) creates figures for all rows in DataTable
% using the default visualization options and returns the handle(s) to
% the generated figure(s).
%
% hdl = NAPPLOT(DataTable, tableSelection) restricts plotting to rows for
% which tableSelection is true. The length of tableSelection must
% match the height of DataTable.
%
% hdl = NAPPLOT(DataTable, tableSelection, Name, Value) additionally
% customizes the data source, energy axis, layout mode, and figure
% formatting using Name-Value arguments.
%
% NAPPLOT is a general-purpose visualization routine for spectroscopy
% experiments that can display:
% - NEXAFS images (h5)
% - time-resolved XPS/Auger maps (ibw)
% - 1D spectra from previously generated table variables
% - interactive NEXAFS + Auger-Meitner views
%
% Required input
% --------------
% DataTable
% Table that contains spectroscopy data and metadata.
% Depending on the chosen tableVariable and energyScale, the
% following variables are typically used:
% - name : file name (string/char), used to
% distinguish '.h5', '.ibw', '.xy'
% - image : processed 2D image (cell of numeric)
% - imageRoh : raw 2D image (cell of numeric)
% - spectrum_counts : 1D spectrum (in arbitrary counts
% - spectrum_countsPerSecond
% : 1D spectrum (normalized to counts per second)
% - spectrum_countsNorm : 1D normalized spectrum
% - scientaEkin_eV : kinetic energy axis (cell of numeric)
% - bindingEnergy_eV : binding energy axis (cell of numeric)
% - xRayEkin_eV : photon energy axis (cell of numeric)
% - scientaEkinRange_eV : [emin emax] for plotting
% - xRayEkinRange_eV : [emin emax] for plotting
% - lastModifiedDatestr : acquisition or file time stamp
% - sample : (optional) sample name for titles
%
% Optional positional input
% -------------------------
% tableSelection
% Logical vector selecting rows of DataTable to plot.
% Default: all rows true
%
% Name-Value arguments
% --------------------
% 'tableVariable'
% Name of the variable in DataTable to plot.
% Type : char or string
% Values : 'image' (default)
% 'imageRoh'
% 'spectrum_countsPerSecond'
% 'spectrum_counts'
% 'spectrum_countsNorm'
%
% 'energyScale'
% Energy axis used for plotting
% Type : char or string
% Values : 'kinetic' (default) - use scientaEkin_eV
% 'binding' - use bindingEnergy_eV
% 'xRay' - use xRayEkin_eV
% 'sweeps' - use column/iteration index
%
% 'mode'
% Layout and plotting mode
% Type : char or string
% Values : 'AllInOne' (default)
% - Plot all selected 1D spectra in a single axes
% (overlaid).
% 'OneEach'
% - One figure per single spectrum or image.
% 'iterations'
% - Plot multiple iterations from a 2D stack in different
% colors to show time/sequence evolution.
% 'AugerMeitner'
% - Extract and plot Auger-Meitner spectra at specified
% photon energies for NEXAFS maps ('.h5').
% 'interactive'
% - Interactive layout for NEXAFS images with linked
% Auger-Meitner and NEXAFS line cuts controlled by
% mouse / data cursor callbacks.
%
% 'figureMode'
% Overall figure formatting, size, and font presets.
% Type : char or string
% Values : 'screen' (default)
% - Standard display window in pixels, moderate fonts.
% 'powerpoint'
% - Larger window and fonts optimized for slides.
% 'word'
% - Compact figure in centimeters for documents.
%
% 'plotStep'
% Step size in iteration index for 'iterations' mode.
% Type : positive numeric scalar
% Default: 1 (plot every iteration)
%
% 'AugerMeitnerEnergies'
% Photon energies (in eV) for 'AugerMeitner' mode
% At each value, the function extracts one column from the image and
% plots the corresponding Auger-Meitner electron spectrum.
% Type : numeric vector
%
% Output
% ------
% hdl
% Handle or array of handles to the generated figure(s)
% For 'AllInOne' this is a single figure. For 'OneEach',
% 'iterations', 'AugerMeitner', and 'interactive', hdl may contain
% one handle per processed row.
%
% Notes
% -----
% - The function checks that the chosen tableVariable is non-empty for
% all selected rows and throws an error otherwise.
% - File type is inferred from the 'name' variable to distinguish h5,
% ibw, and xy-type data
% - Axis labels, limits, and titles are adapted automatically based on
% energyScale, tableVariable, and available metadata (sample name,
% time stamp)
% - In 'interactive' mode, datacursor and mouse motion callbacks update
% linked line plots for Auger-Meitner and NEXAFS traces.
%% TODO
%
% TODO: Add averaging in image and in iteration plot
% TODO: Make code nicer (NEXAFS plotting)
% Define conditions and defaults of input
defaultTableVariable = 'image';
expectedTableVariable = {'image','imageRoh','spectrum_countsPerSecond','spectrum_counts','spectrum_countsNorm'};
defaultMode = 'AllInOne';
expectedMode = {'AllInOne','OneEach','iterations','AugerMeitner','interactive'};
defaultFigureMode = 'screen';
expectedFigureMode = {'screen','powerpoint','word'};
defaultEnergyScale = 'kinetic';
expectedEnergyScale = {'kinetic','binding','xRay','sweeps'};
defaultTableSelection = true(size(DataTable,1),1);
defaultPlotStep = 1;
% Parse input
p = inputParser;
addRequired(p,'DataTable',@istable);
addOptional(p,'tableSelection',defaultTableSelection,@islogical);
addParameter(p,'tableVariable',defaultTableVariable,...
@(x) any(validatestring(x,expectedTableVariable)));
addParameter(p,'mode',defaultMode,...
@(x) any(validatestring(x,expectedMode)));
addParameter(p,'figureMode',defaultFigureMode,...
@(x) any(validatestring(x,expectedFigureMode)));
addParameter(p,'energyScale',defaultEnergyScale,...
@(x) any(validatestring(x,expectedEnergyScale)));
addParameter(p,'plotStep',defaultPlotStep);
addParameter(p,'AugerMeitnerEnergies',@isnumeric)
parse(p,DataTable,varargin{:});
if ~all(cell2mat(cellfun(@size,p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable),'UniformOutput',false)),'all')
disp('The table variable appears to be empty. I quit now')
error('The table variable appears to be empty.')
end
% make figure, with options for output.
if contains(p.Results.figureMode ,'screen') % standard
alw = get(groot,'DefaultAxesLineWidth');
fsz = get(groot,'DefaultAxesFontSize');
lw = 2; %get(groot,'DefaultLineLineWidth');
fnt = get(groot,'DefaultAxesFontName');
loc = 'northeastoutside';
unt = 'pixels';
pos = [20 100 800 500];
elseif contains(p.Results.figureMode,'powerpoint')
alw = 2;
fsz = 26;
lw = 4;
fnt = 'Helvetica Neue';
loc = 'northeastoutside';
unt = 'pixels';
pos = [300 200 1280 720];
elseif contains(p.Results.figureMode,'word')
alw = 0.75;
fsz = 10;
lw = 0.5;
fnt = 'Helvetica Neue';
loc = 'southoutside';
unt = 'centimeters';
pos = [8 10 8 10];
end
if matches(p.Results.mode,'AugerMeitner')
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5')
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
if size(p.Results.AugerMeitnerEnergies) >= 7
tmp_color = colormap(parula(size(p.Results.AugerMeitnerEnergies,2)));
else
tmp_color = colormap(lines(size(p.Results.AugerMeitnerEnergies,2)));
end
% Create axes
hold(gca,'on');
for ij = 1:size(p.Results.AugerMeitnerEnergies,2)
% find x-ray energy in data
tmpXrayEnergy = find(p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii} >= p.Results.AugerMeitnerEnergies(ij),1);
hplot= plot( p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}, ...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(:,tmpXrayEnergy));
hplot.LineWidth = lw;
hold on
end
xlabel('Auger-Meitner electron energy [eV]')
hYLabel = ylabel('Counts per dwell time');
legend(string(p.Results.AugerMeitnerEnergies))
end
end
end
if matches(p.Results.tableVariable,'image') && matches(p.Results.mode,'interactive')
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5') % let's do NEXAFS first.
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',[20 100 1000 800]);
tld = tiledlayout(2,2);
tld.TileSpacing = 'compact';
tld.Padding = 'compact';
% image
ax1= nexttile;
img_handle = image(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},'Parent',ax1,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},1)]);
xlim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
hXLabel = xlabel('# Photon energy, column number');
hYLabel = ylabel('# Auger energy, column number');
box(gca,'on');
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
hdl.Pointer = 'crosshair';
ij= 1;
ik=1;
% Auger-Meitner
ax2 = nexttile;
hplot= plot(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(:,ij), p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii});
hplot.LineWidth = lw;
hold on
ylabel('A-M e energy [eV]')
xlabel('Counts per dwell time');
ax2.YDir = 'reverse';
box(ax2,'on');
set( ax2, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , fsz );
set(ax2, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
% NEXAFS
ax3 = nexttile;
hplot2= plot( p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}, ...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(ik,:));
hplot2.LineWidth = lw;
hold on
xlabel('xray energy [eV]')
hYLabel = ylabel('Counts per dwell time');
box(ax3,'on');
set( ax3, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , fsz );
set(ax3, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
if ~matches(p.Results.figureMode,'word')
title(tld,p.Results.DataTable(p.Results.tableSelection,:).name{ii},'Interpreter','none')
end
% % NOW set up datacursor - after all axes are created
dcm = datacursormode(hdl);
set(dcm, 'UpdateFcn', {@updatePlots, p.Results, ii, ax2, ax3, hplot, hplot2});
set(dcm, 'Enable', 'on');
set(dcm, 'SnapToDataVertex', 'off'); % Allows smooth mouse tracking
set(dcm, 'DisplayStyle', 'window'); % or 'datatip' for tooltip style
% Enable continuous update on mouse move
set(hdl, 'WindowButtonMotionFcn', {@mouseMoveFcn, dcm, p.Results, ii, ax2, ax3, hplot, hplot2, ax1});
end
end
end
if matches(p.Results.tableVariable,'image') && ~matches(p.Results.mode,'AugerMeitner') && ~matches(p.Results.mode,'interactive')
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5') % let's do NEXAFS first.
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
if matches(p.Results.energyScale,'sweep')
image(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},1)]);
xlim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
hXLabel = xlabel('# Photon energy, column number');
hYLabel = ylabel('# Auger energy, column number');
else
% Try to plot image with x and y
try
% interpolate, to have equal x spacing for image plot
Xq = p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}(1):0.1:p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}(end);
Vq = interp2(p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii},p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},Xq,p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii});
image(Xq,p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
Vq,'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
xlim([p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}(1) p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}(end)]);
ylim([p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRange_eV(ii,1) p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRange_eV(ii,2)]);
hXLabel = xlabel('Photon energy [eV]');
hYLabel = ylabel('Auger energy [eV]');
% if this does not work, plot without scaling (just with row and column numbers)
catch
image(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},1)]);
xlim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
hXLabel = xlabel('# Photon energy, column number');
hYLabel = ylabel('# Auger energy, column number');
end
end
box(gca,'on');
if ~matches(p.Results.figureMode,'word')
title(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'Interpreter','none')
end
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
elseif endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy')
if contains(p.Results.energyScale,'kinetic')
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
image(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
1:length(1:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)),...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}',...
'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
if size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2) >= 2
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
end
xlim([p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(1) p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(end)]);
hXLabel = xlabel('Electron energy [eV]');
hYLabel = ylabel('Sequence iteration');
elseif contains(p.Results.energyScale,'binding')
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
image(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii},...
1:length(1:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)),...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}',...
'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
% xlim([p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV(ii,1) p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV(ii,2)]);
hXLabel = xlabel('Binding energy [eV]');
hYLabel = ylabel('Sequence iteration');
end
box(gca,'on');
existColumn = strcmp('sample',p.Results.DataTable.Properties.VariableNames);
if ~matches(p.Results.figureMode,'word')
if ~any(existColumn)
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}],'Interpreter','none')
else
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).sample{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}] ,'Interpreter','none')
end
end
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
end
end
end
if matches(p.Results.tableVariable,'imageRoh')
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5') % let's do NEXAFS first.
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
% Try to plot image with x and y
try
image(p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii},p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
xlim([p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}(1) p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii}(end)]);
ylim([p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRange_eV(ii,1) p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRange_eV(ii,2)]);
hXLabel = xlabel('Photon energy [eV]');
hYLabel = ylabel('Auger energy [eV]');
% if this does not work, plot without scaling (just with row and column numbers)
catch
image(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},1)]);
xlim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
hXLabel = xlabel('# Photon energy, column number');
hYLabel = ylabel('# Auger energy, column number');
end
box(gca,'on');
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
elseif endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy')
if contains(p.Results.energyScale,'kinetic')
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
existColumn = strcmp('scientaEkinRoh_eV',DataTable.Properties.VariableNames);
if any(existColumn)
image(p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRoh_eV{ii},...
1:length(1:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)),...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}',...
'Parent',gca,'CDataMapping','scaled');
xlim([p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRoh_eV{ii}(1) p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRoh_eV{ii}(end)]);
else
image(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
1:length(1:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)),...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}',...
'Parent',gca,'CDataMapping','scaled');
xlim([p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(1) p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(end)]);
end
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
hXLabel = xlabel('Electron energy [eV]');
hYLabel = ylabel('Sequence iteration');
elseif contains(p.Results.energyScale,'binding')
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
image(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii},...
1:length(1:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)),...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}',...
'Parent',gca,'CDataMapping','scaled');
axis(gca,'ij');
set(gca,'Layer','top');
ylim([1 size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)]);
% xlim([p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV(ii,1) p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV(ii,2)]);
hXLabel = xlabel('Binding energy [eV]');
hYLabel = ylabel('Sequence iteration');
end
box(gca,'on');
existColumn = strcmp('sample',p.Results.DataTable.Properties.VariableNames);
if ~matches(p.Results.figureMode,'word')
if ~any(existColumn)
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}],'Interpreter','none')
else
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).sample{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}] ,'Interpreter','none')
end
end
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
end
end
end
if contains(p.Results.tableVariable,'spectrum')
if contains(p.Results.mode,'OneEach')
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
% Create axes
hold(gca,'on');
if (contains(p.Results.energyScale,'kinetic') && (endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy')))
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}');
hplot.LineWidth = lw;
hXLabel = xlabel('Electron kinetic energy [eV]');
xlim([p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRange_eV(ii,1) p.Results.DataTable(p.Results.tableSelection,:).scientaEkinRange_eV(ii,2)]);
elseif (contains(p.Results.energyScale,'binding') && (endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw')|| endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy')))
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}');
hplot.LineWidth = lw;
hXLabel= xlabel('Binding energy [eV]');
xlim([min(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii}) max(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii})]);
elseif (contains(p.Results.energyScale,'xRay') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5'))
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii});
hplot.LineWidth = lw;
hXLabel = xlabel('Photon Energy eV');
xlim([p.Results.DataTable(p.Results.tableSelection,:).xRayEkinRange_eV(ii,1) p.Results.DataTable(p.Results.tableSelection,:).xRayEkinRange_eV(ii,2)]);
end
if contains(p.Results.tableVariable,'Norm')
hYLabel = ylabel('Counts [arb. unit]');
elseif contains(p.Results.energyScale,'xRay')
hYLabel = ylabel('partial A-M.E.Y.');
else
hYLabel = ylabel('Counts per second');
end
box(gca,'on');
existColumn = strcmp('sample',p.Results.DataTable.Properties.VariableNames);
if ~matches(p.Results.figureMode,'word')
if ~any(existColumn)
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}],'Interpreter','none')
else
try
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).sample{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}] ,'Interpreter','none')
catch
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).sample{ii}}] ,'Interpreter','none')
end
end
end
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
end
end
if contains(p.Results.mode,'AllInOne')
% generate colormap
hdl = figure('Name','AllInOneSpectrum','units', unt,'Position',pos);
if size(p.Results.DataTable(p.Results.tableSelection,:),1) >= 7
tmp_color = colormap(parula(size(p.Results.DataTable(p.Results.tableSelection,:),1)));
else
tmp_color = colormap(lines(size(p.Results.DataTable(p.Results.tableSelection,:),1)));
end
if contains(p.Results.energyScale,'kinetic')
% axes('Parent',gcf,'XDir','reverse')
hold(gca,'on');
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if (endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy'))
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}','DisplayName',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'Color',tmp_color(ii,:));
hplot.LineWidth = lw;
end
end
hXLabel = xlabel('Electron kinetic energy [eV]');
elseif contains(p.Results.energyScale,'binding')
axes('Parent',gcf,'XDir','reverse')
hold(gca,'on');
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if (endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy'))
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}','DisplayName',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'Color',tmp_color(ii,:));
hplot.LineWidth = lw;
end
end
hXLabel= xlabel('Binding energy [eV]');
elseif contains(p.Results.energyScale,'xRay')
hold(gca,'on');
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5')
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).xRayEkin_eV{ii},...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},...
'DisplayName',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'Color',tmp_color(ii,:));
hplot.LineWidth = lw;
end
end
hXLabel = xlabel('Photon Energy eV');
end
if contains(p.Results.tableVariable,'Norm')
hYLabel = ylabel('Counts [arb. unit]');
elseif contains(p.Results.energyScale,'xRay')
hYLabel = ylabel('partial A-M.E.Y.');
else
hYLabel = ylabel('Counts per second');
end
box(gca,'on');
if ~matches(p.Results.figureMode,'word')
title('PE Spectra','Interpreter','none')
hlegend = legend(p.Results.DataTable(p.Results.tableSelection,:).name{:});
hlegend.FontSize = fsz;
hlegend.Interpreter = 'none';
hlegend.Location = loc;
set(legend, 'Interpreter','none')
end
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
end
end
if contains(p.Results.mode,'iterations')
% generate colormap
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy')
hdl = figure('Name',p.Results.DataTable(p.Results.tableSelection,:).name{ii},'units', unt,'Position',pos);
if size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2) >= 7
tmp_color = colormap(parula(size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)));
else
tmp_color = colormap(lines(size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)));
end
% Create axes
hold(gca,'on');
if contains(p.Results.energyScale,'kinetic')
for ij = 1:p.Results.plotStep:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)
hplot= plot(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}',...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(:,ij),'Color',tmp_color(ij,:));
hplot.LineWidth = lw;
hold on
end
xlabel('Electron kinetic energy [eV]')
elseif contains(p.Results.energyScale,'binding')
%axes('Parent',gcf,'XDir','reverse')
for ij = 1:p.Results.plotStep:size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2)
hplot = plot(p.Results.DataTable(p.Results.tableSelection,:).bindingEnergy_eV{ii}',...
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(:,ij),'Color',tmp_color(ii,:));
hplot.LineWidth = lw;
end
hXLabel = xlabel('Binding energy [eV]');
end
if contains(p.Results.tableVariable,'Norm')
hYLabel = ylabel('Counts [arb. unit]');
else
hYLabel = ylabel('Counts per second');
end
box(gca,'on');
if ~matches(p.Results.figureMode,'word')
title([{p.Results.DataTable(p.Results.tableSelection,:).name{ii} p.Results.DataTable(p.Results.tableSelection,:).sample{ii} p.Results.DataTable(p.Results.tableSelection,:).lastModifiedDatestr{ii}}] ,'Interpreter','none')
end
set( gca, ...
'FontName' , fnt,'FontSize' , fsz );
set([hXLabel, hYLabel], ...
'FontName' , fnt);
set([hXLabel, hYLabel] , ...
'FontSize' , 1.2*fsz );
set(gca, ...
'Box' , 'off' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'YMinorTick' , 'off' , ...
'XGrid' , 'on' , ...
'XColor' , [0 0 0], ...
'YColor' , [0 0 0], ...
'LineWidth' , alw );
end
end
end
% Nested callback function
% function txt = updatePlots(~, event_obj, pResults, ii, ax2, ax3, hplot2, hplot3)
% pos = get(event_obj, 'Position');
% ij = round(pos(1));
% ik = round(pos(2));
%
% set(hplot2, 'XData', pResults.DataTable(pResults.tableSelection,:).(pResults.tableVariable){ii}(:,ij));
% title(ax2, sprintf('Auger-Meitner (X index = %d)', ij));
%
% set(hplot3, 'YData', pResults.DataTable(pResults.tableSelection,:).(pResults.tableVariable){ii}(ik,:));
% title(ax3, sprintf('NEXAFS (Y index = %d)', ik));
%
% % Create custom datatip text showing coordinates
% txt = {sprintf('X index: %d', ij), ...
% sprintf('Y index: %d', ik), ...
% sprintf('Intensity: %.2f', dataMatrix(ik, ij))};
% end
function mouseMoveFcn(~, ~, dcm, pResults, ii, ax2, ax3, hplot2, hplot3, ax1)
% Check if mouse is over the image axes
if gca == ax1
% Get current mouse position
cp = get(ax1, 'CurrentPoint');
ij = round(cp(1, 1)); % X index
ik = round(cp(1, 2)); % Y index
% Get the data matrix
dataMatrix = pResults.DataTable(pResults.tableSelection,:).(pResults.tableVariable){ii};
% Ensure indices are within bounds
[nRows, nCols] = size(dataMatrix);
if ij >= 1 && ij <= nCols && ik >= 1 && ik <= nRows
% Update plots
set(hplot2, 'XData', dataMatrix(:, ij));
title(ax2, sprintf('Auger-Meitner (X index = %d)', ij));
set(hplot3, 'YData', dataMatrix(ik, :));
title(ax3, sprintf('NEXAFS (Y index = %d)', ik));
end
end
end
% Datatip callback - shows info
function txt = updatePlots(~, event_obj, pResults, ii, ax2, ax3, hplot2, hplot3)
try
pos = get(event_obj, 'Position');
ij = round(pos(1));
ik = round(pos(2));
dataMatrix = pResults.DataTable(pResults.tableSelection,:).(pResults.tableVariable){ii};
[nRows, nCols] = size(dataMatrix);
ij = max(1, min(ij, nCols));
ik = max(1, min(ik, nRows));
txt = {sprintf('X: %d', ij), ...
sprintf('Y: %d', ik), ...
sprintf('Intensity: %.2f', dataMatrix(ik, ij))};
catch
pos = get(event_obj, 'Position');
txt = {sprintf('X: %.1f', pos(1)), ...
sprintf('Y: %.1f', pos(2))};
end
end
end