From 1f7526c594a823077f7b6e6b42496e93d1353155 Mon Sep 17 00:00:00 2001 From: Karthik Chandrashekara Date: Mon, 18 Aug 2025 16:03:25 +0200 Subject: [PATCH] Modifications in batch analysis script to take sequence name, date and run number, to reuse data saved in workspace and enhancements to image viewer. --- Data-Analyzer/+Helper/batchAnalyze.m | 4 +- Data-Analyzer/+Helper/collectODImages.m | 25 +++-- .../BECToDroplets/plotAnalysisResults.m | 24 +++-- .../+Scripts/BECToDroplets/plotImages.m | 93 ++++++++++++++----- 4 files changed, 101 insertions(+), 45 deletions(-) diff --git a/Data-Analyzer/+Helper/batchAnalyze.m b/Data-Analyzer/+Helper/batchAnalyze.m index 0c59b53..b030ed3 100644 --- a/Data-Analyzer/+Helper/batchAnalyze.m +++ b/Data-Analyzer/+Helper/batchAnalyze.m @@ -9,7 +9,7 @@ function results_all = batchAnalyze(dataSources, options) options.baseDataFolder = '//DyLabNAS/Data'; end - results_all = struct([]); % one element per folder + results_all = {}; % one element per folder for i = 1:numel(dataSources) ds = dataSources{i}; @@ -63,7 +63,7 @@ function results_all = batchAnalyze(dataSources, options) result.results = analysisResults; % Append to output - results_all(end+1,1) = result; + results_all{end+1,1} = result; catch ME warning("Error processing %s/%s/%s: %s", ... diff --git a/Data-Analyzer/+Helper/collectODImages.m b/Data-Analyzer/+Helper/collectODImages.m index a2d5e93..1393da5 100644 --- a/Data-Analyzer/+Helper/collectODImages.m +++ b/Data-Analyzer/+Helper/collectODImages.m @@ -20,6 +20,15 @@ function [ordered_od_imgs, ordered_scan_parameter_values, ordered_file_list] = c % ordered_od_imgs : cell array of processed OD images (ordered) % ordered_scan_parameter_values: vector of scan parameter values (ordered) % ordered_file_list : cell array of file names (ordered) + + % --- Early exit if processed data already exist --- + if evalin('base', 'exist(''od_imgs'',''var'') && exist(''scan_parameter_values'',''var'') && exist(''file_list'',''var'')') + fprintf('\nReusing processed OD images, scan parameters, and file list from memory.\n'); + ordered_od_imgs = evalin('base','od_imgs'); + ordered_scan_parameter_values = evalin('base','scan_parameter_values'); + ordered_file_list = evalin('base','file_list'); + return; % ✅ skip rest of the function + end % --- Check if the full OD dataset and scan parameters exist in workspace --- fullDataExists = evalin('base', 'exist(''full_od_imgs'', ''var'')') && ... @@ -39,7 +48,7 @@ function [ordered_od_imgs, ordered_scan_parameter_values, ordered_file_list] = c fprintf('\nFull OD image dataset or scan parameters not found in memory.\n'); [full_od_imgs, full_bkg_imgs, raw_scan_parameter_values, raw_file_list] = Helper.processRawData(options); - % Optionally save the full dataset into workspace for future reuse + % Save raw full dataset for reuse assignin('base', 'full_od_imgs', full_od_imgs); assignin('base', 'full_bkg_imgs', full_bkg_imgs); assignin('base', 'raw_scan_parameter_values', raw_scan_parameter_values); @@ -103,9 +112,9 @@ function [ordered_od_imgs, ordered_scan_parameter_values, ordered_file_list] = c ordered_file_list = cell(1, n_total); counter = 1; - temp_scan_values = raw_scan_parameter_values; % copy for indexing + temp_scan_values = raw_scan_parameter_values; temp_od_imgs = processed_od_imgs; - temp_file_list = raw_file_list; % copy original file paths for reordering + temp_file_list = raw_file_list; for rep = 1:n_reps for val = options.scan_reference_values @@ -113,25 +122,25 @@ function [ordered_od_imgs, ordered_scan_parameter_values, ordered_file_list] = c if isempty(idx), continue; end ordered_scan_parameter_values(counter) = temp_scan_values(idx); ordered_od_imgs{counter} = temp_od_imgs{idx}; - ordered_file_list{counter} = temp_file_list{idx}; % reorder file list - temp_scan_values(idx) = NaN; % mark as used + ordered_file_list{counter} = temp_file_list{idx}; + temp_scan_values(idx) = NaN; temp_od_imgs{idx} = []; temp_file_list{idx} = []; counter = counter + 1; end end - fprintf('\nImage reordering completed.\n'); else % No unshuffling: keep original order ordered_od_imgs = processed_od_imgs; ordered_scan_parameter_values = raw_scan_parameter_values; - ordered_file_list = raw_file_list; + ordered_file_list = raw_file_list; end - % Optionally save the full dataset into workspace for future reuse + % --- Save processed dataset for reuse --- assignin('base', 'od_imgs', ordered_od_imgs); assignin('base', 'scan_parameter_values', ordered_scan_parameter_values); + assignin('base', 'file_list', ordered_file_list); fprintf('\nOD image dataset ready for further analysis.\n'); end \ No newline at end of file diff --git a/Data-Analyzer/+Scripts/BECToDroplets/plotAnalysisResults.m b/Data-Analyzer/+Scripts/BECToDroplets/plotAnalysisResults.m index 1ba03bc..3051592 100644 --- a/Data-Analyzer/+Scripts/BECToDroplets/plotAnalysisResults.m +++ b/Data-Analyzer/+Scripts/BECToDroplets/plotAnalysisResults.m @@ -1,6 +1,10 @@ +idx = 1; +compiled_results = results_all{idx}.results; +options.skipSaveFigures = false; + %% ------------------ 1. Mean ± Std Plots ------------------ % Plot Radial Spectral Contrast -Plotter.plotMeanWithSE(scan_parameter_values, results_all.spectral_analysis_results.radial_spectral_contrast, ... +Plotter.plotMeanWithSE(scan_parameter_values, compiled_results.spectral_analysis_results.radial_spectral_contrast, ... 'Title', options.titleString, ... 'XLabel', 'B (G)', ... 'YLabel', 'Radial Spectral Contrast', ... @@ -11,7 +15,7 @@ Plotter.plotMeanWithSE(scan_parameter_values, results_all.spectral_analysis_resu 'SkipSaveFigures', options.skipSaveFigures); % Plot Angular Spectral Weight -Plotter.plotMeanWithSE(scan_parameter_values, results_all.spectral_analysis_results.angular_spectral_weight, ... +Plotter.plotMeanWithSE(scan_parameter_values, compiled_results.spectral_analysis_results.angular_spectral_weight, ... 'Title', options.titleString, ... 'XLabel', 'B (G)', ... 'YLabel', 'Angular Spectral Weight', ... @@ -22,7 +26,7 @@ Plotter.plotMeanWithSE(scan_parameter_values, results_all.spectral_analysis_resu 'SkipSaveFigures', options.skipSaveFigures); % Plot Peak Offset Angular Correlation -Plotter.plotMeanWithSE(options.scan_reference_values, results_all.custom_g_results.max_g2_all_per_scan_parameter_value, ... +Plotter.plotMeanWithSE(options.scan_reference_values, compiled_results.custom_g_results.max_g2_all_per_scan_parameter_value, ... 'Title', options.titleString, ... 'XLabel', 'B (G)', ... 'YLabel', '$\mathrm{max}[g^{(2)}_{[50,70]}(\delta\theta)]$', ... @@ -34,9 +38,9 @@ Plotter.plotMeanWithSE(options.scan_reference_values, results_all.custom_g_resul 'SkipSaveFigures', options.skipSaveFigures); %% ------------------ 2. g²(θ) across transition ------------------ -Plotter.plotG2(results_all.full_g2_results.g2_all, ... - results_all.full_g2_results.g2_error_all, ... - results_all.full_g2_results.theta_values, ... +Plotter.plotG2(compiled_results.full_g2_results.g2_all, ... + compiled_results.full_g2_results.g2_error_all, ... + compiled_results.full_g2_results.theta_values, ... options.scan_reference_values, ... 'rot_mag_field', ... 'Title', options.titleString, ... @@ -50,7 +54,7 @@ Plotter.plotG2(results_all.full_g2_results.g2_all, ... 'Colormap', @Colormaps.coolwarm); %% ------------------ 3. PDF of max g² across transition ------------------ -Plotter.plotPDF(results_all.custom_g_results.max_g2_all_per_scan_parameter_value, options.scan_reference_values, ... +Plotter.plotPDF(compiled_results.custom_g_results.max_g2_all_per_scan_parameter_value, options.scan_reference_values, ... 'Title', options.titleString, ... 'XLabel', 'B (G)', ... 'YLabel', '$\mathrm{max}[g^{(2)}]$', ... @@ -67,7 +71,7 @@ Plotter.plotPDF(results_all.custom_g_results.max_g2_all_per_scan_parameter_value %% ------------------ 4. Cumulants across transition ------------------ Plotter.plotCumulants(options.scan_reference_values, ... - {results_all.custom_g_results.mean_max_g2, results_all.custom_g_results.var_max_g2, results_all.custom_g_results.skew_max_g2_angle, results_all.custom_g_results.fourth_order_cumulant_max_g2}, ... + {compiled_results.custom_g_results.mean_max_g2, compiled_results.custom_g_results.var_max_g2, compiled_results.custom_g_results.skew_max_g2_angle, compiled_results.custom_g_results.fourth_order_cumulant_max_g2}, ... 'Title', 'Cumulants of Peak Offset Angular Correlation', ... 'XLabel', 'B (G)', ... 'FigNum', 6, ... @@ -136,7 +140,7 @@ compareMultipleDatasets(scanValsCell, meanValsCell, stderrValsCell, ... BFields = [2.35, 2.15, 2.0, 1.85, 1.7, 1.55, 1.4, 1.35]; % Heatmap of mean_max_g2_values -Plotter.plotHeatmap(results_all, options.scan_groups, BFields, 'mean_max_g2_values', ... +Plotter.plotHeatmap(compiled_results, options.scan_groups, BFields, 'mean_max_g2_values', ... 'Colormap', @sky, ... 'CLim', [0 1], ... 'XLabel', '\alpha (degrees)', ... @@ -147,7 +151,7 @@ Plotter.plotHeatmap(results_all, options.scan_groups, BFields, 'mean_max_g2_valu 'SaveDirectory', options.resultsDir); % Heatmap of radial_spectral_contrast -Plotter.plotHeatmap(results_all, options.scan_groups, BFields, 'radial_spectral_contrast', ... +Plotter.plotHeatmap(compiled_results, options.scan_groups, BFields, 'radial_spectral_contrast', ... 'Colormap', @sky, ... 'CLim', [0 0.008], ... 'XLabel', '\alpha (degrees)', ... diff --git a/Data-Analyzer/+Scripts/BECToDroplets/plotImages.m b/Data-Analyzer/+Scripts/BECToDroplets/plotImages.m index 93146d0..d35c330 100644 --- a/Data-Analyzer/+Scripts/BECToDroplets/plotImages.m +++ b/Data-Analyzer/+Scripts/BECToDroplets/plotImages.m @@ -1,10 +1,19 @@ %% ===== BEC-Droplets Settings ===== + +% Specify data location to run analysis on +dataSources = { + struct('sequence', 'StructuralPhaseTransition', ... + 'date', '2025/08/13', ... + 'runs', [62]) % specify run numbers as a string in "" or just as a numeric value +}; + options = struct(); % File / paths -options.folderPath = "//DyLabNAS/Data/StructuralPhaseTransition/2025/08/13/0062"; +options.baseDataFolder = '//DyLabNAS/Data'; options.savefileName = 'BECToDroplets'; -options.saveDirectory = "Z:/Users/Karthik/Data-Analyzer/+Scripts"; +scriptFullPath = mfilename('fullpath'); +options.saveDirectory = fileparts(scriptFullPath); % Camera / imaging options.cam = 5; @@ -19,41 +28,40 @@ options.ImagingMode = 'HighIntensity'; options.PulseDuration = 5e-6; % in s % Fourier analysis settings -% Radial Spectral Distribution options.theta_min = deg2rad(0); options.theta_max = deg2rad(180); options.N_radial_bins = 500; options.Radial_Sigma = 2; -options.Radial_WindowSize = 5; % odd number for centered moving avg +options.Radial_WindowSize = 5; % odd number -% Angular Spectral Distribution -options.k_min = 1.2771; % in μm⁻¹ -options.k_max = 2.5541; % in μm⁻¹ +options.k_min = 1.2771; % μm⁻¹ +options.k_max = 2.5541; % μm⁻¹ options.N_angular_bins = 180; options.Angular_Threshold = 75; options.Angular_Sigma = 2; options.Angular_WindowSize = 5; -options.zoom_size = 50; % zoomed-in region around center +options.zoom_size = 50; % Scan parameter options.scan_parameter = 'rot_mag_field'; -if strcmp(options.savefileName, 'BECToDroplets') - options.scan_reference_values = [2.40, 2.39, 2.38, 2.37, 2.35, 2.34, 2.32, 2.30, 2.28, 2.26, 2.24, 2.22, 2.2, 2.15, 2.10, 2.05, 2, 1.95, 1.90, 1.85, 1.8]; - options.titleString = 'BEC to Droplets'; -elseif strcmp(options.savefileName, 'BECToStripes') - options.scan_reference_values = [2.45, 2.44, 2.43, 2.42, 2.4, 2.39, 2.38, 2.37, 2.36, 2.35, 2.34, 2.32, 2.3, 2.28, 2.25, 2.2, 2.15, 2.10, 2.0, 1.90, 1.8]; - options.titleString = 'BEC to Stripes'; -elseif strcmp(options.savefileName, 'DropletsToStripes') - options.scan_reference_values = [0, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 35, 40]; - options.titleString = 'Droplets to Stripes'; -elseif strcmp(options.savefileName, 'StripesToDroplets') - options.scan_reference_values = fliplr([0, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 35, 40]); - options.titleString = 'Stripes to Droplets'; +switch options.savefileName + case 'BECToDroplets' + options.scan_reference_values = [2.40, 2.39, 2.38, 2.37, 2.35, 2.34, 2.32, 2.30, 2.28, 2.26, 2.24, 2.22, 2.2, 2.15, 2.10, 2.05, 2, 1.95, 1.90, 1.85, 1.8]; + options.titleString = 'BEC to Droplets'; + case 'BECToStripes' + options.scan_reference_values = [2.45, 2.44, 2.43, 2.42, 2.4, 2.39, 2.38, 2.37, 2.36, 2.35, 2.34, 2.32, 2.3, 2.28, 2.25, 2.2, 2.15, 2.10, 2.0, 1.90, 1.8]; + options.titleString = 'BEC to Stripes'; + case 'DropletsToStripes' + options.scan_reference_values = [0, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 35, 40]; + options.titleString = 'Droplets to Stripes'; + case 'StripesToDroplets' + options.scan_reference_values = fliplr([0, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 35, 40]); + options.titleString = 'Stripes to Droplets'; end % Flags -options.skipNormalization = true; +options.skipNormalization = false; options.skipUnshuffling = false; options.skipPreprocessing = true; options.skipMasking = true; @@ -62,14 +70,49 @@ options.skipBinarization = true; options.skipMovieRender = true; options.skipSaveFigures = true; options.skipSaveOD = true; -options.skipLivePlot = false; +options.skipLivePlot = false; options.showProgressBar = true; -% Optional extras +% Extras options.font = 'Bahnschrift'; -%% +%% ===== Build Paths from Data Sources ===== + +allPaths = {}; % initialize + +for i = 1:length(dataSources) + ds = dataSources{i}; + + % Split the date string into year/month/day + dateParts = strsplit(ds.date, '/'); + + for run = ds.runs + runStr = sprintf('%04d', run); % 4-digit run number + fullPath = fullfile(options.baseDataFolder, ds.sequence, dateParts{:}, runStr); + + if isfolder(fullPath) % only include valid directories + allPaths{end+1} = fullPath; + else + warning('Path does not exist: %s', fullPath); + end + end +end + +% Let user select a single path +set(0,'DefaultUicontrolFontSize',10); % increase default font size +[selectedIndex, tf] = listdlg('PromptString','Select a path to analyze:', ... + 'SelectionMode','single', ... + 'ListString', allPaths, ... + 'ListSize',[400, 300]); % width x height in pixels +if tf + options.folderPath = allPaths{selectedIndex}; % ✅ store in options + fprintf('Path set to selection: %s\n', options.folderPath); +else + error('No path selected. Aborting.'); +end + +%% ===== Collect Images and Launch Viewer ===== + [od_imgs, scan_parameter_values, file_list] = Helper.collectODImages(options); -%% Analyzer.runInteractiveODImageViewer(od_imgs, scan_parameter_values, file_list, options); \ No newline at end of file