From aac4e834c3d8dff1b69eeff4cae80f6589cdfcf7 Mon Sep 17 00:00:00 2001 From: ThorBarRa Date: Mon, 24 Nov 2025 19:08:38 +0100 Subject: [PATCH] added Auger-Meitner plots and interactive NEXAFS --- beamtime/nappPlot.m | 289 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 267 insertions(+), 22 deletions(-) diff --git a/beamtime/nappPlot.m b/beamtime/nappPlot.m index 6b8d9ba..544d442 100644 --- a/beamtime/nappPlot.m +++ b/beamtime/nappPlot.m @@ -28,11 +28,11 @@ function hdl = nappPlot(DataTable,varargin) defaultTableVariable = 'image'; expectedTableVariable = {'image','imageRoh','spectrum_countsPerSecond','spectrum_counts','spectrum_countsNorm'}; defaultMode = 'AllInOne'; -expectedMode = {'AllInOne','OneEach','iterations'}; +expectedMode = {'AllInOne','OneEach','iterations','AugerMeitner','interactive'}; defaultFigureMode = 'screen'; expectedFigureMode = {'screen','powerpoint','word'}; defaultEnergyScale = 'kinetic'; -expectedEnergyScale = {'kinetic','binding','xRay'}; +expectedEnergyScale = {'kinetic','binding','xRay','sweeps'}; defaultTableSelection = true(size(DataTable,1),1); defaultPlotStep = 1; @@ -49,8 +49,11 @@ addParameter(p,'figureMode',defaultFigureMode,... 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.') @@ -88,32 +91,182 @@ elseif contains(p.Results.figureMode,'word') 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)) -if matches(p.Results.tableVariable,'image') + + 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'); - % 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 + 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'); @@ -121,8 +274,33 @@ if matches(p.Results.tableVariable,'image') 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 + 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') @@ -404,7 +582,7 @@ if contains(p.Results.tableVariable,'spectrum') 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))); @@ -435,7 +613,7 @@ if contains(p.Results.tableVariable,'spectrum') end hXLabel= xlabel('Binding energy [eV]'); elseif contains(p.Results.energyScale,'xRay') - hold(gca,'on'); + 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},... @@ -553,5 +731,72 @@ if contains(p.Results.mode,'iterations') 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 \ No newline at end of file