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: % ___vs__.txt % For non-tiled figures: % __vs__.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