Appending data when extracting nested fields as individual variables

1 visualización (últimos 30 días)
Hi Matlab community,
I have a variable "hands" that contains several fields, and I am trying to make hand_type, one of the fields, as an individual variable. The size of "hands" varies between 1x1 struct and 1x2 struct, hence I used the if-elseif loop. When "hands" is 1x2 struct, I want the second group of data to be stored in a parallel cell next to the first group of data, hence the {end+1}, as I don't want them to be in the same cell and create an additional layer of nesting.
However, in the resulting "hand_type", whenever "hands" is 1x2 struct, "hand_type" only has 0x0 double. In comparison, when "hands" is 1x1 struct, "hand_type" has a value of a number (0, 1, etc).
Could someone help me to identify what I am doing wrong, and how I can fix the problem? The full script is attached.
Thank you in advance!
has_hands = ~cellfun(@isempty, {frames.hands});
filtered_frames = frames(has_hands);
id = {filtered_frames.id};
time = {filtered_frames.timestamp};
hands = {filtered_frames.hands};
hand_type = cell(size(hands));
for i = 1:numel(hands)
if isequal(size(hands{i}),[1,1])
hand_type{i} = hands{i}.type;
elseif isequal(size(hands{i}),[1,2])
hand_type{end+1} = hands{i}(1).type;
hand_type{end+1} = hands{i}(2).type;
end
  4 comentarios
Voss
Voss el 30 de Abr. de 2024
@Julia Thanks for that!
However, it looks like the variable in the .mat file is not similar to what you describe in the question.
S = load('frames.mat')
S = struct with fields:
first100: [1x100 struct]
frames = S.first100
frames = 1x100 struct array with fields:
frames
temp = [frames.frames]
temp = 1x100
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
any(temp)
ans = logical
0
It is a struct array with one field (called "frames") containing all scalar zeros, instead of a struct array with multiple fields ("hands", "id", "timestamp").
Julia
Julia el 1 de Mayo de 2024
@Voss I'm so sorry about that! I made a mistake when extracting part "frames" (the original variable is too large to upload). The correct version of frames.mat is now uploaded, which should represent what I described in the question.

Iniciar sesión para comentar.

Respuesta aceptada

Stephen23
Stephen23 el 1 de Mayo de 2024
Editada: Stephen23 el 1 de Mayo de 2024
The simple and efficient MATLAB approach using two comma-separated lists (no loops are required!):
first100 = load('frames.mat').first100
first100 = 1x100 struct array with fields:
id timestamp hands version
tmp = [first100.hands]; % 1x140 structure array
hand_type = [tmp.type] % 1x140 double array
hand_type = 1x140
0 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
  7 comentarios
Julia
Julia el 1 de Mayo de 2024
Editada: Julia el 1 de Mayo de 2024
Edited: Sorry for bothering you! I think I figured it out by using bones_only = arrayfun(@(x) x.bones, thumb, 'UniformOutput', false);
Hi@Stephen23, can I ask for your help one more time?
I am trying to extract data from "digits" in "hands". For my new variable "thumb_1", I would need all data of "prev_joint" in row 1 for each "bones" structure. However, I am having troubles accessing that.
Here are the steps I have taken so far:
digits = [tmp.digits];
thumb = digits([digits.finger_id] == 0);
Then, when I tried to extract "bones", thumb_data = thumb.bones; only gave me a 1x4 struct instead the whole array of data. I tried vertcat and indexing, which had the same problem.
I'm really sorry if this is another stupid question.
Stephen23
Stephen23 el 1 de Mayo de 2024
"For my new variable "thumb_1", I would need all data of "prev_joint" in row 1 for each "bones" structure. However, I am having troubles accessing that."
In total there are 2700 BONES structures: perhaps you only want to access a subset of them.
"Row 1" is confusing me... I do not see any arrays which have more than one row.
first100 = load('frames.mat').first100
first100 = 1x100 struct array with fields:
id timestamp hands version
tmp = [first100.hands]
tmp = 1x140 struct array with fields:
id type confidence visible_time pinch_distance grab_angle pinch_strength grab_strength palm digits arm
digits = [tmp.digits]
digits = 1x700 struct array with fields:
finger_id is_extended bones
id0 = [digits.finger_id]==0;
nnz(id0)
ans = 140
bones = [digits.bones]
bones = 1x2800 struct array with fields:
prev_joint next_joint width rotation
[bones.prev_joint]
ans = 1x8400
-116.7911 162.2039 -46.7425 -116.7911 162.2039 -46.7425 -119.9917 117.6783 -38.0319 -126.3976 96.3697 -35.3235 -108.4055 162.7472 -61.3988 -93.4886 98.3964 -77.4282 -92.6329 72.1629 -68.9765 -100.3854 67.2915 -57.0133 -113.6001 162.8399 -68.6146 -105.5847 102.6094 -90.1403
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Perhaps something like this:
thumb = [digits(id0).bones]
thumb = 1x560 struct array with fields:
prev_joint next_joint width rotation
or perhaps this, which returns the first element of each structure array:
first = cellfun(@(s)s(1),{digits(id0).bones})
first = 1x140 struct array with fields:
prev_joint next_joint width rotation
[first.prev_joint]
ans = 1x420
-116.7911 162.2039 -46.7425 -118.7844 162.6437 -45.3555 -121.9578 165.5228 -42.9163 -122.7603 168.2865 -42.1373 -55.5596 379.1909 -25.3262 -124.2343 170.6235 -41.0462 -56.3998 382.6714 -26.1379 -125.5027 172.1781 -40.9584 -57.1402 385.6229 -26.9821 -126.1411 173.0077 -41.2141
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>

Iniciar sesión para comentar.

Más respuestas (1)

SAI SRUJAN
SAI SRUJAN el 1 de Mayo de 2024
Editada: SAI SRUJAN el 1 de Mayo de 2024
Hi Julia,
I understand that you are facing an issue appending data when extracting nested fields as inidividual variables.
Please go through the following code sample to proceed further,
has_hands = ~cellfun(@isempty, {first100.hands});
filtered_first100 = first100(has_hands);
id = {filtered_first100.id};
time = {filtered_first100.timestamp};
hands = {filtered_first100.hands};
hand_type = {};
for i = 1:numel(hands)
if isequal(size(hands{i}), [1,1])
hand_type{end+1} = hands{i}.type;
elseif isequal(size(hands{i}), [1,2])
hand_type{end+1} = hands{i}(1).type;
hand_type{end+1} = hands{i}(2).type;
end
end
The variable 'hands' is a 1x99 struct, containing 41 structs within it, each of size [1,2]. Therefore, the expected size of 'hand_types' should be 140 double as we are parallelly storing the values instead of nesting.
I hope this helps!
  2 comentarios
Stephen23
Stephen23 el 1 de Mayo de 2024
Editada: Stephen23 el 1 de Mayo de 2024
"The variable 'hands' is a 1x99 struct"
No, it is actually a cell array (not a structure). Lets check it right now (note that MATLAB tells us it is a cell array too):
first100 = load('frames.mat').first100;
has_hands = ~cellfun(@isempty, {first100.hands});
filtered_first100 = first100(has_hands);
hands = {filtered_first100.hands} % <- here you define HANDS as a cell array.
hands = 1x99 cell array
Columns 1 through 11 {1x1 struct} {1x1 struct} {1x1 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 12 through 22 {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 23 through 33 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 34 through 44 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 45 through 55 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 56 through 66 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 67 through 77 {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 78 through 88 {1x2 struct} {1x2 struct} {1x2 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x2 struct} {1x2 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 89 through 99 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct}
isstruct(hands) % is it a struct array? (hint: no)
ans = logical
0
iscell(hands) % it is a cell array (exactly as I wrote)
ans = logical
1
If you had used square brackets it would be a structure array (and more efficient data design).
"containing 41 structs within it, each of size [1,2]."
Lets now check that misinformation as well:
C = cellfun(@size,hands,'uni',0);
unique(vertcat(C{:}),'rows')
ans = 2x2
1 1 1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Some of the structures are scalar (i.e. 1x1), some have size 1x2 (just as the OP correctly stated).
"Therefore, the expected size of 'hand_types' should be 140 double as we are parallelly storing the values instead of nesting."
But it won't be, because you defined it to be a cell array, not a double array (you can confirm this by actually running your code):
hand_type = {}; % <- cell array
Note that storing lots of scalar numerics in a cell array is very inefficient data design and should be avoided.
Julia
Julia el 1 de Mayo de 2024
It worked!! Thank you so much! Your help is really appreciated.
I see that I made a mistake when assigning an empty cell array to hand_type. Could you please help me to understand why hand_type = cell(size(hands)); was wrong, and what's the difference between it and hand_type = {};? Sorry I'm quite new to Matlab and may be asking silly questions.
Besides, may I ask a further question? If I also need to double the values in "id" and "time" when "hands" has size [1,2], so that the data in "hands" can still match the id and timestamp, is it possible to do?

Iniciar sesión para comentar.

Categorías

Más información sobre Matrix Indexing en Help Center y File Exchange.

Productos


Versión

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by