Does anyone know of any methods of extracting the data from a MATLAB fig file using Python? I know these are binary files but the methods in the Python Cookbook for .mat files http://www.scipy.org/Cookbook/Reading_mat_files don't seem to work for .fig files...
Thanks in advance for any help, Dan
You can open a FIG file using the openfig(filename) function and save a figure as a FIG file with the saveas(fig,filename) function. In the MATLAB application interface, you can save a FIG file by selecting File → Save or you can export it to an image, such as . JPG or . PNG, by selecting File → Export.
I recently noticed that octave will load a fig file as a structure, so if you're stuck with trying to open fig files without being able to access Matlab you could try and write an octave function that will load the fig file and reconstitute the plot from the contents of the struct .
.fig files are .mat files (containing a struct), see http://undocumentedmatlab.com/blog/fig-files-format/
As the reference you give states, structs are only supported up to v7.1: http://www.scipy.org/Cookbook/Reading_mat_files
So, in MATLAB I save using -v7:
plot([1 2],[3 4])
hgsave(gcf,'c','-v7');
Then in Python 2.6.4 I use:
>>> from scipy.io import loadmat
>>> x = loadmat('c.fig')
>>> x
{'hgS_070000': array([[<scipy.io.matlab.mio5.mat_struct object at 0x1500e70>]], dtype=object), '__version__': '1.0', '__header__': 'MATLAB 5.0 MAT-file, Platform: MACI64, Created on: Fri Nov 18 12:02:31 2011', '__globals__': []}
>>> x['hgS_070000'][0,0].__dict__
{'handle': array([[1]], dtype=uint8), 'children': array([[<scipy.io.matlab.mio5.mat_struct object at 0x1516030>]], dtype=object), '_fieldnames': ['type', 'handle', 'properties', 'children', 'special'], 'type': array([u'figure'], dtype='<U6'), 'properties': array([[<scipy.io.matlab.mio5.mat_struct object at 0x1500fb0>]], dtype=object), 'special': array([], shape=(1, 0), dtype=float64)}
Where I used .__dict__
to see how to traverse the structure. E.g. to get XData
and YData
I can use:
>>> x['hgS_070000'][0,0].children[0,0].children[0,0].properties[0,0].XData
array([[1, 2]], dtype=uint8)
>>> x['hgS_070000'][0,0].children[0,0].children[0,0].properties[0,0].YData
array([[3, 4]], dtype=uint8)
Showing that I'd used plot([1 2],[3 4])
in MATLAB (the child is the axis and the grandchild is the lineseries).
Here is my update from Sascha's post. Now it can:
The code is below:
from scipy.io import loadmat
import numpy as np
import matplotlib.pyplot as plt
def plotFig(filename,fignr=1):
d = loadmat(filename,squeeze_me=True, struct_as_record=False)
matfig = d['hgS_070000']
childs = matfig.children
ax1 = [c for c in childs if c.type == 'axes']
if(len(ax1) > 0):
ax1 = ax1[0]
legs = [c for c in childs if c.type == 'scribe.legend']
if(len(legs) > 0):
legs = legs[0]
else:
legs=0
pos = matfig.properties.Position
size = np.array([pos[2]-pos[0],pos[3]-pos[1]])/96
plt.figure(fignr,figsize=size)
plt.clf()
plt.hold(True)
counter = 0
for line in ax1.children:
if line.type == 'graph2d.lineseries':
if hasattr(line.properties,'Marker'):
mark = "%s" % line.properties.Marker
if(mark != "none"):
mark = mark[0]
else:
mark = '.'
if hasattr(line.properties,'LineStyle'):
linestyle = "%s" % line.properties.LineStyle
else:
linestyle = '-'
if hasattr(line.properties,'Color'):
r,g,b = line.properties.Color
else:
r = 0
g = 0
b = 1
if hasattr(line.properties,'MarkerSize'):
marker_size = line.properties.MarkerSize
else:
marker_size = -1
x = line.properties.XData
y = line.properties.YData
if(mark == "none"):
plt.plot(x,y,linestyle=linestyle,color=[r,g,b])
elif(marker_size==-1):
plt.plot(x,y,marker=mark,linestyle=linestyle,color=[r,g,b])
else:
plt.plot(x,y,marker=mark,linestyle=linestyle,color=[r,g,b],ms=marker_size)
elif line.type == 'text':
if counter == 0:
plt.xlabel("$%s$" % line.properties.String,fontsize =16)
elif counter == 1:
plt.ylabel("$%s$" % line.properties.String,fontsize = 16)
elif counter == 3:
plt.title("$%s$" % line.properties.String,fontsize = 16)
counter += 1
plt.grid(ax1.properties.XGrid)
if(hasattr(ax1.properties,'XTick')):
if(hasattr(ax1.properties,'XTickLabelRotation')):
plt.xticks(ax1.properties.XTick,ax1.properties.XTickLabel,rotation=ax1.properties.XTickLabelRotation)
else:
plt.xticks(ax1.properties.XTick,ax1.properties.XTickLabel)
if(hasattr(ax1.properties,'YTick')):
if(hasattr(ax1.properties,'YTickLabelRotation')):
plt.yticks(ax1.properties.YTick,ax1.properties.YTickLabel,rotation=ax1.properties.YTickLabelRotation)
else:
plt.yticks(ax1.properties.YTick,ax1.properties.YTickLabel)
plt.xlim(ax1.properties.XLim)
plt.ylim(ax1.properties.YLim)
if legs:
leg_entries = tuple(['$' + l + '$' for l in legs.properties.String])
py_locs = ['upper center','lower center','right','left','upper right','upper left','lower right','lower left','best','best']
MAT_locs=['North','South','East','West','NorthEast', 'NorthWest', 'SouthEast', 'SouthWest','Best','none']
Mat2py = dict(zip(MAT_locs,py_locs))
location = legs.properties.Location
plt.legend(leg_entries,loc=Mat2py[location])
plt.hold(False)
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With