New plotting routines

This commit is contained in:
Karthik 2025-09-09 14:06:08 +02:00
parent ffa50e2525
commit 5fd39e31f4
12 changed files with 730 additions and 54 deletions

View File

@ -43,26 +43,29 @@ function plotAndCompareG2Cumulants(results1, results2, varargin)
% --- Legend labels for θ --- % --- Legend labels for θ ---
thetaLabels = arrayfun(@(t) sprintf('\\pi/%g', round(pi/t)), opts.DesiredTheta, 'UniformOutput', false); thetaLabels = arrayfun(@(t) sprintf('\\pi/%g', round(pi/t)), opts.DesiredTheta, 'UniformOutput', false);
% --- Marker per θ ---
markerList = {'o','s','^','d','v','>','<','p','h'}; % more markers if needed
Ntheta = numel(thIdx);
markers = markerList(mod(0:Ntheta-1, numel(markerList))+1); % cycle if Ntheta > markerList
% --- Line styles for datasets --- % --- Line styles for datasets ---
lineStyles = {'-', '--'}; % solid for dataset1, dashed for dataset2 lineStyles = {'-', '--'}; % solid for dataset1, dashed for dataset2
% --- Colors per θ (generalized, using only ends of coolwarm) --- % --- Colors per θ ---
%{
cmapFull = Colormaps.coolwarm(256); cmapFull = Colormaps.coolwarm(256);
Ntheta = numel(thIdx); Ntheta = numel(thIdx);
startColor = cmapFull(1,:);
% pick start and end colors endColor = cmapFull(end,:);
startColor = cmapFull(1, :); % deep blue
endColor = cmapFull(end, :); % deep red
% interpolate RGB linearly between start and end for Ntheta points
thetaColors = [linspace(startColor(1), endColor(1), Ntheta)', ... thetaColors = [linspace(startColor(1), endColor(1), Ntheta)', ...
linspace(startColor(2), endColor(2), Ntheta)', ... linspace(startColor(2), endColor(2), Ntheta)', ...
linspace(startColor(3), endColor(3), Ntheta)']; linspace(startColor(3), endColor(3), Ntheta)'];
%}
cmapFull = Colormaps.coolwarm(256);
Ntheta = numel(thIdx);
% Split into two halves: blue side (1:128), red side (129:256)
blueSide = cmapFull(1:100, :); % cut before gray
redSide = cmapFull(157:end, :); % cut after gray
% Concatenate to avoid center
cmapTrimmed = [blueSide; redSide];
% Now sample evenly from this trimmed colormap
indices = round(linspace(1, size(cmapTrimmed,1), Ntheta));
thetaColors = cmapTrimmed(indices, :);
% --- Create figure --- % --- Create figure ---
@ -85,7 +88,7 @@ function plotAndCompareG2Cumulants(results1, results2, varargin)
% Dataset 1 -> solid line + marker % Dataset 1 -> solid line + marker
plot(ax, x1, squeeze(kappa1(th,:,k)), ... plot(ax, x1, squeeze(kappa1(th,:,k)), ...
'LineStyle', lineStyles{1}, 'Color', c, ... 'LineStyle', lineStyles{1}, 'Color', c, ...
'LineWidth', 2, 'Marker', 'o', 'MarkerSize', 7, ... 'LineWidth', 2, 'Marker', 'o', 'MarkerSize', 7, ... % markerList = {'o','s','^','d','v','>','<','p','h'}; % more markers if needed
'MarkerFaceColor', c); 'MarkerFaceColor', c);
% Dataset 2 -> dashed line + marker % Dataset 2 -> dashed line + marker

View File

@ -0,0 +1,135 @@
function plotAndCompareG2Mean(results1, results2, varargin)
%% plotAndCompareG2Mean: Compare first cumulant (mean) of g²(θ) for two datasets
% results1, results2 : g2_analysis_results objects
%
% Dataset 1 = Solid line
% Dataset 2 = Dashed line
% Marker shape encodes θ value (consistent across datasets)
% Dataset colors are distinct
%
% Plots mean ± standard deviation of g² values at the desired θ
% --- Parse name-value pairs ---
p = inputParser;
addParameter(p, 'Title', 'Mean Comparison', @(x) ischar(x) || isstring(x));
addParameter(p, 'XLabel', 'Scan Parameter', @(x) ischar(x) || isstring(x));
addParameter(p, 'YLabel', 'Mean (\kappa_1)', @(x) ischar(x) || isstring(x));
addParameter(p, 'FontName', 'Arial', @ischar);
addParameter(p, 'FontSize', 14, @isnumeric);
addParameter(p, 'FigNum', [], @(x) isempty(x) || (isnumeric(x) && isscalar(x)));
addParameter(p, 'SkipSaveFigures', false, @islogical);
addParameter(p, 'SaveFileName', 'G2MeanComparison.fig', @ischar);
addParameter(p, 'SaveDirectory', pwd, @ischar);
addParameter(p, 'DesiredTheta', [pi/12 pi/6 pi/3 pi/2 2*pi/3 5*pi/6], @(x) isnumeric(x) && isvector(x));
parse(p, varargin{:});
opts = p.Results;
% --- Helper to extract mean, STD, and SEM at desired θ ---
function [xvals, yMean, yStd, ySEM, thIdx] = extractData(results)
xvals = results.scan_parameter_values(:); % [N_params × 1]
N_params = numel(xvals);
thetaVals = results.theta_values; % all θ
desiredTheta = opts.DesiredTheta;
[~, thIdx] = arrayfun(@(t) min(abs(thetaVals - t)), desiredTheta);
Ndesired = numel(desiredTheta);
yMean = zeros(N_params, Ndesired); % [scan × θ]
yStd = zeros(N_params, Ndesired);
ySEM = zeros(N_params, Ndesired);
for i = 1:N_params
G = results.g2_curves{i}; % [N_reps × N_theta] for this scan parameter
for j = 1:Ndesired
th = thIdx(j);
data = G(:, th); % all reps for this θ at this scan param
yMean(i,j) = mean(data); % mean across reps
yStd(i,j) = std(data,0,1); % std across reps
ySEM(i,j) = std(data,0,1)/sqrt(numel(data)); % SEM
end
end
end
% --- Extract data for both datasets ---
[x1, yMean1, yStd1, ySEM1, thIdx] = extractData(results1);
[x2, yMean2, yStd2, ySEM2, ~] = extractData(results2);
% --- Legend labels for θ ---
thetaLabels = arrayfun(@(t) sprintf('\\pi/%g', round(pi/t)), opts.DesiredTheta, 'UniformOutput', false);
% --- Line styles for datasets ---
lineStyles = {'-', '--'}; % solid for dataset1, dashed for dataset2
% --- Colors per θ ---
%{
cmapFull = Colormaps.coolwarm(256);
Ntheta = numel(thIdx);
startColor = cmapFull(1,:);
endColor = cmapFull(end,:);
thetaColors = [linspace(startColor(1), endColor(1), Ntheta)', ...
linspace(startColor(2), endColor(2), Ntheta)', ...
linspace(startColor(3), endColor(3), Ntheta)'];
%}
cmapFull = Colormaps.coolwarm(256);
Ntheta = numel(thIdx);
% Split into two halves: blue side (1:128), red side (129:256)
blueSide = cmapFull(1:100, :); % cut before gray
redSide = cmapFull(157:end, :); % cut after gray
% Concatenate to avoid center
cmapTrimmed = [blueSide; redSide];
% Now sample evenly from this trimmed colormap
indices = round(linspace(1, size(cmapTrimmed,1), Ntheta));
thetaColors = cmapTrimmed(indices, :);
% --- Create figure ---
if isempty(opts.FigNum), fig = figure; else, fig = figure(opts.FigNum); end
clf(fig);
set(fig,'Color','w','Position',[100 100 950 750]);
ax = axes(fig); hold(ax,'on'); grid(ax,'on');
xlabel(ax, opts.XLabel, 'FontName', opts.FontName, 'FontSize', opts.FontSize);
ylabel(ax, opts.YLabel, 'FontName', opts.FontName, 'FontSize', opts.FontSize);
title(ax, opts.Title, 'FontName', opts.FontName, 'FontSize', opts.FontSize+2);
% --- Plot each θ with SEM ---
for idx = 1:Ntheta
c = thetaColors(idx,:);
% Dataset 1 -> solid line + marker + SEM
errorbar(ax, x1, yMean1(:,idx), ySEM1(:,idx), 'LineStyle', lineStyles{1}, ...
'Color', c, 'LineWidth', 2, 'Marker', 'o', 'MarkerSize', 7, 'MarkerFaceColor', c);
% Dataset 2 -> dashed line + marker + SEM
errorbar(ax, x2, yMean2(:,idx), ySEM2(:,idx), 'LineStyle', lineStyles{2}, ...
'Color', c, 'LineWidth', 2, 'Marker', 's', 'MarkerSize', 7, 'MarkerFaceColor', c);
end
% --- Line-only legend for θ ---
thetaHandles = gobjects(Ntheta,1);
for m = 1:Ntheta
thetaHandles(m) = plot(ax, NaN, NaN, 'LineStyle','-', 'Color',thetaColors(m,:), ...
'LineWidth',6, 'Marker','none');
end
legend(ax, thetaHandles, thetaLabels, 'Location','northeast', 'FontSize', opts.FontSize-2);
% --- Dataset legend (solid/dashed + marker) ABOVE AXES ---
axLegend = axes(fig,'Position',[0.65 0.65 0.25 0.15],'Visible','off');
hold(axLegend,'on');
d1 = plot(axLegend, NaN, NaN, 'LineStyle',lineStyles{1}, ...
'Color','k', 'Marker','none', 'LineWidth',2);
d2 = plot(axLegend, NaN, NaN, 'LineStyle',lineStyles{2}, ...
'Color','k', 'Marker','none', 'LineWidth',2);
legend(axLegend,[d1 d2],{'D -> S','S -> D'}, ...
'FontName', opts.FontName, 'FontSize', opts.FontSize+2, ...
'Orientation','vertical', 'Box','off');
% --- Save figure ---
if ~opts.SkipSaveFigures
if ~exist(opts.SaveDirectory,'dir'), mkdir(opts.SaveDirectory); end
savefig(fig, fullfile(opts.SaveDirectory, opts.SaveFileName));
end
end

View File

@ -0,0 +1,121 @@
function plotG2CurvesMultiParam(results, scan_parameter_values, scan_reference_values, param1ValuesToPlot, param2ValuesToPlot, varargin)
%% plotG2CurvesMultiParam: Plot g²(θ) curves for selected param1 and param2 values in a phase diagram
%
% Usage:
% plotG2CurvesMultiParam(results, scan_parameter_values, scan_reference_values, ...
% param1ValuesToPlot, param2ValuesToPlot, ...
% 'Title','g² Curves','FontName','Arial','FontSize',14,'FigNum',1, ...
% 'Param1Name','BField','Param2Name','Alpha', ...
% 'HighlightEvery',10,'SkipSaveFigures',false, ...
% 'SaveFileName','G2CurvesPhaseDiagram.fig','SaveDirectory','results');
% --- Parse name-value pairs ---
p = inputParser;
addParameter(p, 'Title', 'g² Curves', @(x) ischar(x) || isstring(x));
addParameter(p, 'FontName', 'Arial', @ischar);
addParameter(p, 'FontSize', 14, @isnumeric);
addParameter(p, 'FigNum', [], @(x) isempty(x) || (isnumeric(x) && isscalar(x)));
addParameter(p, 'Param1Name', 'Param1', @(x) ischar(x) || isstring(x));
addParameter(p, 'Param2Name', 'Param2', @(x) ischar(x) || isstring(x));
addParameter(p, 'HighlightEvery', 10, @(x) isnumeric(x) && isscalar(x) && x>=1);
addParameter(p, 'SkipSaveFigures', false, @islogical);
addParameter(p, 'SaveFileName', 'G2CurvesPhaseDiagram.fig', @ischar);
addParameter(p, 'SaveDirectory', pwd, @ischar);
parse(p, varargin{:});
opts = p.Results;
% --- Convert reference/parameter values to numeric arrays ---
scanRefArray = cell2mat(scan_reference_values(:)); % nParams × 2
scanParamArray = cell2mat(scan_parameter_values(:)); % nTotal × 2
% --- Select subset based on param1ValuesToPlot and param2ValuesToPlot ---
keepIdx = ismembertol(scanRefArray(:,1), param1ValuesToPlot, 1e-6) & ...
ismembertol(scanRefArray(:,2), param2ValuesToPlot, 1e-6);
scan_reference_values_plot = scan_reference_values(keepIdx);
nParamsPlot = numel(scan_reference_values_plot);
% --- Warn about missing values ---
existingP1 = param1ValuesToPlot(ismembertol(param1ValuesToPlot, unique(scanRefArray(:,1)), 1e-6));
missingP1 = setdiff(param1ValuesToPlot, existingP1);
existingP2 = param2ValuesToPlot(ismembertol(param2ValuesToPlot, unique(scanRefArray(:,2)), 1e-6));
missingP2 = setdiff(param2ValuesToPlot, existingP2);
if ~isempty(missingP1)
warning('The following %s values were not found: %s', opts.Param1Name, num2str(missingP1));
end
if ~isempty(missingP2)
warning('The following %s values were not found: %s', opts.Param2Name, num2str(missingP2));
end
param1Plot = sort(existingP1, 'descend');
param2Plot = sort(existingP2);
% --- Extract theta values ---
theta = results.theta_values / pi;
Nhighlight = opts.HighlightEvery;
% --- Create figure ---
if isempty(opts.FigNum)
fig = figure;
else
fig = figure(opts.FigNum);
end
clf(fig);
set(fig,'Color','w','Position',[100 100 1200 800]);
t = tiledlayout(numel(param1Plot), numel(param2Plot), 'TileSpacing','compact','Padding','compact');
title(t, opts.Title, 'FontName', opts.FontName, 'FontSize', opts.FontSize+2);
% --- Loop over selected param1/param2 values ---
for r = 1:numel(param1Plot)
P1 = param1Plot(r);
for c = 1:numel(param2Plot)
P2 = param2Plot(c);
ax = nexttile((r-1)*numel(param2Plot) + c); hold(ax,'on');
% Find index of this (param1, param2)
k = find(cellfun(@(v) all(abs(v - [P1 P2]) < 1e-6), scan_reference_values_plot), 1);
if isempty(k), continue; end
% Extract g² curves for this pair
G = results.g2_curves{k}; % [N_reps × Nθ]
% --- Plot all repetitions in light grey ---
plot(ax, theta, G', 'Color', [0.7 0.7 0.7, 0.5]);
% --- Highlight every Nth repetition ---
idx = Nhighlight:Nhighlight:size(G,1);
for j = idx
plot(ax, theta, G(j,:), 'Color', [0.3 0.3 0.3, 1], 'LineWidth', 1.5);
end
% --- Mean + SEM shading ---
mu = mean(G,1,'omitnan');
se = std(G,0,1,'omitnan')/sqrt(size(G,1));
fill(ax, [theta fliplr(theta)], [mu-se fliplr(mu+se)], [0.2 0.4 0.8], ...
'FaceAlpha',0.2,'EdgeColor','none');
% --- Mean curve ---
plot(ax, theta, mu, 'b-', 'LineWidth', 2);
% --- Vertical reference lines at pi/3 and 2pi/3 ---
xlines = [1/3 2/3];
for xl = xlines
xline(ax, xl, 'k--', 'LineWidth', 1.5, 'Alpha', 0.5);
end
% --- Axes formatting ---
grid(ax,'on');
xlabel(ax, '\theta / \pi', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
ylabel(ax, 'g^2(\theta)', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
title(ax, sprintf('%s=%.3g, %s=%.1f', opts.Param1Name, P1, opts.Param2Name, P2), ...
'FontName', opts.FontName, 'FontSize', opts.FontSize);
set(ax, 'FontName', opts.FontName, 'FontSize', opts.FontSize);
end
end
% --- Save figure ---
if ~opts.SkipSaveFigures
if ~exist(opts.SaveDirectory,'dir'), mkdir(opts.SaveDirectory); end
savefig(fig, fullfile(opts.SaveDirectory, opts.SaveFileName));
end
end

View File

@ -0,0 +1,118 @@
function plotG2MeanHeatmap(results, theta_query, scan_parameter_values, scan_reference_values, varargin)
%% plotG2MeanHeatmap: Plots a heatmap of mean g² values at a specified theta across the phase diagram
%
% Usage:
% plotG2MeanHeatmap(results, pi/6, scan_parameter_values, scan_reference_values, ...
% 'FigNum', 1, 'Colormap', @jet, 'CLim', [], 'ColorScale', 'linear', ...
% 'XLabel', '\alpha (degrees)', 'YLabel', 'BField (G)', ...
% 'Title', 'Mean g²', 'SaveFileName', 'g2MeanHeatmap.fig', ...
% 'SaveDirectory', 'results', 'SkipSaveFigures', false);
% --- Parse optional inputs ---
p = inputParser;
addParameter(p, 'FigNum', []);
addParameter(p, 'Colormap', @jet);
addParameter(p, 'CLim', []);
addParameter(p, 'ColorScale', 'linear', @(x) any(validatestring(x,{'linear','log'})));
addParameter(p, 'XLabel', '\alpha (degrees)');
addParameter(p, 'YLabel', 'BField (G)');
addParameter(p, 'Title', 'Mean g²');
addParameter(p, 'FontName', 'Arial');
addParameter(p, 'FontSize', 14);
addParameter(p, 'SkipSaveFigures', false, @islogical);
addParameter(p, 'SaveFileName', 'g2MeanHeatmap.fig', @ischar);
addParameter(p, 'SaveDirectory', pwd, @ischar);
parse(p, varargin{:});
opts = p.Results;
% --- Extract data at requested theta ---
theta_vals = results.theta_values;
[~, idx_theta] = min(abs(theta_vals - theta_query)); % closest index
N_total = numel(results.g2_curves);
dataCell = cell(N_total,1);
for i = 1:N_total
G = results.g2_curves{i}; % [N_reps × Nθ]
dataCell{i} = G(:, idx_theta); % all repetitions at chosen theta
end
% --- Convert reference/parameter values to numeric arrays ---
scanRefArray = cell2mat(scan_reference_values(:)); % nParams × 2
scanParamArray = cell2mat(scan_parameter_values(:)); % nTotal × 2
BFields = sort(unique(scanRefArray(:,1)), 'ascend'); % rows
alphas = sort(unique(scanRefArray(:,2)), 'ascend'); % cols
nB = numel(BFields);
nA = numel(alphas);
% --- Preallocate data matrix ---
data_matrix = NaN(nB, nA);
% --- Fill matrix by looping over unique parameter pairs ---
for k = 1:size(scanRefArray,1)
B = scanRefArray(k,1);
alpha = scanRefArray(k,2);
row = find(ismembertol(BFields, B, 1e-6));
col = find(ismembertol(alphas, alpha, 1e-6));
if isempty(row) || isempty(col), continue; end
repIdx = find(ismembertol(scanParamArray, [B alpha], 1e-6, 'ByRows', true));
if isempty(repIdx), continue; end
% Extract mean g² across repetitions
vals = cellfun(@(x) mean(x, 'omitnan'), dataCell(repIdx));
data_matrix(row,col) = mean(vals, 'omitnan');
end
% --- Create figure ---
if isempty(opts.FigNum)
fig = figure;
else
fig = figure(opts.FigNum);
end
clf(fig);
set(fig, 'Color', 'w', 'Position', [100 100 950 750]);
% --- Plot heatmap ---
imagesc(alphas, BFields, data_matrix);
set(gca, ...
'FontName', opts.FontName, ...
'FontSize', opts.FontSize, ...
'YDir', 'normal', ...
'ColorScale', opts.ColorScale); % linear or log
% --- Labels and title ---
xlabel(opts.XLabel, 'Interpreter', 'tex', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
ylabel(opts.YLabel, 'Interpreter', 'tex', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
% --- Compute fraction of pi ---
theta_factor = theta_query / pi; % e.g., pi/6 -> 1/6
% --- Format as string ---
if abs(round(1/theta_factor) - 1/theta_factor) < 1e-6 % e.g., 1/6
theta_str = sprintf('\\pi/%d', round(1/theta_factor));
elseif abs(theta_factor - round(theta_factor)) < 1e-6 % e.g., pi or 2*pi
theta_str = sprintf('%d\\pi', round(theta_factor));
else
theta_str = sprintf('%.3g \\pi', theta_factor); % fallback numeric
end
% --- Set title ---
title(sprintf('%s | Mean g^{(2)}(\\delta\\theta) at \\delta\\theta = %s', opts.Title, theta_str), ...
'FontName', opts.FontName, 'FontSize', opts.FontSize + 2, 'FontWeight', 'bold');
% --- Colorbar ---
colormap(feval(opts.Colormap));
if ~isempty(opts.CLim)
caxis(opts.CLim);
end
c = colorbar;
% --- Save figure ---
if ~opts.SkipSaveFigures
if ~exist(opts.SaveDirectory,'dir'), mkdir(opts.SaveDirectory); end
savefig(fig, fullfile(opts.SaveDirectory, opts.SaveFileName));
end
end

View File

@ -118,7 +118,7 @@ function plotG2PDF(results, theta_query, varargin)
end end
% --- Set title --- % --- Set title ---
title(sprintf('%s | g^{(2)}(\\delta\\theta) at \\theta = %s', opts.Title, theta_str), ... title(sprintf('%s | g^{(2)}(\\delta\\theta) at \\delta\\theta = %s', opts.Title, theta_str), ...
'FontName', opts.FontName, 'FontSize', opts.FontSize + 2, 'FontWeight', 'bold'); 'FontName', opts.FontName, 'FontSize', opts.FontSize + 2, 'FontWeight', 'bold');
colormap(feval(opts.Colormap)); colormap(feval(opts.Colormap));

View File

@ -1,9 +1,10 @@
function plotHeatmap(results_all, x_values, y_values, fieldName, varargin) function plotHeatmap(results, scan_parameter_values, scan_reference_values, fieldName, varargin)
%% plotHeatmap: Plots a heatmap for a field in a struct array. %% plotHeatmap: Plots a heatmap for a field in a struct array.
% %
% Usage: % Usage:
% plotHeatmap(results_all, x_values, y_values, fieldName, ... % plotHeatmap(results, scan_parameter_values, scan_reference_values, 'energy', ...
% 'FigNum', 1, 'Colormap', parula, 'CLim', [0 1], ... % 'FigNum', 1, 'Colormap', parula, 'CLim', [0 1], ...
% 'ColorScale', 'log', ...
% 'XLabel', '\alpha (degrees)', 'YLabel', 'BField (G)', ... % 'XLabel', '\alpha (degrees)', 'YLabel', 'BField (G)', ...
% 'Title', 'My Title', 'SaveFileName', 'heatmap.fig', ... % 'Title', 'My Title', 'SaveFileName', 'heatmap.fig', ...
% 'SaveDirectory', 'results', 'SkipSaveFigures', false); % 'SaveDirectory', 'results', 'SkipSaveFigures', false);
@ -13,6 +14,7 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
addParameter(p, 'FigNum', []); addParameter(p, 'FigNum', []);
addParameter(p, 'Colormap', parula); addParameter(p, 'Colormap', parula);
addParameter(p, 'CLim', []); addParameter(p, 'CLim', []);
addParameter(p, 'ColorScale', 'linear', @(x) any(validatestring(x,{'linear','log'}))); % NEW
addParameter(p, 'XLabel', '\alpha (degrees)'); addParameter(p, 'XLabel', '\alpha (degrees)');
addParameter(p, 'YLabel', 'BField (G)'); addParameter(p, 'YLabel', 'BField (G)');
addParameter(p, 'Title', fieldName); addParameter(p, 'Title', fieldName);
@ -24,17 +26,32 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
parse(p, varargin{:}); parse(p, varargin{:});
opts = p.Results; opts = p.Results;
N_y = length(results_all); % --- Convert reference/parameter values to numeric arrays ---
N_x = length(x_values); scanRefArray = cell2mat(scan_reference_values(:)); % nParams × 2
scanParamArray = cell2mat(scan_parameter_values(:)); % nTotal × 2
BFields = sort(unique(scanRefArray(:,1)), 'ascend'); % rows
alphas = sort(unique(scanRefArray(:,2)), 'ascend'); % cols
nB = numel(BFields);
nA = numel(alphas);
% --- Preallocate data matrix --- % --- Preallocate data matrix ---
data_matrix = NaN(N_y, N_x); data_matrix = NaN(nB, nA);
for i = 1:N_y
if isfield(results_all(i), fieldName) % --- Fill matrix by looping over unique parameter pairs ---
data_matrix(i, :) = results_all(i).(fieldName); for k = 1:size(scanRefArray,1)
else B = scanRefArray(k,1);
warning('Field "%s" does not exist in results_all(%d). Filling with NaN.', fieldName, i); alpha = scanRefArray(k,2);
end
row = find(ismembertol(BFields, B, 1e-6));
col = find(ismembertol(alphas, alpha, 1e-6));
if isempty(row) || isempty(col), continue; end
repIdx = find(ismembertol(scanParamArray, [B alpha], 1e-6, 'ByRows', true));
if isempty(repIdx), continue; end
vals = results.(fieldName)(repIdx);
data_matrix(row,col) = mean(vals, 'omitnan');
end end
% --- Create figure --- % --- Create figure ---
@ -44,20 +61,24 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
fig = figure(opts.FigNum); fig = figure(opts.FigNum);
end end
clf(fig); clf(fig);
set(fig, 'Color', 'w', 'Position', [50 50 950 750]); set(fig, 'Color', 'w', 'Position', [100 100 950 750]);
% --- Plot heatmap --- % --- Plot heatmap ---
imagesc(x_values, y_values, data_matrix); imagesc(alphas, BFields, data_matrix);
colormap(opts.Colormap); colormap(feval(opts.Colormap));
if ~isempty(opts.CLim) if ~isempty(opts.CLim)
caxis(opts.CLim); caxis(opts.CLim);
end end
set(gca, 'FontName', opts.FontName, 'FontSize', opts.FontSize, 'YDir', 'normal'); set(gca, ...
'FontName', opts.FontName, ...
'FontSize', opts.FontSize, ...
'YDir', 'normal', ...
'ColorScale', opts.ColorScale); % <-- linear or log
% --- Labels and title --- % --- Labels and title ---
xlabel(opts.XLabel, 'Interpreter', 'tex', 'FontName', opts.FontName, 'FontSize', opts.FontSize); xlabel(opts.XLabel, 'Interpreter', 'tex', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
ylabel(opts.YLabel, 'Interpreter', 'tex', 'FontName', opts.FontName, 'FontSize', opts.FontSize); ylabel(opts.YLabel, 'Interpreter', 'tex', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
title(opts.Title, 'Interpreter', 'latex', 'FontSize', opts.FontSize + 2, 'FontWeight', 'bold'); title(opts.Title, 'Interpreter', 'latex', 'FontName', opts.FontName, 'FontSize', opts.FontSize + 2, 'FontWeight', 'bold');
colorbar; colorbar;
% --- Save figure --- % --- Save figure ---
@ -65,5 +86,4 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
'SaveFileName', opts.SaveFileName, ... 'SaveFileName', opts.SaveFileName, ...
'SaveDirectory', opts.SaveDirectory, ... 'SaveDirectory', opts.SaveDirectory, ...
'SkipSaveFigures', opts.SkipSaveFigures); 'SkipSaveFigures', opts.SkipSaveFigures);
end end

View File

@ -100,9 +100,9 @@ function plotPDF(dataCell, referenceValues, varargin)
ylabel(c, 'PDF', 'FontName', opts.FontName, 'FontSize', opts.FontSize); ylabel(c, 'PDF', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
else else
if opts.NormalizeHistogram if opts.NormalizeHistogram
ylabel(c, 'Probability Density', 'FontName', opts.FontName, 'FontSize', opts.FontSize); ylabel(c, 'Probability Density', 'Rotation', -90, 'FontName', opts.FontName, 'FontSize', opts.FontSize);
else else
ylabel(c, 'Counts', 'FontName', opts.FontName, 'FontSize', opts.FontSize); ylabel(c, 'Counts', 'FontName', 'Rotation', -90, opts.FontName, 'FontSize', opts.FontSize);
end end
end end

View File

@ -1,5 +1,5 @@
%% --- User chooses which dataset to load --- %% --- User chooses which dataset to load ---
datasetIdx = 6; % <-- change this to 1, 2, 3, ... datasetIdx = 1; % <-- change this to 1, 2, 3, ...
datasetName = sprintf('Dataset_%d', datasetIdx); datasetName = sprintf('Dataset_%d', datasetIdx);
% --- Base directory selection --- % --- Base directory selection ---

View File

@ -91,9 +91,6 @@ end
[od_imgs, scan_parameter_values, scan_reference_values, ~] = Helper.collectODImages(options); [od_imgs, scan_parameter_values, scan_reference_values, ~] = Helper.collectODImages(options);
% === Plot raw images === % === Plot raw images ===
n_total = numel(scan_parameter_values);
nParams = numel(scan_reference_values);
nReps = n_total/nParams;
% Select every 10th repetition % Select every 10th repetition
selected_reps = [1, 10, 20, 30, 40, 50]; selected_reps = [1, 10, 20, 30, 40, 50];

View File

@ -1,32 +1,99 @@
BFieldRange = [2.45 2.44 2.43 2.42 2.40 2.39 2.38 2.37 2.36 2.35 2.34 2.32 2.30 2.28 2.25 2.20 2.15 2.10 2.05 2.00 1.95 1.90 1.85 1.80]; %% --- User chooses which dataset to load ---
AlphaRange = [180 175 170 168 166 164 162 160 158 156 154 152 150 145 140]; datasetIdx = 1; % <-- change this to 1, 2, 3, ...
datasetName = sprintf('Dataset_%d', datasetIdx);
% Z must be 15x24 to match y-by-x % --- Base directory selection ---
Z = zeros([numel(BFieldRange), numel(AlphaRange)]);... % your data useLocalBaseDir = false; % <-- set true to use script location, false to use manual path
[X,Y] = meshgrid(x, y); if useLocalBaseDir
% Use folder where this script is located
thisScriptPath = mfilename('fullpath');
[thisScriptDir, ~, ~] = fileparts(thisScriptPath);
baseDir = fullfile(thisScriptDir, 'Results');
else
% Use manually specified folder
% baseDir = 'E:\Results - Experiment\202508\BECToDropletsToStripes\';
baseDir = 'C:\Users\Karthik-OfficePC\Documents\GitRepositories\Calculations\Data-Analyzer\+Scripts\PhaseDiagram\Results';
end
% --- Build paths ---
dataFile = fullfile(baseDir, 'SavedData', [datasetName '.mat']);
figSaveDir = fullfile(baseDir, 'SavedFigures', datasetName);
% --- Load dataset ---
data = load(dataFile);
% --- Ensure figure folder exists ---
if ~exist(figSaveDir, 'dir')
mkdir(figSaveDir);
end
% --- Access dataset struct dynamically ---
datasetStruct = data.(datasetName);
compiled_results = datasetStruct.results;
scan_parameter_values = datasetStruct.scan_parameter_values;
scan_reference_values = datasetStruct.scan_reference_values;
% --- Load options used during analysis ---
options = datasetStruct.options;
options.font = 'Bahnschrift'; % override if needed
options.skipSaveFigures = false; % override if needed
%% ------------------ Plot Heatmaps ------------------ %% ------------------ Plot Heatmaps ------------------
% Heatmap of radial_spectral_contrast % Heatmap of radial_spectral_contrast
Plotter.plotHeatmap(compiled_results, scan_reference_values, BFields, 'radial_spectral_contrast', ... Plotter.plotHeatmap(compiled_results.spectral_analysis_results, scan_parameter_values, scan_reference_values, 'radial_spectral_contrast', ...
'Colormap', @sky, ... 'Colormap', @Colormaps.coolwarm, ...
'CLim', [0 0.008], ... 'ColorScale', 'log', ...
'XLabel', '\alpha (degrees)', ... 'XLabel', '\alpha (degrees)', ...
'YLabel', 'BField (G)', ... 'YLabel', 'BField (G)', ...
'Title', 'Radial Spectral Contrast', ... 'Title', 'Radial Spectral Contrast', ...
'FigNum', 10, ... 'FontName', options.font, ...
'FigNum', 9, ...
'SaveFileName', 'Heatmap_RadialSpectralContrast.fig', ... 'SaveFileName', 'Heatmap_RadialSpectralContrast.fig', ...
'SaveDirectory', options.saveDirectory); 'SaveDirectory', options.saveDirectory);
% Heatmap of mean_max_g2_values %% Heatmap of mean_max_g2_values
Plotter.plotHeatmap(compiled_results, scan_reference_values, BFields, 'mean_max_g2_values', ... Plotter.plotHeatmap(compiled_results.custom_g_results, scan_parameter_values, scan_reference_values, 'mean_max_g2', ...
'Colormap', @sky, ... 'Colormap', @Colormaps.coolwarm, ...
'CLim', [0 1], ... 'ColorScale', 'linear', ...
'XLabel', '\alpha (degrees)', ... 'XLabel', '\alpha (degrees)', ...
'YLabel', 'BField (G)', ... 'YLabel', 'BField (G)', ...
'Title', '$\mathrm{max}[g^{(2)}_{[50,70]}(\delta\theta)]$', ... 'Title', '$\mathrm{max}[g^{(2)}_{[50,70]}(\delta\theta)]$', ...
'FigNum', 9, ... 'FontName', options.font, ...
'FigNum', 10, ...
'SaveFileName', 'Heatmap_MaxG2.fig', ... 'SaveFileName', 'Heatmap_MaxG2.fig', ...
'SaveDirectory', options.saveDirectory); 'SaveDirectory', options.saveDirectory);
%% Heatmap of mean g2 values as specific theta
Plotter.plotG2MeanHeatmap(compiled_results.full_g2_results, pi/2, ...
scan_parameter_values, scan_reference_values, ...
'Colormap', @Colormaps.coolwarm, ...
'CLim', [0 1.0], ...
'ColorScale', 'log', ...
'XLabel', '\alpha (degrees)', ...
'YLabel', 'BField (G)', ...
'Title', options.titleString, ...
'FontName', options.font, ...
'FigNum', 11, ...
'SaveFileName', 'Heatmap_MeanG2.fig', ...
'SaveDirectory', options.saveDirectory);
%% G2 curves across phase diagram
Plotter.plotG2CurvesMultiParam(compiled_results.full_g2_results, ...
scan_parameter_values, scan_reference_values, ...
[2.45, 2.35, 2.32, 2.28], ...
[0, 10, 20, 30, 40], ...
'FigNum', 12, ...
'FontName', options.font, ...
'FontSize', 14, ...
'Title', options.titleString, ...
'Param1Name', 'B', ...
'Param2Name', '\alpha', ...
'HighlightEvery', 5, ...
'SkipSaveFigures', false, ...
'SaveFileName', 'G2Curves_PhaseDiagram.fig', ...
'SaveDirectory', options.saveDirectory);

View File

@ -4,7 +4,7 @@
dataSources = { dataSources = {
struct('sequence', 'StructuralPhaseTransition', ... struct('sequence', 'StructuralPhaseTransition', ...
'date', '2025/08/20', ... 'date', '2025/08/20', ...
'runs', [2]) % specify run numbers as a string in "" or just as a numeric value 'runs', [1]) % specify run numbers as a string in "" or just as a numeric value
}; };
options = struct(); options = struct();
@ -56,7 +56,7 @@ options.skipFullODImagesFolderUse = false;
options.skipSaveData = false; options.skipSaveData = false;
options.skipSaveFigures = true; options.skipSaveFigures = true;
options.skipSaveProcessedOD = true; options.skipSaveProcessedOD = true;
options.skipLivePlot = true; options.skipLivePlot = false;
options.showProgressBar = true; options.showProgressBar = true;
% Extras % Extras

View File

@ -0,0 +1,215 @@
%% ===== BEC-Droplets-Stripes Settings =====
% Specify data location to run analysis on
dataSources = {
struct('sequence', 'StructuralPhaseTransition', ...
'date', '2025/08/20', ...
'runs', [1]) % specify run numbers as a string in "" or just as a numeric value
};
options = struct();
% File paths
options.baseDataFolder = '//DyLabNAS/Data';
options.FullODImagesFolder = 'E:/Data - Experiment/FullODImages/202508';
options.measurementName = 'DropletsToStripes';
scriptFullPath = mfilename('fullpath');
options.saveDirectory = fileparts(scriptFullPath);
% Camera / imaging settings
options.cam = 4; % 1 - ODT_1_Axis_Camera; 2 - ODT_2_Axis_Camera; 3 - Horizontal_Axis_Camera;, 4 - Vertical_Axis_Camera;
options.angle = 0; % angle by which image will be rotated
options.center = [1420, 2050];
options.span = [200, 200];
options.fraction = [0.1, 0.1];
options.pixel_size = 5.86e-6; % in meters
options.magnification = 24.6;
options.ImagingMode = 'HighIntensity';
options.PulseDuration = 5e-6; % in s
% Fourier analysis settings
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
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;
% Flags
options.skipUnshuffling = false;
options.skipNormalization = false;
options.skipFringeRemoval = true;
options.skipPreprocessing = true;
options.skipMasking = true;
options.skipIntensityThresholding = true;
options.skipBinarization = true;
options.skipFullODImagesFolderUse = false;
options.skipSaveData = false;
options.skipSaveFigures = true;
options.skipSaveProcessedOD = true;
options.skipLivePlot = false;
options.showProgressBar = true;
% Extras
options.font = 'Bahnschrift';
switch options.measurementName
case 'DropletsToStripes'
options.ignore_scan_parameter = {'ps_rot_mag_field'}; % Parameter to IGNORE from these - rot_mag_field, ps_rot_mag_field, ps_rot_mag_fin_pol_angle
options.flipSortOrder = true;
options.scanParameterUnits = {'gauss','degrees'};
options.titleString = 'Droplets to Stripes';
case 'StripesToDroplets'
options.ignore_scan_parameter = {'ps_rot_mag_field'}; % Parameter to IGNORE from these - rot_mag_field, ps_rot_mag_field, ps_rot_mag_fin_pol_angle
options.flipSortOrder = false;
options.scanParameterUnits = {'gauss','degrees'};
options.titleString = 'Stripes to Droplets';
end
%% ===== Collect Images and Launch Viewer =====
[options.selectedPath, options.folderPath] = Helper.selectDataSourcePath(dataSources, options);
[od_imgs, scan_parameter_values, scan_reference_values, ~] = Helper.collectODImages(options);
%% === Plot raw images ===
% === User selection of BFields and alpha values ===
BFieldsToPlot = [2.45, 2.4, 2.35, 2.34, 2.32, 2.3, 2.28]; % [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.1, 2.05, 2.0, 1.95, 1.90, 1.85, 1.8] G
alphasToPlot = [0, 5, 10, 20, 30, 40]; % [0, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 35, 40] degrees
% --- Convert scan_reference_values (cell array of 1x2) into Nx2 array ---
scanRefArray = cell2mat(scan_reference_values(:)); % Nx2
scanParamArray = cell2mat(scan_parameter_values(:)); % Nx2
BFieldVals = scanRefArray(:,1);
alphaVals = scanRefArray(:,2);
% --- Select subset of scan_reference_values to plot ---
keepIdx = ismembertol(BFieldVals, BFieldsToPlot, 1e-6) & ...
ismembertol(alphaVals, alphasToPlot, 1e-6);
scan_reference_values_plot = scan_reference_values(keepIdx);
nParamsPlot = numel(scan_reference_values_plot);
% --- Warn about missing values ---
existingB = BFieldsToPlot(ismembertol(BFieldsToPlot, unique(BFieldVals), 1e-6));
missingB = setdiff(BFieldsToPlot, existingB);
existingA = alphasToPlot(ismembertol(alphasToPlot, unique(alphaVals), 1e-6));
missingA = setdiff(alphasToPlot, existingA);
if ~isempty(missingB)
warning('The following BFields were not found: %s', num2str(missingB));
end
if ~isempty(missingA)
warning('The following alpha values were not found: %s', num2str(missingA));
end
BFieldsPlot = existingB;
alphasPlot = existingA;
% --- Collect all repetitions for each kept parameter ---
od_imgs_grouped = cell(nParamsPlot, 1);
for k = 1:nParamsPlot
paramVal = scan_reference_values_plot{k}; % 1x2 vector [BField, alpha]
% Find all repetitions matching this parameter pair (BField, alpha)
repIdx = find(ismembertol(scanParamArray, paramVal, 1e-6, 'ByRows', true));
% Store images + parameter values
od_imgs_grouped{k} = od_imgs(repIdx);
end
% === Plot OD images as a phase diagram ===
% Unique values for axes
BFieldsPlot = sort(unique(cellfun(@(c) c(1), scan_reference_values_plot)), 'descend'); % y-axis
alphasPlot = sort(unique(cellfun(@(c) c(2), scan_reference_values_plot))); % x-axis
nB = numel(BFieldsPlot);
nA = numel(alphasPlot);
repToPlot = 1; % which repetition to show
% Create figure
figure(300); clf;
set(gcf, 'Position', [100 100 950 750]);
t = tiledlayout(nB, nA, 'TileSpacing', 'compact', 'Padding', 'compact');
font = 'Bahnschrift';
allAxes = gobjects(nB, nA);
% Loop over rows (BFields) and columns (alphas)
for r = 1:nB
B = BFieldsPlot(r);
for c = 1:nA
alpha = alphasPlot(c);
ax = nexttile((r-1)*nA + c);
allAxes(r,c) = ax;
% Find the index k corresponding to this (BField, alpha) pair
k = find(cellfun(@(v) all(abs(v - [B alpha]) < 1e-6), scan_reference_values_plot), 1);
if ~isempty(k)
img = od_imgs_grouped{k}{repToPlot};
imagesc(ax, img);
else
% If missing, leave blank
axis(ax, 'off');
continue
end
set(ax, 'YDir', 'normal');
axis(ax, 'image');
ax.DataAspectRatioMode = 'manual';
ax.PlotBoxAspectRatioMode = 'auto';
ax.XTick = [];
ax.YTick = [];
colormap(ax, Colormaps.inferno());
end
end
% Shared colorbar
cb = colorbar('Location', 'eastoutside');
ylabel(cb, 'Optical Density');
cb.Layout.Tile = 'east';
cb.FontName = font;
cb.FontSize = 18;
cb.Label.FontSize = 20;
cb.Label.Rotation = -90;
cb.Label.VerticalAlignment = 'bottom';
cb.Label.HorizontalAlignment = 'center';
cb.Direction = 'normal';
% Label alpha values along bottom
for c = 1:nA
ax = allAxes(end, c);
ax.XTick = size(img,2)/2;
ax.XTickLabel = sprintf('%.0f°', alphasPlot(c));
ax.XTickLabelRotation = 45;
ax.FontName = font;
ax.FontSize = 16;
end
% Label BFields along left
for r = 1:nB
ax = allAxes(r, 1);
ax.YTick = size(img,1)/2;
ax.YTickLabel = sprintf('%.2f G', BFieldsPlot(r));
ax.FontName = font;
ax.FontSize = 16;
end
% Figure title
title(t, sprintf('%s', options.titleString), ...
'FontSize', 24, 'FontName', font, 'FontWeight', 'bold');