Wednesday, April 25, 2012

MATLAB tricks

The figure club met today to discuss tricks we use in MATLAB. Here's what we talked about.

(I hope that this discussion can remain ongoing into the future, so if you have MATLAB frustrations, ask your question as a comment here and hopefully someone will have a solution.)

Saving with export_fig
export_fig is a great way to save plots. Way better than "save" or "print" because it is a lot smarter. Personally, I like that it crops my figure. More info on the matlab central file exchange website.

Dropbox
Using dropbox to make matlab code the same on both a home and work computer. (Dan can you elaborate more on this?)

Edit Plot tip
Don't use Edit Plot tool in matlab. It does some funky things so you're way better off to write the code that will plot the figure in its final version.

File types
For vector graphics, save your figures as pdf or eps. For raster graphics, use png or tiff. Do not use jpeg because it compresses the file in a way that's only appropriate for photos and that will make the text in your figure very pixelated. I personally use pdf whenever possible because it preserves the text as text so it can be changed in a program like Illustrator. pdfs are also very robust, in other words, they will appear the same on any computer.

Labeling a colorbar:
h=colorbar;
ylabel(h,'waterdepth, m')

Multiple colormaps:
freezeColors and cbfreeze are very useful tools from the file exchange.  freezeColors will allow you to have multiple colormaps on one plot and cbfreeze allows multiple colorbars. Use the following syntax:
figure
subplot(121)
imagesc(bathy.lon,bathy.lat,bathy.z)
axis xy
set(gca,'dataaspectratio',[1 cos(48*pi/180) 1]) 
colorbar
freezeColors
cbfreeze
subplot(122)
imagesc(bathy.lon,bathy.lat,bathy.z) 
axis xy
set(gca,'dataaspectratio',[1 cos(48*pi/180) 1])
colorbar
colormap('gray')
set(gcf,'color','w')
export_fig test.pdf

The end result is a figure that has two different colormaps!

Instead of pcolor: imsc
Dan really likes imsc to plot rather than pcolor or imagesc. Dan can you give more feedback as to why this function is great? Pcolor has the disadvantage that when you try to save it as a vector graphic it comes back with really weird white lines. Not only that, it cuts off a row and column of data. As of now, if you want to use pcolor, you have to save it as a tiff or png to make it appear without the bad rendering.

Default figure settings
You can change the default figure settings by changing the startup file. If you haven't created one already, make a file called startup.m and put it in your matlab folder. This will be executed every time matlab opens. I have defined three things in my startup file: (1) I want the figure command to put a figure window in the upper right hand corner of my screen rather than right in the center, (2) I want the default figure background color to be white, and (3) I want the default font size to be 14 pts.

Here's my startup.m file:
% set the default figure position to be in the upper right
set(0,'defaultFigurePosition',[1353 661 560 420])
% set the default figure color to be white
set(0,'defaultFigureColor',[1 1 1])
% set the default font size to be 14
set(0,'defaultaxesfontsize',14);
set(0,'defaulttextfontsize',14);

Other things you may want to set here are the figure orientation (set(0,'orient','landscape')), or the default line or text color.

You can see what your default settings are:
get(0,'default')

Structures
If you don't already use them, structures can be a great way to organize your data. Instead of different variable names for everything, save things as structures. For instance, if I always have structures called ctd and adcp and then within those structures I'll save the variables such as ctd.z, ctd.temp, ctd.salt, adcp.u, adcp.v, adcp.w, etc.

I always like to include a readme file in each structure (if it is data from an instrument). For instance, ctd.readme would tell me what all of the variables are and what their units are. I like to create readme files using the strvcat command:
ctd.readme = strvcat(...
    'CTD data from October 2010 cruise at TTP',...
    'salt = salinity [psu]',...
    'temp = temperature [deg C]');

One of the biggest advantages to a structure is that you can easily save all of the data by just saying:
 save data.mat ctd

However, if you don't want to save the variables that are in a structure as a structure, you can append the command:
save data.mat -struct ctd z temp salt

Sometimes you may need to run through a loop that will plot a lot of data that is all saved in a structure. Let's say you have data from many different moorings called moor1, moor2, moor3, etc. and within each structure there are variables (moor1.temp, moor1.salt, moor1.time, etc). You can plot these using the eval function within a loop:

for i = 1:10
    figure
    eval(['plot(moor' num2str(i) '.time,moor' num2str(i) '.salt)'])
end

Dan pointed out that you could also have a giant structure, where each mooring is an element within the structure moor. Then you could plot just by:

for i = 1:10
    figure
    plot(moor(1).time,moor(1).salt)
end

nicecolor
Neil Banas gave me nicecolor.m ages ago and I use it all the time. Nicecolor allows you to specify colors by using the matlab abbreviations for colors (r=red, b=blue, etc) instead of specify the rgb vector. It takes an average of all of the colors you specify. So for instance, dark yellow could be 'yk' and orange could be 'ryy'. Use as many letters as you want until you get the color that you want. syntax:
plot(x,y,'color',nicecolor('yk'))

ginput
This is a built-in matlab command that is very useful for grabbing x and y data from a plot by eye. It can be used as simply as:
ginput
or you can be more specific to get multiple variables:
[x,y] = ginput

gtext
If you don't know where you will want to place text in a figure, you can use gtext

input
If you want your code to ask you before doing something, the input command can be very useful. For instance you can say:
year = input('What year would you like to plot? ')

sometimes I use it so that I don't mistakenly overwrite data:
disp('Did you really want to overwrite that .mat file?')
yn = input('Say ''yes'' or ''no'' ');
if strcmp(yn,'yes') == 1
    save data.mat
else
    break
end

better subplots
Matlab often leaves excessive space between subplots. There are two ways to deal with this. The first is easier and the second gives you more control.

packrows, packcols, and packboth allow you to tighten up your subplots after you have already plotted them. I use this when I'm just quickly plotting data. This comes from Jonathan Lilly's plotting toolbox (JLAB), which contains many other useful commands besides this one. syntax:
packrows(2,1)

tight_subplot comes from the matlab file exchange and allows you to specify exactly what you want.
ax = tight_subplot(3,2,0.01)
axes(ax(1))
plot(...
axes(ax(2))
plot(...

Good books
The book Modeling Methods for Marine Science by David M. Glover, William J. Jenkins and Scott C. Doney details many statistical methods. The added benefit of this book is that they tie these methods directly to the matlab code that one would use to implement the statistical analysis. This book takes a simpler approach than Emery and Thomson's Data Analysis Methods in Physical Oceanography (which I also recommend.)


Questions that still remain:
  1. Better alternative to plotyy and/or easier way to deal with datetick and plotyy. (Is there an easier way to do this than to specify two axes handles and using the datetick command twice?)
  2. Getting a time axes to align when some subplots need a colorbar and others don't. (I always just plot colorbars that I don't need and delete them or I specify the axes limits manually.)
  3. Saving a discrete colorbar (one with only a few color levels.) It's easy to plot this in matlab, but the save always screws up the colorbar and makes it continuous, even with export_fig.

4 comments:

  1. I downloaded FloatAxis from http://woodshole.er.usgs.gov/operations/sea-mat/ (under hydrographic tools)

    I haven't used it a ton, so can't vouch for how easy it is to manipulate, but it seems like a good place to start for multiple x or y axes.

    ReplyDelete
  2. Sometimes I plot several variables vs time (ie a 4X1 plot), and want to zoom in to a shorter time period. The function linkaxes(gca,'x') links all the subplots together in x, so that zooming in on one also zooms the other panels to the same range.

    ReplyDelete
    Replies
    1. Cool! I never knew about that function. It will definitely be useful!

      Delete
  3. I recommend grabit.m as well. Grabit is a nifty little tool that lets you load in someone else's figure (of a line plot) as an image (png, jpg, whatever), and then snag the data from the figure by laboriously clicking along the line. It's great if you want to do some quick checking against another time series.

    ReplyDelete