Loren on the Art of MATLAB

Turn ideas into MATLAB

Working with structs

MATLAB has some functions that are specifically designed for exploring the contents of structures (entities known in MATLAB by the class struct). I find the functions isfield and fieldnames particularly helpful. The reason I raise this area of functionality is because some users new to MATLAB occasionally have trouble finding these functions and try to use the function exist to do the work for them and find it doesn't work out.

Contents

Example Application

Suppose I'm writing an M-file to analyze data that I expect to come in a struct with two fields, named time and amplitude. Since I intend to pass this M-file to lots of other folks, I want to write it somewhat carefully so errors the users make give them enough information to correct problems without having to consult me too often.

snippet Help

Let's look at the help for our function first:

help snippet
 SNIPPET plots time vs. amplitude from an input struct.
    SNIPPET(D) plots data from a struct D which must contain the two fields:
            time : a sequence of times
       amplitude : corresponding amplitudes
    If either D.time or D.amplitude are missing, SNIPPET errors out.

Sample Data

Next let's get some data that is suitable for this function (ss and ssExtra), and some that is not (ssBad).

sunspots = load('sunspot.dat');
ss.time = sunspots(:,1);
ss.amplitude = sunspots(:,2);
ssBad.time = ss.time;
ssBad.amp = ss.amplitude;
ssExtra = ss;
ssExtra.other = datestr(today);

Checking Inputs for Suitability with snippet with exist

Let's explore how I might check our different versions of the sunspot data to see which one or ones is suitable for use with snippet so I can figure out what code to put into snippet to do the error checking. Remember, we want to check to see if the input is a struct and, if so, that it has fields time and amplitude. I'll begin by trying exist, and I am placing the code inside a try-catch. so I can capture any errors and easily show them.

try
    exist(ss.time)
catch
    err = lasterror;
    disp(err.message)
end
Error using ==> exist
The first input to exist is a string.

That didn't work because exist expects string input. So here's my next attempt.

try
    exist('ss.time')
catch
    err = lasterror;
    disp(err.message)
end
ans =

     0

and that didn't work either! What went wrong? I gave exist a string input. Looking at the help carefully, I see that the name I give must be a variable name or the name of some file or method. So now let me check my variable name using the function isvarname.

isvarname('ss.time')
ans =

     0

I can also see what variables I do have in my workspace:

whos
  Name           Size                    Bytes  Class

  ans            1x1                         1  logical array
  err            1x1                      2158  struct array
  f              1x25                      200  double array
  fibo           1x25                      200  double array
  n              1x1                         8  double array
  nmax           1x1                         8  double array
  sbad           1x1                      4856  struct array
  spots        288x2                      4608  double array
  ss             1x1                      4856  struct array
  ssBad          1x1                      4856  struct array
  ssExtra        1x1                      5002  struct array
  sunspots     288x2                      4608  double array

Grand total is 3969 elements using 31361 bytes

and I see that I have ss but not ss.time because ss.time is a member of the struct but not a variable itself. I've seen this confusion between structures, their fields, and variables, fairly regularly on the MATLAB newsgroup.

Try struct-specific functions

I now understand that I have to look at the details of the structure variables to see if the fields I need are there. Here's the code I wrote:

type snippet
function snippet(D)
%SNIPPET plots time vs. amplitude from an input struct.
%   SNIPPET(D) plots data from a struct D which must contain the two fields:
%           time : a sequence of times
%      amplitude : corresponding amplitudes
%   If either D.time or D.amplitude are missing, SNIPPET errors out.

if ~isstruct(D) || ...
    ~(isfield(D,'time') && isfield(D,'amplitude'))
    error('snippet:incorrectInput', ...
        'snippet expects a struct with fields time and amplitude');
end
plot(D.time,D.amplitude)

Try snippet on Incorrect Inputs

try
    snippet(sunspots)
catch
    err = lasterror;
    disp(err.message)
end
try
    snippet(ssBad)
catch
    err = lasterror;
    disp(err.message)
end
Error using ==> snippet
snippet expects a struct with fields time and amplitude
Error using ==> snippet
snippet expects a struct with fields time and amplitude

Try snippet with Good Inputs

I leave it as an exercise for you to show that snippet runs correctly using either ss or ssExtra as inputs.

Extra Credit

For extra credit, anyone care to write the code I'd need to add to snippet to disallow inputs with an extra fields to work? I gave a hint earlier in this column.

Any thoughts on this topic? If so, enter them here.

|

Comments

To leave a comment, please click here to sign in to your MathWorks Account or create a new one.