Calculations/Data-Analyzer/+Plotter/plotFitParameterPDF.m

151 lines
5.1 KiB
Matlab
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function plotFitParameterPDF(fitResults, scanValues, paramName, varargin)
%% plotFitParameterPDF
% Author: Karthik
% Date: 2025-10-06
% Version: 1.0
%
% Description:
% Plots 2D PDF (heatmap) of any parameter from two-Gaussian fit results
% for multiple scan parameters, with optional overlay of mean ± SEM.
%
% Inputs:
% fitResults - struct array from fitTwoGaussianCurves
% scanValues - vector of scan parameter values
% paramName - string specifying the parameter to plot:
% 'mu1', 'sigma1', 'A2', 'mu2', 'sigma2'
%
% Optional name-value pairs (same as before, plus OverlayMeanSEM):
% 'OverlayMeanSEM' - logical, overlay mean ± SEM (default: true)
% --- Parse optional inputs ---
p = inputParser;
addParameter(p, 'Title', '', @(x) ischar(x) || isstring(x));
addParameter(p, 'XLabel', '', @(x) ischar(x) || isstring(x));
addParameter(p, 'YLabel', '', @(x) ischar(x) || isstring(x));
addParameter(p, 'FigNum', 1, @(x) isscalar(x));
addParameter(p, 'FontName', 'Arial', @ischar);
addParameter(p, 'FontSize', 14, @isnumeric);
addParameter(p, 'SkipSaveFigures', false, @islogical);
addParameter(p, 'SaveFileName', 'FitParameterPDF.fig', @ischar);
addParameter(p, 'SaveDirectory', pwd, @ischar);
addParameter(p, 'NumPoints', 200, @(x) isscalar(x));
addParameter(p, 'DataRange', [], @(x) isempty(x) || numel(x)==2);
addParameter(p, 'XLim', [], @(x) isempty(x) || numel(x)==2);
addParameter(p, 'Colormap', @jet);
addParameter(p, 'PlotType', 'histogram', @(x) any(validatestring(x,{'kde','histogram'})));
addParameter(p, 'NumberOfBins', 50, @isscalar);
addParameter(p, 'NormalizeHistogram', true, @islogical);
addParameter(p, 'OverlayMeanSEM', true, @islogical);
parse(p, varargin{:});
opts = p.Results;
% --- Map paramName to index ---
paramMap = struct('mu1',1,'sigma1',2,'A2',3,'mu2',4,'sigma2',5);
if ~isfield(paramMap,paramName)
error('Invalid paramName. Must be one of: mu1, sigma1, A2, mu2, sigma2');
end
paramIdx = paramMap.(paramName);
% --- Determine repetitions and scan parameters ---
N_params = numel(scanValues);
N_total = numel(fitResults);
N_reps = N_total / N_params;
% --- Extract chosen parameter values ---
paramValues = nan(N_reps, N_params);
for k = 1:N_total
paramIdxScan = mod(k-1, N_params) + 1;
repIdx = floor((k-1)/N_params) + 1;
if fitResults(k).isValid
paramValues(repIdx, paramIdxScan) = fitResults(k).pFit(paramIdx);
end
end
% --- Prepare data per scan parameter ---
dataCell = cell(N_params,1);
for i = 1:N_params
dataCell{i} = paramValues(:,i);
end
% --- Determine y-range ---
if isempty(opts.DataRange)
allData = cell2mat(dataCell(:));
y_min = min(allData);
y_max = max(allData);
else
y_min = opts.DataRange(1);
y_max = opts.DataRange(2);
end
% --- Prepare PDF grid/matrix ---
if strcmpi(opts.PlotType,'kde')
y_grid = linspace(y_min, y_max, opts.NumPoints);
pdf_matrix = zeros(numel(y_grid), N_params);
else
edges = linspace(y_min, y_max, opts.NumberOfBins+1);
binCenters = (edges(1:end-1) + edges(2:end))/2;
pdf_matrix = zeros(numel(binCenters), N_params);
end
% --- Compute PDFs ---
for i = 1:N_params
data = dataCell{i};
data = data(~isnan(data));
if isempty(data), continue; end
if strcmpi(opts.PlotType,'kde')
f = ksdensity(data, y_grid);
pdf_matrix(:,i) = f;
else
counts = histcounts(data, edges);
if opts.NormalizeHistogram
binWidth = edges(2) - edges(1);
counts = counts / (sum(counts) * binWidth);
end
pdf_matrix(:,i) = counts(:);
end
end
% --- Plot heatmap ---
fig = figure(opts.FigNum); clf(fig);
set(fig, 'Color', 'w', 'Position', [100 100 950 750]);
if strcmpi(opts.PlotType,'kde')
imagesc(scanValues, y_grid, pdf_matrix);
else
imagesc(scanValues, binCenters, pdf_matrix);
end
set(gca, 'YDir', 'normal', 'FontName', opts.FontName, 'FontSize', opts.FontSize);
xlabel(opts.XLabel, 'FontSize', opts.FontSize, 'FontName', opts.FontName);
ylabel(opts.YLabel, 'FontSize', opts.FontSize, 'FontName', opts.FontName);
title(opts.Title, 'FontSize', opts.FontSize+2, 'FontWeight', 'bold');
colormap(feval(opts.Colormap));
c = colorbar;
if strcmpi(opts.PlotType,'kde') || opts.NormalizeHistogram
ylabel(c, 'Probability Density', 'Rotation', -90, 'FontName', opts.FontName, 'FontSize', opts.FontSize);
else
ylabel(c, 'Counts', 'Rotation', -90, 'FontName', opts.FontName, 'FontSize', opts.FontSize);
end
if ~isempty(opts.XLim)
xlim(opts.XLim);
end
% --- Overlay mean ± SEM if requested ---
if opts.OverlayMeanSEM
meanParam = nanmean(paramValues,1);
semParam = nanstd(paramValues,0,1) ./ sqrt(sum(~isnan(paramValues),1));
hold on;
xVec = reshape(scanValues, 1, []); % ensures 1 × N_params
fill([xVec, fliplr(xVec)], [meanParam - semParam, fliplr(meanParam + semParam)], ...
[0.2 0.4 0.8], 'FaceAlpha',0.2, 'EdgeColor','none');
plot(scanValues, meanParam, 'k-', 'LineWidth', 2);
end
% --- Save figure ---
if ~opts.SkipSaveFigures
if ~exist(opts.SaveDirectory,'dir'), mkdir(opts.SaveDirectory); end
savefig(fig, fullfile(opts.SaveDirectory, opts.SaveFileName));
end
end