Files
nappMATLAB-toolbox/utils/exportFigureData.m
T

282 lines
9.3 KiB
Matlab

function exportFigureData(figHandle)
%exportFigureData Export line and scatter plot data to ASCII files
%
% This function extracts x and y data from all line and scatter plots in a
% figure (including tiled layouts) and saves each data series to a separate
% ASCII file. File names are constructed from the figure title, tile title
% (if in a tiled layout), axis labels, and legend entries. Data is limited
% to the current x-axis scale range.
%
% SYNTAX:
% exportFigureData() % Uses current active figure
% exportFigureData(figHandle) % Uses specified figure handle
%
% INPUTS:
% figHandle : figure handle (optional)
% If empty or omitted, the current active figure (gcf) is used.
%
% OUTPUT:
% ASCII files are saved in the current working directory, named as:
% <FigureTitle>_<TileTitle>_<YLabel>_vs_<XLabel>_<LineLabel>.txt
% For non-tiled figures:
% <FigureTitle>_<YLabel>_vs_<XLabel>_<LineLabel>.txt
% Each file contains two columns: X-data and Y-data (tab-delimited)
%
% NOTES:
% - Works with line plots (line objects) and scatter plots (scatter objects)
% - Handles both regular axes and tiled layouts
% - Data outside the x-axis scale limits are excluded
% - Lines without legend entries are named as 'line_N' where N is a counter
% - Scatter plots without legend entries are named as 'scatter_N'
% - Axis labels default to 'x' and 'y' if not set
% - Tile titles are included only for tiled layouts
% - If no figure title is set, 'figure' is used as the base name
%
% EXAMPLE:
% % Create a tiled figure with multiple subplots
% figure
% tiledlayout(2, 1, 'TileSpacing', 'compact')
%
% nexttile
% x = 0:0.1:10;
% plot(x, sin(x), 'DisplayName', 'sin(x)')
% hold on
% plot(x, cos(x), 'DisplayName', 'cos(x)')
% title('Sine and Cosine')
% xlabel('Time (s)')
% ylabel('Amplitude')
% legend
%
% nexttile
% plot(x, sin(x).*cos(x), 'DisplayName', 'sin*cos')
% title('Product')
% xlabel('Time (s)')
% ylabel('Value')
% legend
%
% sgtitle('Trigonometric Functions')
% exportFigureData(gcf)
%
% % Creates files like:
% % Trigonometric_Functions_Sine_and_Cosine_Amplitude_vs_Time_(s)_sin(x).txt
% % Trigonometric_Functions_Sine_and_Cosine_Amplitude_vs_Time_(s)_cos(x).txt
% % Trigonometric_Functions_Product_Value_vs_Time_(s)_sin*cos.txt
%
% See also: tiledlayout, nexttile, legend, line, scatter
% Handle input: use current figure if none provided
if nargin == 0 || isempty(figHandle)
figHandle = gcf;
end
% Get figure title (use sgtitle if available, else Name)
figTitle = '';
sgtitleObjs = findall(figHandle, 'type', 'text', 'Tag', 'sgtitle');
if ~isempty(sgtitleObjs)
figTitle = get(sgtitleObjs(1), 'String');
if iscell(figTitle)
figTitle = figTitle{1};
end
end
if isempty(figTitle)
figTitle = get(figHandle, 'Name');
end
if isempty(figTitle)
figTitle = 'figure';
end
figTitle = sanitizeFilename(figTitle); % Sanitize figure title
% Get all axes in the figure (works for both regular and tiled layouts)
allAxes = findall(figHandle, 'type', 'axes');
if isempty(allAxes)
warning('exportFigureData:NoAxes', 'No axes found in figure.');
return;
end
% Counters for unnamed line and scatter objects
lineCounter = 0;
scatterCounter = 0;
% Loop over all axes
for ii = 1:length(allAxes)
ax = allAxes(ii);
% Skip legend axes and colorbar axes
if strcmp(ax.Tag, 'legend') || strcmp(ax.Tag, 'colorbar')
continue
end
% Get axis titles
xLabel = ax.XLabel.String;
yLabel = ax.YLabel.String;
tileTitle = ax.Title.String;
% Convert to cell if char, then handle empty cases
if ischar(xLabel), xLabel = cellstr(xLabel); end
if ischar(yLabel), yLabel = cellstr(yLabel); end
if ischar(tileTitle), tileTitle = cellstr(tileTitle); end
if isempty(xLabel) || (iscell(xLabel) && isempty(xLabel{1}))
xLabel = 'x';
else
xLabel = xLabel{1};
end
if isempty(yLabel) || (iscell(yLabel) && isempty(yLabel{1}))
yLabel = 'y';
else
yLabel = yLabel{1};
end
if isempty(tileTitle) || (iscell(tileTitle) && isempty(tileTitle{1}))
tileTitle = '';
else
tileTitle = tileTitle{1};
end
% Sanitize axis labels and tile title
xLabel = sanitizeFilename(xLabel);
yLabel = sanitizeFilename(yLabel);
tileTitle = sanitizeFilename(tileTitle);
% Get x-axis limits for filtering
xLims = ax.XLim;
% Get all children of the axes (lines, scatter, etc.)
children = get(ax, 'Children');
% Build a legend object if it exists (for extracting labels)
legendObj = legend(ax);
legendLabels = {};
if ~isempty(legendObj)
legendLabels = legendObj.String;
if ischar(legendLabels)
legendLabels = {legendLabels};
end
end
% Initialize a counter for matching legend entries to graphics objects
graphicsIndex = 0;
% Loop over all child graphics objects
for jj = 1:length(children)
obj = children(jj);
% Check if this is a line object
if isa(obj, 'matlab.graphics.chart.primitive.Line')
graphicsIndex = graphicsIndex + 1;
% Get x and y data
xData = get(obj, 'XData');
yData = get(obj, 'YData');
% Skip if empty
if isempty(xData) || isempty(yData)
continue
end
% Filter data to x-axis range
mask = (xData >= xLims(1)) & (xData <= xLims(2));
xData = xData(mask);
yData = yData(mask);
% Determine label: use legend entry or auto-generate name
if graphicsIndex <= length(legendLabels) && ~isempty(legendLabels{graphicsIndex})
label = legendLabels{graphicsIndex};
else
lineCounter = lineCounter + 1;
label = sprintf('line_%d', lineCounter);
end
% Sanitize label for filename
label = sanitizeFilename(label);
% Create filename with tile title if present
if ~isempty(tileTitle)
fileName = sprintf('%s_%s_%s_vs_%s_%s.txt', figTitle, tileTitle, yLabel, xLabel, label);
else
fileName = sprintf('%s_%s_vs_%s_%s.txt', figTitle, yLabel, xLabel, label);
end
% Write data to ASCII file
data = [xData(:), yData(:)];
writematrix(data, fileName, 'Delimiter', '\t');
fprintf('Saved: %s\n', fileName);
% Check if this is a scatter object
elseif isa(obj, 'matlab.graphics.chart.primitive.Scatter')
graphicsIndex = graphicsIndex + 1;
% Get x and y data
xData = get(obj, 'XData');
yData = get(obj, 'YData');
% Skip if empty
if isempty(xData) || isempty(yData)
continue
end
% Ensure row vectors for indexing
xData = xData(:)';
yData = yData(:)';
% Filter data to x-axis range
mask = (xData >= xLims(1)) & (xData <= xLims(2));
xData = xData(mask);
yData = yData(mask);
% Determine label: use legend entry or auto-generate name
if graphicsIndex <= length(legendLabels) && ~isempty(legendLabels{graphicsIndex})
label = legendLabels{graphicsIndex};
else
scatterCounter = scatterCounter + 1;
label = sprintf('scatter_%d', scatterCounter);
end
% Sanitize label for filename
label = sanitizeFilename(label);
% Create filename with tile title if present
if ~isempty(tileTitle)
fileName = sprintf('%s_%s_%s_vs_%s_%s.txt', figTitle, tileTitle, yLabel, xLabel, label);
else
fileName = sprintf('%s_%s_vs_%s_%s.txt', figTitle, yLabel, xLabel, label);
end
% Write data to ASCII file
data = [xData(:), yData(:)];
writematrix(data, fileName, 'Delimiter', '\t');
fprintf('Saved: %s\n', fileName);
end
end
end
fprintf('Data export complete.\n');
end
% =========================================================================
% Helper function: sanitize strings for use in filenames
% =========================================================================
function cleanStr = sanitizeFilename(str)
%sanitizeFilename Remove or replace characters invalid in filenames
%
% Replaces spaces, slashes, backslashes, colons, asterisks, parentheses,
% and other problematic characters with underscores.
cleanStr = str;
cleanStr = strrep(cleanStr, ' ', '_');
cleanStr = strrep(cleanStr, '/', '_');
cleanStr = strrep(cleanStr, '\', '_');
cleanStr = strrep(cleanStr, ':', '_');
cleanStr = strrep(cleanStr, '*', '_');
cleanStr = strrep(cleanStr, '?', '_');
cleanStr = strrep(cleanStr, '"', '_');
cleanStr = strrep(cleanStr, '<', '_');
cleanStr = strrep(cleanStr, '>', '_');
cleanStr = strrep(cleanStr, '|', '_');
cleanStr = strrep(cleanStr, '(', '_');
cleanStr = strrep(cleanStr, ')', '_');
cleanStr = strrep(cleanStr, '.', '_'); % Optional: replace dots
end