0

I have a structure array (98*1) in MATLAB:

enter image description here

Now I am trying to plot a graph by using 2 particular fields (say x and y). The values of x and y are present on each of these 98 rows. Trying the following command to plot gives error.

plot(ans{1:98,1}.x,ans{1:98,1}.y)

Expected one output from a curly brace or dot indexing expression, but there were 98 results.

Error in just (line 1) plot(ans{1:98,1}.x,ans{1:98,1}.y)

Need help in knowing what I am doing wrong, and how to correct it.

1
  • Nusrat, please read the "unsolicited advice" that I just added to my answer. I really think you need to rethink how you save your data. Commented Jan 7, 2018 at 6:57

3 Answers 3

6

You can do what you want by

S = [ans{:}];
x = [S.x];
y = [S.y];
plot(x,y)

The first line converts the cell array into a struct array. ans{:} returns a comma-separated list of all elements in the cell array. The square brackets capture that, catenating all elements into a vector.

S.x again returns a comma-separated list. Here we catenate all x values into a numeric vector.


Unsolicited advice

But please, please, please change how you store your data. Below I'll make a case for why you should.

Let's start with some random data in a structure similar to yours (a cell array where each element is a struct):

C = cell(1,100);
for ii=1:length(C)
   C{ii} = struct('x',randn(1),'y',randn(1),'z',randn(1),...
      'name',char('a'+floor(rand(1,10)*('z'-'a'+1))),...
      'status',rand(1)>0.3);
end

A better solution is a struct array:

S = [C{:}];

A struct array is a standard thing in MATLAB: it's an array where each element is an identical struct. You index these two somewhat differently:

>> C{5}
ans = 
  struct with fields:
         x: -0.0818
         y: 0.5463
         z: -0.8194
      name: 'ysrkqlzcms'
    status: 1

>> S(5)
ans = 
  struct with fields:
         x: -0.0818
         y: 0.5463
         z: -0.8194
      name: 'ysrkqlzcms'
    status: 1

Why is S a better solution than C?

A struct array is much more efficient memory wise

>> whos
  Name        Size              Bytes  Class     Attributes
  C           1x100            103700  cell                
  S           1x100             60820  struct              

Note how C occupies almost double what S does. Why is this? C contains 100 structs, each struct stores some values, but also the names of those values. Thus, C stores 100 times the same names (in this case, 'x', 'y', 'z', 'name' and 'status'). S only stores those once.

A struct array is much easier to index.

That you needed to post this question proves this point. The first step in my answer was to convert the cell array to a struct array. Luis Mendo's answer shows how awkward it is to work with a cell array of structs.

A struct array is safer

You can do C{5} = 'sorry', and prevent any sort of approach to use all x elements of the structs, because one of the cells no longer is a struct. S(5)='sorry' gives an error. This is to say, there is no way to enforce that all structs in your cell array of structs have the same elements. This complicates things significantly.

But there's an even better approach

Since MATLAB R2013b there is a table class. Objects of type table are even better than struct arrays.

T = struct2table(S);

A table stores each column as a single array, and therefore has a lot less overhead. That is, T.x is a single array, rather than S.x which is 100 arrays. This makes it much, much more efficient:

>> whos
  Name        Size              Bytes  Class     Attributes
  C           1x100            103700  cell                
  S           1x100             60820  struct              
  T         100x5               17476  table               

Note how T uses 1/6 of the memory of C. This makes it also type safe: the x value for each row is guaranteed to be the same type and size. You cannot assign a string to one x value, nor anything that is not a scalar, if x is defined as a scalar double.

Indexing again is slightly different, but T.x directly gives you the array for all x values, and

>> T(5,:)
ans =
  1×5 table
    x           y          z            name        status
_________    _______    ________    ____________    ______
-0.081774    0.54633    -0.81939    'ysrkqlzcms'    true  

So instead of indexing C{5}.x or S(5).x, you do T.x(5).

Sign up to request clarification or add additional context in comments.

2 Comments

Good idea! I knew there had to be a simpler way
+1 Nice and concise. It should also be mentioned that prior to 2013b there was a dataset (now retired) that was similar to a table, and also a better option than structures and cell array.
0

You probably need cellfun with an anonymous function (or a for loop) to extract the x and y fields from each cell's contents:

plot(cellfun(@(t) t.x, ans(1:98,1)), cellfun(@(t) t.y, ans(1:98,1)))

Note:

  • () indexing is used instead of {}, because cellfun expects a cell array as input (more information about indexing cell arrays here). Also, if you want to process the whole cell array you can skip indexing altogether and just use

    plot(cellfun(@(t) t.x, ans), cellfun(@(t) t.y, ans))
    
  • The two anonymous functions @(t) t.x and @(t) t.y act on each cell's contents, namely a scalar struct, and extract from it the x or y field respectively. The results are packed by default into a standard (numerical) array by cellfun.

It would be much easier if your data were organized in a more convenient manner, such as a 98×1 struct array with fields x and y, or better yet two numeric vectors x and y.

Comments

0

I also once had this problem for nested structure arrays (e.g., i wanted to plot kind of ans.x.y.z)

I posted some simple custom functions at my matlab file exchange: [1]: https://www.mathworks.com/matlabcentral/fileexchange/116130-matlab-struct-operations

You can use following for the question

plotStructArray(ans,'x')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.