在 Matlab 中绘制结构数组

Plotting structure array in Matlab

我在 MATLAB 中有一个结构数组 (98*1):

现在我正在尝试使用 2 个特定字段(比如 x 和 y)绘制图表。 x 和 y 的值出现在这 98 行的每一行中。尝试使用以下命令绘图会出错。

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)

需要帮助了解我做错了什么,以及如何纠正它。

你可以做你想做的

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

第一行将元胞数组转换为结构数组。 ans{:} returns 元胞数组中所有元素的逗号分隔列表。方括号捕捉到这一点,将所有元素连接到一个向量中。

S.x 再次 returns 一个逗号分隔的列表。在这里,我们将所有 x 值连接成一个数字向量。


不请自来的建议

但是拜托,拜托,请改变你存储数据的方式。下面我将说明为什么你应该这么做。

让我们从类似于您的结构(每个元素都是一个结构的元胞数组)中的一些随机数据开始:

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

更好的解决方案是结构数组:

S = [C{:}];

结构数组是 MATLAB 中的标准事物:它是一个数组,其中每个元素都是相同的结构。您对这两个的索引有所不同:

>> 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

为什么 SC 更好?

结构数组在内存方面效率更高

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

请注意 C 几乎是 S 的两倍。为什么是这样? C 包含 100 个结构,每个结构存储一些值,还有这些值的名称。因此,C 存储了 100 次相同的名称(在本例中,'x''y''z''name''status')。 S 只存储一次。

结构数组更容易索引。

你需要 post 这个问题证明了这一点。我回答的第一步是将元胞数组转换为结构数组。 Luis Mendo 的回答表明使用结构元胞数组是多么尴尬。

结构数组更安全

您可以 C{5} = 'sorry',并防止以任何方式使用结构的所有 x 元素,因为其中一个单元格不再是结构。 S(5)='sorry' 报错。也就是说,无法强制结构元胞数组中的所有结构都具有相同的元素。这使事情变得非常复杂。

但还有更好的方法

从 MATLAB R2013b 开始有 table class。 table 类型的对象甚至比结构数组更好。

T = struct2table(S);

A table 将每一列存储为一个数组,因此开销要少得多。也就是说,T.x 是一个数组,而不是 S.x 100 个数组。这使得它更加高效:

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

注意 T 如何使用 C 的 1/6 内存。这也使其类型安全:保证每一行的 x 值具有相同的类型和大小。如果 x 被定义为双精度标量,则不能将字符串分配给一个 x 值,也不能将任何非标量的值分配给它。

再次索引略有不同,但 T.x 直接为您提供所有 x 值的数组,并且

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

所以不用索引 C{5}.xS(5).x,而是 T.x(5).

您可能需要 cellfun with an anonymous function(或 for 循环)从每个单元格的内容中提取 xy 字段:

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

注:

    使用
  • () 索引而不是 {},因为 cellfun 需要元胞数组作为输入(有关索引元胞数组的更多信息 here ).另外,如果你想处理整个单元格数组,你可以完全跳过索引,只使用

    plot(cellfun(@(t) t.x, ans), cellfun(@(t) t.y, ans))
    
  • 两个匿名函数@(t) t.x@(t) t.y作用于每个单元格的内容,即标量结构,并从中提取xy 字段分别。默认情况下,结果按 cellfun.

  • 打包到标准(数字)数组中

如果您的数据以更方便的方式组织,例如具有字段 xy 的 98×1 结构数组,或者更好的是两个数字向量

=14=] 和 y.