【问题标题】:Plotting structure array in Matlab在 Matlab 中绘制结构数组
【发布时间】:2018-01-07 02:19:31
【问题描述】:

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

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

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

期望大括号或点索引表达式有一个输出,但是 有 98 个结果。

仅(第 1 行)绘图中的错误(ans{1:98,1}.x,ans{1:98,1}.y)

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

【问题讨论】:

  • Nusrat,请阅读我刚刚添加到答案中的“不请自来的建议”。我真的认为您需要重新考虑如何保存数据。

标签: matlab matlab-figure matlab-guide


【解决方案1】:

你可以做你想做的事

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

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

S.x 再次返回一个逗号分隔的列表。在这里,我们将所有 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 只存储一次。

结构数组更容易索引。

您需要发布此问题证明了这一点。我回答的第一步是将元胞数组转换为结构数组。 Luis Mendo 的回答显示了使用结构单元数组是多么尴尬。

结构体数组更安全

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

但还有更好的方法

自 MATLAB R2013b 以来,有一个 table 类。 table 类型的对象甚至比结构数组更好。

T = struct2table(S);

表将每一列存储为单个数组,因此开销要少得多。也就是说,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  

因此,您可以使用T.x(5),而不是索引C{5}.xS(5).x

【讨论】:

  • 好主意!我知道必须有更简单的方法
  • +1 简洁明了。还应该提到的是,在 2013b 之前,有一个类似于表格的 dataset(现已退役),也是比结构和元胞数组更好的选择。
【解决方案2】:

您可能需要cellfunanonymous 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 结构数组,或者更好的是两个数字向量xy .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多