MATLAB Answers

14

How do I extract data from MATLAB figures?

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.

7 Answers

Answer by MathWorks Support Team on 8 Aug 2019 at 4:00
 Accepted Answer

This example shows how to extract data from a MATLAB figure.
If the figure is stored in a file, such as 'example.fig', then open the figure file using 'openfig'. Assign the Figure object to the variable 'fig'.
fig = openfig('example.fig');
If the figure is already open, then use 'gcf' to access the Figure object and assign it to the variable 'fig'.
fig = gcf;
There are several ways to access the data for the plotted graphics objects. You can use the Children property or you can use 'findobj'.
Use Children Property
Access the plotted graphics objects through the Children properties. The Axes objects are children of the figure. The plotted graphics objects are typically children of the Axes object.
axObjs = fig.Children
dataObjs = axObjs.Children
The 'dataObjs' array that appears in the Command Window indicates the types of graphics objects in the axes. Different graphics objects store data differently. For example, Line objects store the data in the 'XData', 'YData', and 'ZData' properties. If the first element in 'dataObjs' is a Line object, then access its data using this code.
x = dataObjs(1).XData
y = dataObjs(1).YData
z = dataObjs(1).ZData
If the figure contains other types of graphics objects, then use the appropriate properties to access the data. For a list of graphics objects and their properties, see:
Use findobj Function
Alternatively, you can find all the graphics objects in a figure with a certain data property. For example, find all graphics objects that have a 'YData' property. Then access the 'YData' values for the first object.
dataObjs = findobj(fig,'-property','YData')
y1 = dataObjs(1).YData

  7 Comments

Hello all,
Just wanted to point out that, if the data were plotted as a 2D matrix (where each row is a different line), none of the solutions on this thread give back the initial matrix (after conversion of YData to a matrix, of course). In fact, the rows in the extracted data are all out of order.
Any thoughts on this? Are lines created/indexed in any particular order when they are plotted from a matrix?
Thanks, Michael
When you plot a matrix by columns, then the order of handles returned from the plot() call is the order of the columns:
data = sort(rand(20,5),2);
h = plot(data);
Now h(1) corresponds to column 1, h(2) corresponds to column 2, and so on. You can confirm this with:
h(1).DisplayName = 'col1';
h(2).DisplayName = 'col2';
h(3).DisplayName = 'col3';
h(4).DisplayName = 'col4';
h(5).DisplayName = 'col5';
legend();
and see that indeed the item labeled col5 is the one with highest average Y (it was constructed that way by the sort() call).
However, the order of axes children defaults to the reverse of this:
>> get(gca,'Children')
ans =
5×1 Line array:
Line (col5)
Line (col4)
Line (col3)
Line (col2)
Line (col1)
because the rule is that the axes children are (by default) painted from last to first (first is on top, last is on bottom). This can be altered in a few ways, including some obscure specialized settings that were new in R2014b, but also the order can be changed with good old uistack()
When you recall a figure file and pull out the axes children, the axes children are going to be in the same order as was present in the axes when it was saved to the figure file. If nothing in the original code altered the order, that is going to be last column first. So if you retrieve the YData and mat2cell() it into a 2D matrix, make sure to fliplr() to get the original order.
Hi all,
Regarding subplots, I found that simply entering in "subplot(n,m,p)" to direct MATLAB to your desired subplot does the trick. Add it before you set a=get(gca,'Children'); There's probably a more clever way of doing it, but it worked for me. I'm using Felipe Bittencourt de Souza's solution below and 2018b.

Sign in to comment.



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');

  0 Comments

Sign in to comment.


Answer by Michael
on 13 Jun 2014
Edited by Michael
on 13 Jun 2014

I tried to follow these steps, but when I got to objTypes = get(dataObjs, 'Type') I got this error:
Error using get Conversion to double from cell is not possible.
I don't know Matlab's figure format and I'm not familiar with Matlab's API for accessing figure data. I'm not sure what this error means.
If anyone else happens upon this: Matlab figures are just ".mat" files. The scipy.io library in Pylab can read Matfiles into numpy structures using the 'loadmat' command. One can then browse the figure data in Python and locate the data.
Edit: one can also step through the figure data in Matlab, by loading the figure using the command "s=load('Figure.fig','-mat')". The solutions using "get" never really worked for me. I think this is because every figure is structured slightly differently, and people are posting solutions that work for a particular figure, but don't generalize well. If you just grab the figure data structure, you can step through it and find what you need.

  3 Comments

I managed to get a similar error when running the line:
dataObjs = get(axesObjs, 'Children');
I'm not entirely sure why it's unable to access the handles using the 'get' method, but changing the code to
dataObjs = axesObjs.Children;
seems to have done the trick. Hope this helps.
i tried all answers and always get an error. i got the converting to double error too and with the last answer i got this error: No appropriate method, property, or field 'Children' for class 'matlab.graphics.Graphics'.
Error in daten_auslesen (line 5) dataObjs = axesObjs.Children; I dont know how to fix this code, so id be happy to get some help.
Julia Mödl : you would have that problem if the axes you were looking at was a placeholder rather than an axes object.
all_axesObjs = findobj(h, 'type', 'axes');
now only examine the items in all_axesObjs.
Or use what I posted earlier,
lineObjs = findobj(dataObjs, 'type', 'line');
xdata = get(lineObjs, 'XData');
ydata = get(lineObjs, 'YData');

Sign in to comment.


Answer by Yair Altman on 21 May 2018
Edited by Yair Altman on 21 May 2018

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.

  0 Comments

Sign in to comment.


Answer by Parrish.Ch on 23 Jul 2015

Hi all,
I noticed people were having issues with getting the following error when attempting to run:
objsTypes = get(dataObjs,'Types')
Error using get Conversion to double from cell is not possible.
I think I have a solution to the issue. For surface plots, I noticed that the children of an axes object (so dataObjs in this case) may contain a subgroup that is a complex cell. You have to use cell2struct to break this cell into it's basic pieces so you can extract the data. Here is the code for my solution:
h = gcf;
axes = get(h,'Children');
dataObjs = get(axes,'Children');
Props = cell2struct(dataObjs,'SurfaceProps',2);
SurfaceData = Props.SurfaceProp;
XData = SurfaceData(3,1).XData;
YData = SurfaceData(3,1).YData;
ZData = SurfaceData(2,1).ZData;
**Before you just copy paste this code, there are a few important things to know.
My variable dataObjs is a 2x1 cell. The first index in the cell is empty but the second index is a 3x1 Group. I have to convert this cell group to a structure that can then be used to access my data. From there, I use cell2struct on the second index to accomplish this. The cell2struct generates a property that is named in the second argument of the cell2struct command ('SurfaceProp' for me). Props.SurfaceProp extracts the various "children" from the 3x1 Group in dataObjs. In my case, I have three objects in Props.SurfaceProp: two light objects and one surface object. The surface object contains the x, y, and z data. My surface object is the third index in the matrix generated by Props.SurfaceProp, so I use SurfaceData(3,1).XData to access the XData handle that is in the third index of the SurfaceData array.
I hope this helps!

  2 Comments

I tried your code. But I got an error.
Undefined function 'cell2struct' for input arguments of type 'matlab.graphics.primitive.world.Group'.
- I typed
which cell2struct
- I got the answer
built-in (/Applications/MATLAB_R2014b.app/toolbox/matlab/datatypes/@cell/cell2struct) % cell method >>
what should I do?
Thanks
Would you have some simple code that recreates this problem? My simple test does not create that kind of group, but it could well be that a different call does.

Sign in to comment.


Answer by Daniel Ares on 19 Jun 2017

Hi to everybody,
i can´t run it, i get this error, with this code.
open('Force vs Time.fig');
h = gcf; %current figure handle
axesObjs = get(h, 'Children'); %axes handles
dataObjs = get(axesObjs, 'Children'); %handles to low-level graphics objects in axes
lineObjs = get(dataObjs, 'type', 'line'); %type of low-level graphics object
xdata = get(lineObjs, 'XData'); %data from low-level grahics objects
ydata = get(dataObjs, 'YData');
zdata = get(dataObjs, 'ZData');
Thanks

  1 Comment

Jan
on 19 Jun 2017
You forgot to mention the error you get. But please remove this message and post it as a new question, because this is the section for answers. Thanks.
You will get an answer like:
lineObjs = get(dataObjs, 'type', 'line')
get() does not accept 3 inputs. Do you mean:
lineObjs = findobj(dataObjs, 'type', 'line')
? Note: Please delete this message even if this solves your problem.

Sign in to comment.


Answer by Stephen Becker on 25 Jun 2018

The answers above are for Matlab plots, which is very helpful and should be your first choice. But I wanted to comment that there is some really cool (and free, web-based) software that will take any image of a plot, and estimate the data from it by looking at the pixel locations. See automeris.io/WebPlotDigitizer (and watch the tutorial videos first to see how it works).

  0 Comments

Sign in to comment.