Calculations/Data-Analyzer/+Analyzer/runInteractiveRSDTwoGaussianFitGUI.m

222 lines
8.3 KiB
Matlab

function runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results)
%% runInteractiveRSDTwoGaussianFitGUI
% Author: Karthik
% Date: 2025-10-16
% Version: 1.0
%
% Description:
% Interactive viewer for raw radial spectral distributions.
% Lets user browse through individual curves and refit two-Gaussian models
% live as threshold parameters are adjusted.
%
% Controls:
% - Slider or ←/→ keys to browse curves
% - Editable boxes for thresholds (Residual, Position, Amplitude, KRhoRange, AmplitudeRange)
% - "Re-fit Current Curve" button triggers recomputation
%
% Dependencies:
% Requires Analyzer.fitTwoGaussianCurvesToRadialSpectralDistribution.m
%% --- Initialization ---
rawCurves.x = spectral_analysis_results.S_k_all;
rawCurves.k = spectral_analysis_results.k_rho_vals;
% Handle input organization
if iscell(rawCurves.x)
Ncurves = numel(rawCurves.x);
else
Ncurves = size(rawCurves.x, 1);
tmp = arrayfun(@(i) struct('x', rawCurves.x(i,:), 'k', rawCurves.k(:)'), 1:Ncurves);
rawCurves = tmp(:);
end
% Default fit parameters
params.KRhoRange = [0, 3];
params.AmplitudeRange = [0, 0.5];
params.ResidualThreshold = 0.15;
params.PositionThreshold = 0.5;
params.AmplitudeThreshold = 0.015;
currentIdx = 1;
%% --- Create figure ---
hFig = findobj('Type','figure','Tag','InteractiveTwoGaussianRSD');
if isempty(hFig)
hFig = figure('Name','Radial Spectra Fit Viewer',...
'NumberTitle','off',...
'Position',[100 100 1250 800],...
'Color','w',...
'KeyPressFcn',@keyPressCallback,...
'Tag','InteractiveTwoGaussianRSD');
else
figure(hFig); clf(hFig);
end
%% --- Axes for plot ---
hAx = axes('Parent',hFig,'Position',[0.08 0.1 0.55 0.8]);
grid(hAx,'on'); box(hAx,'on');
xlabel(hAx,'k_\rho','FontSize',12);
ylabel(hAx,'Normalized amplitude','FontSize',12);
%% --- Slider for curve index ---
hSlider = uicontrol('Style','slider','Min',1,'Max',Ncurves,'Value',1,...
'SliderStep',[1/(Ncurves-1), 10/(Ncurves-1)],...
'Units','normalized','Position',[0.1 0.02 0.5 0.03],...
'Callback',@(~,~) updatePlot());
%% --- Parameter definitions ---
paramNames = {'KRhoRange','AmplitudeRange','ResidualThreshold','PositionThreshold','AmplitudeThreshold'};
paramLabels = {'KRho range [min,max]','Amplitude range [min,max]','Residual Threshold','Position Threshold','Amplitude Threshold'};
paramDescs = {'Truncate Krho range for fitting',...
'Truncate amplitudes below/above values',...
'Maximum mean residual for valid fits',...
'Minimum separation between peaks',...
'Minimum amplitude ratio threshold'};
nParams = numel(paramNames);
hEdit = gobjects(nParams,1);
baseY = 0.88;
%% --- Create parameter controls ---
for i = 1:nParams
yPos = baseY - 0.12*(i-1);
% Label
uicontrol('Style','text','Units','normalized',...
'Position',[0.68 yPos 0.25 0.04],...
'String',paramLabels{i},...
'HorizontalAlignment','left',...
'FontSize',10,'FontWeight','bold',...
'BackgroundColor','w');
% Edit box
hEdit(i) = uicontrol('Style','edit','Units','normalized',...
'Position',[0.9 yPos 0.07 0.045],...
'String',num2str(params.(paramNames{i}), '%.4f'),...
'Callback',@(src,~) applyParams());
% Description
uicontrol('Style','text','Units','normalized',...
'Position',[0.68 yPos - 0.04 0.35 0.03],...
'String',paramDescs{i},...
'HorizontalAlignment','left','FontSize',8,'ForegroundColor',[0.4 0.4 0.4],...
'BackgroundColor','w');
end
%% --- Re-fit button ---
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.700 0.295 0.25 0.06],...
'String','Re-fit All Curves',...
'FontSize',14,'FontWeight','bold',...
'BackgroundColor',[0.2 0.6 1],...
'ForegroundColor','w',...
'Callback',@(~,~) refitAll());
%% --- Fit info text boxes ---
infoLabels = {'Fit validity:','Peak positions:','Amplitudes:'};
hInfoText = gobjects(numel(infoLabels),1);
for i = 1:numel(infoLabels)
yText = 0.22 - 0.07*(i-1);
uicontrol('Style','text','Units','normalized',...
'Position',[0.68 yText 0.25 0.05],...
'String',infoLabels{i},...
'FontSize',10,'FontWeight','bold',...
'HorizontalAlignment','left',...
'BackgroundColor','w');
hInfoText(i) = uicontrol('Style','text','Units','normalized',...
'Position',[0.88 yText 0.1 0.05],...
'String','-','FontSize',10,...
'HorizontalAlignment','left',...
'BackgroundColor','w');
end
%% --- Compute initial fits ---
[fitResults, rawData] = Analyzer.fitTwoGaussianCurvesToRadialSpectralDistribution(...
spectral_analysis_results.S_k_all,...
spectral_analysis_results.k_rho_vals,...
'KRhoRange', params.KRhoRange,...
'AmplitudeRange', params.AmplitudeRange,...
'ResidualThreshold', params.ResidualThreshold,...
'PositionThreshold', params.PositionThreshold,...
'AmplitudeThreshold', params.AmplitudeThreshold);
%% --- Initial plot ---
updatePlot();
%% --- Nested functions ---
function applyParams()
% Update parameters from GUI fields
for j = 1:nParams
val = str2double(hEdit(j).String);
if ~isnan(val)
params.(paramNames{j}) = val;
end
end
refitAll();
end
function refitAll()
% Recompute all fits for the entire radial dataset
drawnow;
[fitResults, rawData] = Analyzer.fitTwoGaussianCurvesToRadialSpectralDistribution(...
spectral_analysis_results.S_k_all, ...
spectral_analysis_results.k_rho_vals, ...
'KRhoRange', params.KRhoRange, ...
'AmplitudeRange', params.AmplitudeRange, ...
'ResidualThreshold', params.ResidualThreshold, ...
'PositionThreshold', params.PositionThreshold, ...
'AmplitudeThreshold', params.AmplitudeThreshold);
updatePlot();
end
function updatePlot()
% Display raw curve and two-Gaussian fit
idx = round(get(hSlider,'Value'));
currentIdx = idx;
cla(hAx); hold(hAx,'on');
raw = rawData(idx);
plot(hAx, raw.k, raw.x, 'k.-','LineWidth',1,'DisplayName','Raw Data');
fit = fitResults(idx);
if isfield(fit,'isValid') && ~isempty(fit.isValid) && fit.isValid && ...
isfield(fit,'kFine') && isfield(fit,'yFit') && ~isempty(fit.kFine)
plot(hAx, fit.kFine, fit.yFit, 'r-','LineWidth',1.5,'DisplayName','Two-Gaussian Fit');
if isfield(fit,'pFit') && numel(fit.pFit)>=6
A1=fit.pFit(1); mu1=fit.pFit(2);
A2=fit.pFit(4); mu2=fit.pFit(5);
hInfoText(1).String='Valid'; hInfoText(1).ForegroundColor=[0 0.5 0];
hInfoText(2).String=sprintf('[%.3f, %.3f]',mu1,mu2);
hInfoText(3).String=sprintf('[%.3f, %.3f]',A1,A2);
else
hInfoText(1).String='Valid'; hInfoText(1).ForegroundColor=[0 0.5 0];
hInfoText(2).String='-'; hInfoText(3).String='-';
end
else
hInfoText(1).String='Invalid'; hInfoText(1).ForegroundColor=[0.7 0 0];
hInfoText(2).String='-'; hInfoText(3).String='-';
end
set(gca, 'YScale', 'log');
xlabel(hAx,'k_\rho'); ylabel(hAx,'Normalized amplitude');
title(hAx,sprintf('Curve %d / %d',idx,Ncurves),'FontSize',16);
legend(hAx,'Location','northeast','FontSize',14);
hold(hAx,'off'); drawnow;
end
function keyPressCallback(event)
% Navigate curves via arrow keys
switch event.Key
case 'rightarrow'
if currentIdx<Ncurves, currentIdx=currentIdx+1; set(hSlider,'Value',currentIdx); updatePlot(); end
case 'leftarrow'
if currentIdx>1, currentIdx=currentIdx-1; set(hSlider,'Value',currentIdx); updatePlot(); end
end
end
end