How do I extract data from MATLAB figures?
Show older comments
I have a few MATLAB figures, but no MATLAB code associated with it. I want to extract the data from the curves in the figures.
Accepted Answer
More Answers (2)
Felipe Bittencourt de Souza
on 15 Dec 2017
I was having the same error message mentioned before: "Error using get Conversion to double from cell is not possible."
I solved this issue with Walter Roberson's answer, using the following code:
open('example.fig');
a = get(gca,'Children');
xdata = get(a, 'XData');
ydata = get(a, 'YData');
zdata = get(a, 'ZData');
Yair Altman
on 21 May 2018
Edited: MathWorks Support Team
on 19 Apr 2021
8 votes
Note that the official MathWorks answer above relies on opening and displaying the figure (using the open() function) before extracting its contents. This is both slow and potentially unwanted (we don't always want to display the figures), especially if we're looping over many FIG files.
Instead, users can directly read and analyze the *.fig file by loading it into Matlab memory using the load() function, since *.fig files are basically simple MAT files with a .fig (rather than .mat) file extension.
Fortunately, the internal format of these files has changed very little over the years - a few fields have changed their name, but the basic file data structure remained the same. So essentially the same code can be used to extract data from .fig files created a decade ago, as well as the latest Matlab release.
Note that the fact that FIG files are basically just MAT files is an undocumented feature of Matlab, and so it might change one day. But for now it is a very handy feature to use.
2 Comments
Walter Roberson
on 20 Apr 2022
fig = openfig('figure.fig');
all_ax = findobj(fig, 'type', 'axes');
all_titles = cellfun(@(T) T.String, get(all_ax, 'title'), 'uniform', 0);
all_lines = arrayfun(@(A) findobj(A, 'type', 'line'), all_ax, 'uniform', 0);
all_XData = cellfun(@(L) get(L,'XData'), all_lines, 'uniform', 0);
all_YData = cellfun(@(L) get(L,'YData'), all_lines, 'uniform', 0);
At this point,
- all_titles is a cell array of character vectors containing the title for each axes (in latex form)
- all_XData is a cell array with one entry for each axes, and the entry is a cell array of numeric row vectors, one entry for each line in the axes
- all_YData is a cell array with one entry for each axes, and the entry is a cell array of numeric row vectors, one entry for each line in the axes
WIth that figure, there are three lines in almost all of the axes, but one of them has four lines (the legend which is attached to one of the axes only has three names defined.)
Walter Roberson
on 22 Apr 2022
[filename, filepath] = uigetfile('*.fig');
if ~ischar(filename)
error('cancel');
end
fullname = fullfile(filepath, filename);
fig = openfig(fullname);
all_ax = findobj(fig, 'type', 'axes');
all_titles = cellfun(@(T) T.String, get(all_ax, 'title'), 'uniform', 0);
all_lines = arrayfun(@(A) findobj(A, 'type', 'line'), all_ax, 'uniform', 0);
all_XData = cellfun(@(L) get(L,'XData'), all_lines, 'uniform', 0);
all_YData = cellfun(@(L) get(L,'YData'), all_lines, 'uniform', 0);
for axIdx = 1 : numel(all_YData)
if iscell(all_YData{axIdx})
mask = cellfun(@(Y) ~isequal(Y, [0 0]), all_YData{axIdx});
all_XData{axIdx} = all_XData{axIdx}(mask);
all_YData{axIdx} = all_YData{axIdx}(mask);
else
all_XData{axIdx} = {all_XData{axIdx}};
all_YData{axIdx} = {all_YData{axIdx}};
end
end
This code permits you to select a .fig file, and processes it. It outputs a cell array of character vectors named all_titles . It outputs a cell array named all_XData in which there is one celll array entry for each axes, that contains an entry for each line inside the axes, that is the line x coordinates. It outputs a cell array named all_YData in which there is one celll array entry for each axes, that contains an entry for each line inside the axes, that is the line y coordinates. The coordinate entries have been filtered to remove any lines with Y coordinate [0 0]
The difference between this code and the previous version is that this version filters out lines where the y coordinate is just [0 0]. This version also accounts for the possibility that an axes only has one line.
In the case where the axes had more than one line, the internal get() call would have returned a cell array of coordinates, but in the case where the axes had exactly one line, the internal get() call would have returned the numeric coordinates directly: this code detects the single-line case and deliberately wraps it inside a cell array, so that the outputs are consistent.
So, for axes #K,all_titles{K} is a character vector that is the axes title, and all_XData{K} is a cell array with one entry per line inside the axes for the X coordinates, and all_YData{K} is a cell array with one entry per line inside the axes for the Y coordinates.
This code does not assume that all of the lines inside an axes have the same number of points. If you are willing to assume that, then you can process the arrays further by
XData_matrices = cellfun(@cell2mat, all_XData);
YData_matrices = cellfun(@cell2mat, all_YData);
and then those would be cell arrays with one entry per axes, and the entries would be N x L numeric arrays where N is the number of lines and L is the number of points in the line.
Categories
Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!