Best way to input an unknown number of structures and options.

22 views (last 30 days)
We're writing some data visualization code to compare different experiments. Each experiment is stored in a structure -- let's say they're called E1, E2, E3... This let's us get at all the metadata for each structure, keep track of power, frequency, all that jazz. This has been working really really well for us and we have a lot of data stored this way.
I've been using varargin to load any number of these structures into our custom plotting functions. However, as we go forward, we need to have a few more optional parameters for some datasets. An example: experiments E1, E2, and E3 were measured at temperatures between [0 300] but experiments E4, E5, E6 were measured between [100 200]. I only want to plot the data from all experiments in the range [100 200] and I want to pass this as an optional parameter. This really seems to call for use of the inputParser class to parse the inputs and define defaults. I'll define a parameter 'TempRange',[## ##] and then there'll be a default if the user doesn't specify it. There are a couple of other options that we want to add this way too.
However, I do not know how many structures the end user will specify. In the above example, there were six. There could be 2 or 20. Using the addOptional method requires that I name the classes, but I don't know how many there will be. I could try to use KeepUnmatched to catch the extra parameters, but this is acting weirdly because I am trying to pass structures. If StructExpand is true, I lose my "E2" top-level structure and my fields get smushed together. If E2 and E3 have the same fieldnames (and this could sometimes happen) then the parsing function only keeps the last fields loaded. If StructExpand is false, I get the error "Expected a string for the parameter name, instead the input type was 'struct'."
Not sure why this is happening or the best way to try to load my variables. Any help out there? Short version of my code is below:
function myInputTest(input1,varargin)
p = inputParser;
p.KeepUnmatched = true;
p.StructExpand = false;
addRequired(p,input1,@(x) isstruct(x));
parse(p,input1,varargin{:})
call
myinputTest(struct(),struct())
Although in this example I'm calling with empty structures, I get the same error if there are dummy fields in the structs.

Accepted Answer

jgg
jgg on 18 Jan 2016
Edited: jgg on 18 Jan 2016
The issue is that the optional arguments need string names 'struct2' 'struct3' and it's freaking out because you're not passing one in.
I think a better way to do this would be instead of passing each struct, pass in a cell array of structs:
s = {struct(),struct(),struct()};
n = size(s,2);
Then you can figure out how many you've passed in a access them in a loop or whatever you want to do. Pass in the options like TempRange or whatever as actual options and name them.
So, your function would be like:
function myInputTest(myStructsList,varargin)
p = inputParser;
p.KeepUnmatched = true;
p.StructExpand = false;
addRequired(p,myStructsList,@iscell);
addOptional(p,'TempRange',[-Inf,Inf],@isnumeric);
parse(p,input1,varargin{:})
%%etc
Then call it like
myInputTest(s,'TempRange',[0,100])
  2 Comments
Stephen23
Stephen23 on 19 Jan 2016
An even better solution would be to use one non-scalar structure, instead of all of those separate individual structures in a cell array. Any subset of the structures can be accessed using indexing:
>> x(1).a = 2;
>> x(2).a = 4;
>> x(3).a = 8;
>> [x.a]
ans = 2 4 8
>> [x([1,3]).a]
ans = 2 8

Sign in to comment.

More Answers (0)

Categories

Find more on Argument Definitions in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!