在 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
为什么 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
只存储一次。
结构数组更容易索引。
你需要 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}.x
或 S(5).x
,而是 T.x(5)
.
您可能需要 cellfun
with an anonymous function(或 for
循环)从每个单元格的内容中提取 x
和 y
字段:
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
作用于每个单元格的内容,即标量结构,并从中提取x
或y
字段分别。默认情况下,结果按 cellfun
.
打包到标准(数字)数组中
如果您的数据以更方便的方式组织,例如具有字段 x
和 y
的 98×1 结构数组,或者更好的是两个数字向量
=14=] 和 y
.
我在 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
为什么 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
只存储一次。
结构数组更容易索引。
你需要 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}.x
或 S(5).x
,而是 T.x(5)
.
您可能需要 cellfun
with an anonymous function(或 for
循环)从每个单元格的内容中提取 x
和 y
字段:
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
作用于每个单元格的内容,即标量结构,并从中提取x
或y
字段分别。默认情况下,结果按cellfun
. 打包到标准(数字)数组中
如果您的数据以更方便的方式组织,例如具有字段 x
和 y
的 98×1 结构数组,或者更好的是两个数字向量
=14=] 和 y
.