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 θ ---
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 ---
lineStyles = {'-', '--'}; % solid for dataset1, dashed for dataset2
% --- Colors per θ (generalized, using only ends of coolwarm) ---
% --- Colors per θ ---
%{
cmapFull = Colormaps.coolwarm(256);
Ntheta = numel(thIdx);
% pick start and end colors
startColor = cmapFull(1, :); % deep blue
endColor = cmapFull(end, :); % deep red
% interpolate RGB linearly between start and end for Ntheta points
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 ---
@ -85,7 +88,7 @@ function plotAndCompareG2Cumulants(results1, results2, varargin)
% Dataset 1 -> solid line + marker
plot(ax, x1, squeeze(kappa1(th,:,k)), ...
'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);
% 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
% --- 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');
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.
%
% 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], ...
% 'ColorScale', 'log', ...
% 'XLabel', '\alpha (degrees)', 'YLabel', 'BField (G)', ...
% 'Title', 'My Title', 'SaveFileName', 'heatmap.fig', ...
% 'SaveDirectory', 'results', 'SkipSaveFigures', false);
@ -13,6 +14,7 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
addParameter(p, 'FigNum', []);
addParameter(p, 'Colormap', parula);
addParameter(p, 'CLim', []);
addParameter(p, 'ColorScale', 'linear', @(x) any(validatestring(x,{'linear','log'}))); % NEW
addParameter(p, 'XLabel', '\alpha (degrees)');
addParameter(p, 'YLabel', 'BField (G)');
addParameter(p, 'Title', fieldName);
@ -24,17 +26,32 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
parse(p, varargin{:});
opts = p.Results;
N_y = length(results_all);
N_x = length(x_values);
% --- 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(N_y, N_x);
for i = 1:N_y
if isfield(results_all(i), fieldName)
data_matrix(i, :) = results_all(i).(fieldName);
else
warning('Field "%s" does not exist in results_all(%d). Filling with NaN.', fieldName, i);
end
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
vals = results.(fieldName)(repIdx);
data_matrix(row,col) = mean(vals, 'omitnan');
end
% --- Create figure ---
@ -44,20 +61,24 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
fig = figure(opts.FigNum);
end
clf(fig);
set(fig, 'Color', 'w', 'Position', [50 50 950 750]);
set(fig, 'Color', 'w', 'Position', [100 100 950 750]);
% --- Plot heatmap ---
imagesc(x_values, y_values, data_matrix);
colormap(opts.Colormap);
imagesc(alphas, BFields, data_matrix);
colormap(feval(opts.Colormap));
if ~isempty(opts.CLim)
caxis(opts.CLim);
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 ---
xlabel(opts.XLabel, '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;
% --- Save figure ---
@ -65,5 +86,4 @@ function plotHeatmap(results_all, x_values, y_values, fieldName, varargin)
'SaveFileName', opts.SaveFileName, ...
'SaveDirectory', opts.SaveDirectory, ...
'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);
else
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
ylabel(c, 'Counts', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
ylabel(c, 'Counts', 'FontName', 'Rotation', -90, opts.FontName, 'FontSize', opts.FontSize);
end
end

View File

@ -1,5 +1,5 @@
%% --- 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);
% --- Base directory selection ---

View File

@ -91,9 +91,6 @@ end
[od_imgs, scan_parameter_values, scan_reference_values, ~] = Helper.collectODImages(options);
% === Plot raw images ===
n_total = numel(scan_parameter_values);
nParams = numel(scan_reference_values);
nReps = n_total/nParams;
% Select every 10th repetition
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];
AlphaRange = [180 175 170 168 166 164 162 160 158 156 154 152 150 145 140];
%% --- User chooses which dataset to load ---
datasetIdx = 1; % <-- change this to 1, 2, 3, ...
datasetName = sprintf('Dataset_%d', datasetIdx);
% Z must be 15x24 to match y-by-x
Z = zeros([numel(BFieldRange), numel(AlphaRange)]);... % your data
% --- Base directory selection ---
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 ------------------
% Heatmap of radial_spectral_contrast
Plotter.plotHeatmap(compiled_results, scan_reference_values, BFields, 'radial_spectral_contrast', ...
'Colormap', @sky, ...
'CLim', [0 0.008], ...
Plotter.plotHeatmap(compiled_results.spectral_analysis_results, scan_parameter_values, scan_reference_values, 'radial_spectral_contrast', ...
'Colormap', @Colormaps.coolwarm, ...
'ColorScale', 'log', ...
'XLabel', '\alpha (degrees)', ...
'YLabel', 'BField (G)', ...
'Title', 'Radial Spectral Contrast', ...
'FigNum', 10, ...
'FontName', options.font, ...
'FigNum', 9, ...
'SaveFileName', 'Heatmap_RadialSpectralContrast.fig', ...
'SaveDirectory', options.saveDirectory);
% Heatmap of mean_max_g2_values
Plotter.plotHeatmap(compiled_results, scan_reference_values, BFields, 'mean_max_g2_values', ...
'Colormap', @sky, ...
'CLim', [0 1], ...
%% Heatmap of mean_max_g2_values
Plotter.plotHeatmap(compiled_results.custom_g_results, scan_parameter_values, scan_reference_values, 'mean_max_g2', ...
'Colormap', @Colormaps.coolwarm, ...
'ColorScale', 'linear', ...
'XLabel', '\alpha (degrees)', ...
'YLabel', 'BField (G)', ...
'Title', '$\mathrm{max}[g^{(2)}_{[50,70]}(\delta\theta)]$', ...
'FigNum', 9, ...
'FontName', options.font, ...
'FigNum', 10, ...
'SaveFileName', 'Heatmap_MaxG2.fig', ...
'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 = {
struct('sequence', 'StructuralPhaseTransition', ...
'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();
@ -56,7 +56,7 @@ options.skipFullODImagesFolderUse = false;
options.skipSaveData = false;
options.skipSaveFigures = true;
options.skipSaveProcessedOD = true;
options.skipLivePlot = true;
options.skipLivePlot = false;
options.showProgressBar = true;
% 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');