263 lines
9.4 KiB
Matlab
263 lines
9.4 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)
|
|
|
|
% 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
|
|
|
|
% Check if this axes uses yyaxis
|
|
isYYAxis = isprop(ax, 'YAxis') && numel(ax.YAxis) == 2;
|
|
if isYYAxis
|
|
sidesToProcess = {'left', 'right'};
|
|
else
|
|
sidesToProcess = {'single'};
|
|
end
|
|
|
|
% 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 through both sides if yyaxis is used, otherwise process normally once
|
|
for s = 1:length(sidesToProcess)
|
|
|
|
if isYYAxis
|
|
yyaxis(ax, sidesToProcess{s}); % Switch active side to expose its lines and label
|
|
end
|
|
|
|
% Get axis titles (now correctly tied to the active side)
|
|
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 active side
|
|
children = get(ax, 'Children');
|
|
|
|
% Reverse so we extract in creation order to match the legend
|
|
if ~isempty(children)
|
|
children = flipud(children(:));
|
|
end
|
|
|
|
% Loop over all child graphics objects for this side
|
|
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: prefer internal DisplayName to fix yyaxis mismatch
|
|
label = '';
|
|
if isprop(obj, 'DisplayName') && ~isempty(obj.DisplayName)
|
|
label = obj.DisplayName;
|
|
elseif 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
|
|
label = '';
|
|
if isprop(obj, 'DisplayName') && ~isempty(obj.DisplayName)
|
|
label = obj.DisplayName;
|
|
elseif 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
|
|
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 |