在MatLab中绘制结构数组

v440hwme  于 2022-11-15  发布在  Matlab
关注(0)|答案(3)|浏览(213)

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

现在我正试着用两个特定的字段(比如x和y)来绘制一张图。X和y的值出现在这98行中的每一行上。尝试使用以下命令绘制时出错。

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

大括号或点索引表达式应该有一个输出,但有98个结果。
Just(行1)绘图错误(ANS{1:98,1}.x,ANS{1:98,1}.y)
我需要帮助知道我做错了什么,以及如何改正它。

nvbavucw

nvbavucw1#

你可以通过以下方式做你想做的

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

为什么S是比C更好的解决方案?

结构数组在内存方面要高效得多

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

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

oyjwcjzk

oyjwcjzk2#

您可能需要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

mklgxw1f

mklgxw1f3#

我曾经遇到过嵌套结构数组的这个问题(例如,我想绘制一种ans.x.y.z)
我在我的matlab文件交换中发布了一些简单的定制函数:[1]:https://www.mathworks.com/matlabcentral/fileexchange/116130-matlab-struct-operations
你可以用下面的句子来回答这个问题

plotStructArray(ans,'x')

相关问题