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 currentIdx1, currentIdx=currentIdx-1; set(hSlider,'Value',currentIdx); updatePlot(); end end end end