Matlab tips

Get figures actually to save/export as they look!

set(gcf,'PaperPositionMode','auto');

This makes an export, e.g. to EPS or PNG, of the current figure (gcf) have a bit more change of looking like the figure on the screen. This is important if one has changed a figure's size or moved parts about in it: they get hopelessly messed up with the default options.

Better, get the user-contributed add-on export_fig, from the matlab website.

Get file modification time in a useable numeric form

Aim: get a file's modification time (date/time of last change of its contents) in seconds, in a format that easily can be used for calculations such as `how long ago was this modified' and that doesn't rely on platform-specific things like

[status,age_str] = unix('echo $(( $(date +%s) - $(stat -c %Y filename.m)))')
or on silly Java-based things. Matlab's dir command is the key here. The following does the same as the above, using only core matlab functions, and returning the result of the age of the file as a number rather than a string all in one line.
 age = etime( clock, datevec( getfield( dir('filename.m'), 'date') ) )
Note that this relies on datevec being able to parse automatically the string format returned by dir, which on my system is in the format referred to as '0' in the documentation for datestr, e.g. "24-May-2010 11:15:50". Other platforms, ages and locales may give something else. The datevec function can instead be given a second argument to specify the format precisely, using the 'HH:MM:SS' etc. method also described in help datestr.

(Perhaps) get consistent fonts for differently sized figures

The aim: whether the figure be large or small, have fonts on all the labels and ticks being the same actual size on the page, when included in a Latex document. There appear to be options about the specified rather than scaled size of font if using the `print preview' option. Seeking something command-based, I've gone on separately.

One way: set a font-size in all the text of the figure (by the defaults for new objects, or by going through all the existing objects -- see methods below); set the figure's 'Units' to whatever you want to use (e.g. centimeter [sorry about the spelling -- matlab insists), then the 'Position' property to make the figure width be however many such units you actually want in the document. Then export, and don't using scaling in the document.

The trouble with this is that for e.g. a sensible 12cm width, the font size (on my system, anyway) has to be about 5pt to come out sensibly, but things like a legend take lots of space; one could say the `natural-size' figure just looks too chunky. So the same basic principle has been followed, of not varying the scaling, but a uniform 50% down-scaling has been used within the document, starting the figure windows at ~24cm width. To make a smaller figure, just resize the window around the axes.

Set legend interpreter by a command

set( legend(filelist), 'Interpreter', 'none');

This allows a legend to be specified as well as setting the interpreter for the legend text: using 'none' prevents for example underscores and carets being interpreted as the (default) TeX subscripts and superscripts.

Set default properties for subsequent figures/axes/lines

Rather than changing things after plotting, different defaults can be set: a zero acts on the `root', i.e. all subsequent figures. Here are some examples of defaults: see results of get(gca) or similar commands to guess others, or search the web.
set(0, 'DefaultAxesFontSize', 14)
set(0, 'DefaultAxesLineStyleOrder', {'-','--',':'})
set(0, 'DefaultAxesColorOrder', [0 0 1; 1 0 0; 0 0.5 0])

Set a default for all axes on a figure

As above, but just for a particular figure,
    set(gcf, 'DefaultAxesFontSize', 10)

Some `discovered' defaults for the root

The following were found in a comment on a matlab webpage. Cleaned up from the mutilated quotation marks and ellipses that somehow got in to the webpage, and modified slightly to taste, they are:
set(0, ...
 'DefaultFigureUnits', 'centimeters', ...
 'DefaultFigurePosition', [0.5,2.0,12,12], ...
 'DefaultFigureColor', 'white', ...
 'DefaultFigurePaperType', 'a4', ...
 'DefaultFigurePaperUnits', 'centimeters', ...
 'DefaultFigurePaperPositionMode','auto', ...
 'DefaultAxesColor', 'white', ...
 'DefaultAxesDrawmode', 'fast', ...
 'DefaultAxesFontUnits', 'points', ...
 'DefaultAxesFontSize', 8, ...
 'DefaultAxesFontAngle', 'normal', ...
 'DefaultAxesFontName', 'Helvetica', ...
 'DefaultAxesGridLineStyle', ':', ...
 'DefaultAxesInterruptible', 'on', ...
 'DefaultAxesLayer', 'bottom', ...
 'DefaultAxesNextPlot', 'replace', ...
 'DefaultAxesUnits', 'centimeters', ... % or 'normalized'
 'DefaultAxesXcolor', [0, 0, 0], ...
 'DefaultAxesYcolor', [0, 0, 0], ...
 'DefaultAxesZcolor', [0, 0, 0], ...
 'DefaultAxesVisible', 'on', ...
 'DefaultLineColor', 'blue', ...
 'DefaultLineLineStyle', '-', ...
 'DefaultLineLineWidth', 1, ...
 'DefaultLineMarker', 'none', ...
 'DefaultLineMarkerSize', 6, ...
 'DefaultTextColor', [0, 0, 0], ...
 'DefaultTextFontUnits', 'Points', ...
 'DefaultTextFontSize', 8, ...
 'DefaultTextFontName', 'Helvetica', ...
 'DefaultTextVerticalAlignment', 'middle', ...
 'DefaultTextHorizontalAlignment', 'left'   );

One way to see the possible values is to open the GUI-based figure editor and choose to set further properties, then look at all the permitted options in the drop-down lists.

Set line-styles of each line on each axis, automatically

When plotting multiple lines of data (a matrix rather than a vector as input) Matlab automatically colours them by cycling through a list. This isn't much help if one would like markers, for example for greyscale printing or for more clarity. The following code finds each axis in the current figure, then finds each line in that axis, and applies markers and colours from lists, besides other features such as the thickness and size. The whole thing can be had as a script to run on each figure after making it: set_linestyles.m.

% lists of colours and markers to cycle through
C = [ ... % R G B
    0.00 0.00 1.00
    0.00 0.50 0.00
    1.00 0.00 0.00 ];
M = 's+dph';
% get properties of current figure: work on each 'child'
f = get(gcf());
for na = 1:numel(f.Children),
    % get details of this child-object: skip if not 'axes' object
    a = get(f.Children(na));
    if ~strcmpi(a.Type,'axes'),
        continue;
    end
    % for each child of the axes,
    n = 0;
    L = sort(a.Children);
    for nl = 1:numel(L),
        % get details of this child: skip if not 'line' object
        l = L(nl);
        if ~strcmp(get(l,'Type'),'line'),
            continue;
        end
        n = n + 1;
        set(l, 'Color', C(mod(n-1,size(C,1))+1,:));
        set(l, 'LineStyle', '-');
        set(l, 'LineWidth', 0.5);
        set(l, 'Marker', M(mod(n-1,length(M))+1));
        set(l, 'MarkerSize', 7);
        set(l, 'MarkerEdgeColor', 'auto');
        set(l, 'MarkerFaceColor', 'none');
    end
end

General modifications to figures, axes etc.

(Alternative: use property explorers, etc., in the GUI. I prefer to avoid this, as working by scripts makes things quicker and more reliably repeatable when one will do them lots of times.)

The get() and set() commands are very handy here. Having got the list of properties of the current figure or axes, one can change particular ones according to (generally easily guessable) rules.

% get properties of the current figure (click figure to make 'current')
get(gcf)
% or get for current axes (click particular plot to make it 
% current, or select one of the 'Children' of the result of
% get(gcf), or else the last-created axes will be current
get(gca)
% set something: e.g. limits of an axis, and ticks
set(gca, 'xlim',[0,50], 'xgrid','on', 'xminorgrid','on');
% likewise for grand-children etc (lines) and for the very
% many other properties

Check a variable for lots of attributes at once

When trying to make functions be robust and have helpful error-messages, conditionals grow to such ones as: if ~isempty(a) && isnumeric(a) && isscalar(a) && ....

It turns out that since version 2007b there have been some useful functions that can do a lot of this at once. This is particularly desirable if the variable to be checked has a long name/indexing so that repetition is undesirable:

	validateattributes()
	validatestring()

Join images together

The following code lets a rectangular array of PNG images, with names consisting of numbers starting at 'oname', be joined into a single image. See `by inspection' the needed variations for using other image formats, other numbers of images, etc. Really, the only trouble was the matter of colour indexing.

ncols = 49; % number of columns (number /in/ a row)
nrows = 52; % " " rows (" column)
first = 1;  % number of the first file (top left)
oname = 'L';
ofmt = 'png';
ncol = 64;    % number of colours in indexed image (0 means not indexed)
a=[];
for i=0:(nrows-1),
    arow=[];
    for j=0:(ncols-1),
        imname = sprintf('%04d.gif', first+ncols*i+j);
        [tmp.ind,tmp.map] = imread(imname);
        % convert list of pixels and colour-map to standard RGB
        atmp = ind2rgb(tmp.ind,tmp.map);
        arow = [arow,atmp];
    end;
    a = [a; arow];
end
if ncol,
    % convert RGB back to indexed (map) for better
    % efficiency for diagram or cartoon type images
    [aind,map] = rgb2ind(a,ncol);
    imwrite(aind, map, [oname,'.',ofmt], ofmt);
else
    % write image directly
    imwrite(a, [oname,'.',ofmt], ofmt);
end

Number nightmares: data-types

A lot of things can be done with a high-level numerically-based language without caring about anything being other than a double-precision floating point number. One might start to care when dealing with arkwardly large amounts of data of range so limited that an 8-byte representation is significantly wasteful, or when dealing with network communication, instrument control, or file input and output involving interaction with other programs. One might then start going mad realising that the scope for manipulation of bytes is highly confusing for someone versed in C (and hardly surprisingly, in some ways, since much of the point of numerical environments is to let lots of users use computers for calculations without caring about representation of numbers or management of memory).

Matlab does have functions to convert a value (scalar, vector, matrix, ...) to other types. For example, double('help') converts the string (character array) help, of length 4, to a numeric array of double-precision numbers having the values that the bytes representing these four characters in ASCII would have when interpreted as integers: [ 104 101 108 112 ]. The function char converts numbers to the characters that they represent; other functions such as int8, uint8, int16, ... etc. convert to other data-types with possible economies of memory, but more limited range. See help datatypes for more on this.

What probably shocks a C-user most is that operations on mixed datatypes give results limited to the smaller range, even when the output is not being forced into a variable of limited type. In C, arithmetic would typically be done in the range of the highest rather than the lowest-range input.

Thus, in matlab,

>> a = uint8(128)
>> f = 250;
>> whos
  Name        Size            Bytes  Class     Attributes
  a           1x1                 1  uint8
  f           1x1                 8  double
>> a*f
ans = 255
while in C,
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
main()
{
        uint8_t a = 128;
        double  f = 250.0;
        printf("%d * %f = %f\n", a, f, a*f);
}
[compile and run]:   128 * 250.000000 = 32000.000000
It's certainly something to look out for when everything seems bizarre. I've opted long ago to force everything to double in matlab or octave, until I'm forced to try to save space. It keeps things simpler.

Still, for some things such as writing a mixed burst of data types as a single stream of bytes to an instrument, I've ended up doing messy things like

for ni=1:length(in),
	si = in(ni);
	if si<0,  % negative values: 
		si = double( uint16(1) + bitxor(uint16(abs(si)),uint16(2^16)) );
	end
	bindata(2*ni-1) = (si - mod(si,256))/256;
	bindata(2*ni)   = mod(si,256);
end
just to convert some input integers (within a 16bit signed-integer range) to an array giving the uint8-values of the byte-stream that would represent these int16 numbers (in big-endian format), in order to send this and a text header all in one command. ``There must be a better way, even in [numerical-oriented] Matlab'', I'd say to myself.

There is (to some extent): typecast allows the underlying data (bytes) to be maintained while accessing them as a different type --- just what we often want to do to convert for example int16 to uint8 (above); there is also cast to change the type by converting the data, which is like using one of the specific functions such as double. Very handy. At last, easy type-manipulation. For example,

d = int16([0, -2500, -1, 1, 2700]);
o = typecast(d, 'uint8')
o =
    0    0   60  246  255  255    1    0  140   10
% check the second one (amd64 is little-endian):
(256*246+60) - 2^16
ans =
       -2500

Set a title to a figure window (for the window-manager to use)

This allows the window containing a figure to display something other than just `Figure 1', `Figure 2' etc.

set(gcf,  'Name', '|s(t)| - s_0', 'NumberTitle', 'off')
This could be handy just for selecting the right figure from a window-manager toolbar, when one is regularly plotting many attributes of data at once. Sophisticated window-managers, such as that within the KDE desktop, can also be instructed to set a window's position, focus and more, based on its name.

Get the contents of a http URL without messing it up

The matlab function urlread() allows a http or https URL to be read into the output character array. This is a trouble for anything that isn't text, as the output gets converted from bytes into unicode characters.

There are so many reasons why one might want to get a non-text url that it's surprising they should make it so hard. Some instruments can provide their data in binary format; one might want quickly to get an image for processing, or a zip-file, etc.

This function: urlget.m gets a URL as a numeric array in which each element is the numeric unsigned (0:255) value of a byte from the URL. It is limited to http, GET, and no proxy.

To make your own function with less limitation, try removing the native2unicode(...) function from a line near the end of matlab's urlread(). A little trickery will be needed beyond just copying and modifying this function, as its residency in $MATLAB/iofun/ gives it access to $MATLAB/iofun/private/urlreadwrite.m which it requires too. And you probably don't want to change the original, since its character-based output may be relied on by other things.


Page started: 2008-12-08
Last change: 2014-09-05