From 195191d5f11b62a3f3aa471c1e5127f925213021 Mon Sep 17 00:00:00 2001 From: Karthik Chandrashekara Date: Thu, 16 Oct 2025 21:00:57 +0200 Subject: [PATCH] POlished interactive fit viewer and added back the plotting of the fit and raw curves in figures that can be saved. --- .../runInteractiveASDTwoGaussianFitGUI.m | 4 +- .../runInteractiveRSDTwoGaussianFitGUI.m | 4 +- .../+Plotter/plotTwoModeGaussianFitsOnRaw.m | 126 ++++++++++++++++++ .../runAngularSpectralDistributionAnalysis.m | 10 +- .../runRadialSpectralDistributionAnalysis.m | 8 ++ .../runAngularSpectralDistributionAnalysis.m | 8 ++ .../runRadialSpectralDistributionAnalysis.m | 8 ++ .../runAngularSpectralDistributionAnalysis.m | 10 +- .../runRadialSpectralDistributionAnalysis.m | 8 ++ .../runAngularSpectralDistributionAnalysis.m | 10 +- .../runRadialSpectralDistributionAnalysis.m | 8 ++ 11 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 Data-Analyzer/+Plotter/plotTwoModeGaussianFitsOnRaw.m diff --git a/Data-Analyzer/+Analyzer/runInteractiveASDTwoGaussianFitGUI.m b/Data-Analyzer/+Analyzer/runInteractiveASDTwoGaussianFitGUI.m index 572c6c0..f4fd164 100644 --- a/Data-Analyzer/+Analyzer/runInteractiveASDTwoGaussianFitGUI.m +++ b/Data-Analyzer/+Analyzer/runInteractiveASDTwoGaussianFitGUI.m @@ -202,7 +202,9 @@ function runInteractiveASDTwoGaussianFitGUI(spectral_analysis_results) hInfoText(3).String = '-'; end end - + + set(gca, 'YScale', 'log'); + title(hAx,sprintf('Curve %d / %d', idx, Ncurves),'FontSize',16); legend(hAx,'Location','northeast','FontSize',14); hold(hAx,'off'); diff --git a/Data-Analyzer/+Analyzer/runInteractiveRSDTwoGaussianFitGUI.m b/Data-Analyzer/+Analyzer/runInteractiveRSDTwoGaussianFitGUI.m index 16dfdee..a1766e1 100644 --- a/Data-Analyzer/+Analyzer/runInteractiveRSDTwoGaussianFitGUI.m +++ b/Data-Analyzer/+Analyzer/runInteractiveRSDTwoGaussianFitGUI.m @@ -67,7 +67,7 @@ function runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results) %% --- 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 k_\rho range for fitting',... + paramDescs = {'Truncate Krho range for fitting',... 'Truncate amplitudes below/above values',... 'Maximum mean residual for valid fits',... 'Minimum separation between peaks',... @@ -200,6 +200,8 @@ function runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results) 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); diff --git a/Data-Analyzer/+Plotter/plotTwoModeGaussianFitsOnRaw.m b/Data-Analyzer/+Plotter/plotTwoModeGaussianFitsOnRaw.m new file mode 100644 index 0000000..0f05419 --- /dev/null +++ b/Data-Analyzer/+Plotter/plotTwoModeGaussianFitsOnRaw.m @@ -0,0 +1,126 @@ +function plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, nRows, nCols, varargin) +%% plotTwoGaussianFitsWithPagination +% Author: Karthik +% Date: 2025-10-16 +% Version: 1.0 +% +% Description: +% Plots raw radial spectral curves with their two-Gaussian fits in a +% compact, paginated layout. Each page shows up to nRows × nCols subplots. +% +% Inputs: +% fitResults - struct array from fitTwoGaussianCurvesToRadialSpectralDistribution +% rawCurves - struct array with fields: +% .x - raw normalized amplitudes +% .k - corresponding k_rho values +% nRows - number of subplot rows per page (default: 8) +% nCols - number of subplot columns per page (default: 12) +% varargin - name-value pairs: +% 'FontName', 'FontSize', 'SkipLivePlot', 'SkipSaveFigures', +% 'SaveDirectory', 'RepsPerPage' + + % --- Parse optional name-value pairs --- + p = inputParser; + addParameter(p, 'FontName', 'Arial', @ischar); + addParameter(p, 'FontSize', 12, @isnumeric); + addParameter(p, 'SkipLivePlot', false, @islogical); + addParameter(p, 'SkipSaveFigures', true, @islogical); + addParameter(p, 'SaveDirectory', pwd, @ischar); + addParameter(p, 'RepsPerPage', [], @isnumeric); % optional override of nRows*nCols + parse(p, varargin{:}); + opts = p.Results; + + % --- Default subplot grid if not provided --- + if nargin < 3 || isempty(nRows), nRows = 8; end + if nargin < 4 || isempty(nCols), nCols = 12; end + + plotsPerPage = nRows * nCols; + if ~isempty(opts.RepsPerPage) + plotsPerPage = opts.RepsPerPage; + end + + Ncurves = numel(rawCurves); + numPages = ceil(Ncurves / plotsPerPage); + + % --- Setup save directory if needed --- + if ~opts.SkipSaveFigures + saveFolder = fullfile(opts.SaveDirectory, 'Results', 'SavedFigures', 'TwoGaussianFits'); + if ~exist(saveFolder, 'dir') + mkdir(saveFolder); + end + end + + for pageIdx = 1:numPages + repStart = (pageIdx-1)*plotsPerPage + 1; + repEnd = min(pageIdx*plotsPerPage, Ncurves); + repSubset = repStart:repEnd; + N_rows = numel(repSubset); + + % --- Create figure --- + if ~opts.SkipLivePlot + fig = figure('Color', 'w', 'Position', [50 50 1600 900]); + else + fig = figure('Color', 'w', 'Position', [50 50 1600 900], 'Visible', 'off'); + end + + t = tiledlayout(fig, ceil(N_rows/nCols), nCols, 'TileSpacing', 'compact', 'Padding', 'compact'); + title(t, sprintf('Two-Gaussian fits | Page %d/%d', pageIdx, numPages), ... + 'FontSize', opts.FontSize + 2, 'FontWeight', 'bold', 'FontName', opts.FontName); + + for r = 1:N_rows + k = repSubset(r); + nexttile; + hold on; grid on; box on; + + % --- Plot raw curve --- + if isfield(rawCurves, 'x') && isfield(rawCurves, 'k') && ... + ~isempty(rawCurves(k).x) && all(isfinite(rawCurves(k).x)) + plot(rawCurves(k).k, rawCurves(k).x, 'k.-', ... + 'LineWidth', 1, 'DisplayName', 'Raw data'); + end + + % --- Overlay fit if valid --- + if k <= numel(fitResults) + fit = fitResults(k); + if isfield(fit, 'isValid') && ~isempty(fit.isValid) && fit.isValid && ... + isfield(fit, 'kFine') && isfield(fit, 'yFit') && ... + ~isempty(fit.kFine) && all(isfinite(fit.yFit)) + plot(fit.kFine, fit.yFit, 'r-', ... + 'LineWidth', 1.2, 'DisplayName', 'Two-Gaussian fit'); + end + end + + set(gca, 'YScale', 'log'); + + % --- Labels and title --- + xlabel('k_\rho', 'FontSize', opts.FontSize); + ylabel('N. A.', 'FontSize', opts.FontSize); + title(sprintf('Curve %d', k), 'FontSize', opts.FontSize - 2, 'Interpreter', 'none'); + + hold off; + end + + % --- Render live plot --- + if ~opts.SkipLivePlot + drawnow; + end + + % --- Save figure --- + if ~opts.SkipSaveFigures + saveFileName = sprintf('TwoGaussianFits_page_%02d.png', pageIdx); + if exist('Plotter', 'class') + Plotter.saveFigure(fig, ... + 'SaveFileName', saveFileName, ... + 'SaveDirectory', saveFolder, ... + 'SkipSaveFigures', opts.SkipSaveFigures); + else + saveas(fig, fullfile(saveFolder, saveFileName)); + end + end + + % --- Close invisible figure to free memory --- + if opts.SkipLivePlot + close(fig); + end + end +end diff --git a/Data-Analyzer/+Scripts/BECToDroplets/runAngularSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToDroplets/runAngularSpectralDistributionAnalysis.m index f7ac16e..02e7f74 100644 --- a/Data-Analyzer/+Scripts/BECToDroplets/runAngularSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToDroplets/runAngularSpectralDistributionAnalysis.m @@ -154,7 +154,7 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'FontName', options.font, ... 'FontSize', 14, ... 'FigNum', 3, ... - 'SkipSaveFigures', false, ... + 'SkipSaveFigures', options.skipSaveFigures, ... 'SaveFileName', 'SpectralCumulants.fig', ... 'SaveDirectory', options.saveDirectory); @@ -167,6 +167,14 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'PositionThreshold', pi/15, ... 'AmplitudeThreshold', 0.15); +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveASDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToDroplets/runRadialSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToDroplets/runRadialSpectralDistributionAnalysis.m index 3b6b3e2..76c2e09 100644 --- a/Data-Analyzer/+Scripts/BECToDroplets/runRadialSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToDroplets/runRadialSpectralDistributionAnalysis.m @@ -122,6 +122,14 @@ Plotter.plotSpectralCurves( ... 'PositionThreshold', 0.5, ... % minimum separation between peaks 'AmplitudeThreshold', 0.015); % minimum secondary peak fraction +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToDropletsToStripes/runAngularSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToDropletsToStripes/runAngularSpectralDistributionAnalysis.m index 87fce66..0a7f4d9 100644 --- a/Data-Analyzer/+Scripts/BECToDropletsToStripes/runAngularSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToDropletsToStripes/runAngularSpectralDistributionAnalysis.m @@ -167,6 +167,14 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'PositionThreshold', pi/15, ... 'AmplitudeThreshold', 0.15); +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveASDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToDropletsToStripes/runRadialSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToDropletsToStripes/runRadialSpectralDistributionAnalysis.m index dba3929..cdac9f9 100644 --- a/Data-Analyzer/+Scripts/BECToDropletsToStripes/runRadialSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToDropletsToStripes/runRadialSpectralDistributionAnalysis.m @@ -122,6 +122,14 @@ Plotter.plotSpectralCurves( ... 'PositionThreshold', 0.5, ... % minimum separation between peaks 'AmplitudeThreshold', 0.015); % minimum secondary peak fraction +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToStripes/runAngularSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToStripes/runAngularSpectralDistributionAnalysis.m index d888fcc..6631091 100644 --- a/Data-Analyzer/+Scripts/BECToStripes/runAngularSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToStripes/runAngularSpectralDistributionAnalysis.m @@ -154,7 +154,7 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'FontName', options.font, ... 'FontSize', 14, ... 'FigNum', 3, ... - 'SkipSaveFigures', false, ... + 'SkipSaveFigures', options.skipSaveFigures, ... 'SaveFileName', 'SpectralCumulants.fig', ... 'SaveDirectory', options.saveDirectory); @@ -167,6 +167,14 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'PositionThreshold', pi/15, ... 'AmplitudeThreshold', 0.15); +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveASDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToStripes/runRadialSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToStripes/runRadialSpectralDistributionAnalysis.m index 09bd476..f0807bb 100644 --- a/Data-Analyzer/+Scripts/BECToStripes/runRadialSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToStripes/runRadialSpectralDistributionAnalysis.m @@ -122,6 +122,14 @@ Plotter.plotSpectralCurves( ... 'PositionThreshold', 0.5, ... % minimum separation between peaks 'AmplitudeThreshold', 0.015); % minimum secondary peak fraction +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToStripesToDroplets/runAngularSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToStripesToDroplets/runAngularSpectralDistributionAnalysis.m index 97ad443..85c59dc 100644 --- a/Data-Analyzer/+Scripts/BECToStripesToDroplets/runAngularSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToStripesToDroplets/runAngularSpectralDistributionAnalysis.m @@ -154,7 +154,7 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'FontName', options.font, ... 'FontSize', 14, ... 'FigNum', 3, ... - 'SkipSaveFigures', false, ... + 'SkipSaveFigures', options.skipSaveFigures, ... 'SaveFileName', 'SpectralCumulants.fig', ... 'SaveDirectory', options.saveDirectory); @@ -167,6 +167,14 @@ Plotter.plotSpectralDistributionCumulants(results, ... 'PositionThreshold', pi/15, ... 'AmplitudeThreshold', 0.15); +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveASDTwoGaussianFitGUI(spectral_analysis_results); diff --git a/Data-Analyzer/+Scripts/BECToStripesToDroplets/runRadialSpectralDistributionAnalysis.m b/Data-Analyzer/+Scripts/BECToStripesToDroplets/runRadialSpectralDistributionAnalysis.m index 406417f..5211b80 100644 --- a/Data-Analyzer/+Scripts/BECToStripesToDroplets/runRadialSpectralDistributionAnalysis.m +++ b/Data-Analyzer/+Scripts/BECToStripesToDroplets/runRadialSpectralDistributionAnalysis.m @@ -122,6 +122,14 @@ Plotter.plotSpectralCurves( ... 'PositionThreshold', 0.5, ... % minimum separation between peaks 'AmplitudeThreshold', 0.015); % minimum secondary peak fraction +%% ------------------ Plot Fits on Raw ------------------ +options.skipLivePlot = true; +options.skipSaveFigures = false; +Plotter.plotTwoModeGaussianFitsOnRaw(fitResults, rawCurves, 4, 6, ... + 'SkipLivePlot', options.skipLivePlot, ... + 'SkipSaveFigures', options.skipSaveFigures, ... + 'SaveDirectory', options.saveDirectory); + %% ------------------ Interactive Fit Viewer ------------------ Analyzer.runInteractiveRSDTwoGaussianFitGUI(spectral_analysis_results);