Manipulating a structure for a more flexible plot
조회 수: 1 (최근 30일)
이전 댓글 표시
Hi,
I am building an app to fit different models to experimental data, each corresponding to a given values of the variable Q, and at the end to plot the results for each parameters vs Q.
The fit output is a structure, named Int, with many fields.
For simplicity I consider here the case with only 3 Qs values:
Int =
struct with fields:
Q: [7 9 10]
ParsNames: {{13×1 cell} {13×1 cell} {13×1 cell}}
ParsFit: {[13×1 double] [13×1 double] [13×1 double]}
eParsFit: {[13×1 double] [13×1 double] [13×1 double]}
In this case the model has 13 parameters, that are stored for each Q in the cells ParsFit, with their errors, and names.
The ParsNames are always the same (Int.ParsNames{1}=Int.ParsNames{2}= ...), in this case:
Int.ParsNames{1} =
{'A0' }
{'A1' }
{'B0' }
{'B1' }
{'IL' }
{'GL' }
{'ID1' }
{'GD1' }
{'ED1' }
{'ID2' }
{'GD2' }
{'ED2' }
{'Chi2_r'}
I need to plot all the variables vs Q. For instance, for the 3 values of the parameter at the position 12:
for k = 1 : length(Int.Q)
ED2(k)=Int.ParsFit{1,k}(12,1); % I used the same variable name as the ParsNames
eED2(k)=Int.eParsFit{1,k}(12,1);
end
figure; errorbar(Int.Q,ED2,eED2)
This of course works, but I'd like to make the app more flexible because the number and name of parameters can vary.
In the example above, I named myself the variable with the proper name (ED2), and I’d avoid that: using another model, the parameter ED2 could be missing, and I would like to avoid writing different scripts for each case
As far as I understood, it is not suggested to define all the variables using dynamically the values contained in ParNames.
I wonder whether (and how) I can build another structure that is almost the transpose of Int with fields equal to those of Int:
newInt.A0 with all the Int.ParsFit{1,k}(1,1)
newInt.A1 with all Int.ParsFit{1,k}(2,1)
........
and put inside them all the Int.ParsFit{1,k}(12,1), and then plot all of them.
Is it possible to name the fields of the new structure with those of the original one Int.ParsNames{1} ?
Do you have suggestion to plot the data in the more clean, logical, and flexible way?
Thanks for your help!
댓글 수: 2
Stephen23
2022년 3월 22일
편집: Stephen23
2022년 3월 22일
"Is it possible to name the fields of the new structure with those of the original one Int.ParsNames{1} ?"
Of course: you can get a cell array of all fieldnames using FIELDNAMES, and create fields is a structure either using SETFIELD or dynamic fieldnames (simpler):
In practice this will require a loop and paying careful attention to the details, but it isn't difficult.
"Do you have suggestion to plot the data in the more clean, logical, and flexible way?"
I would suggest that rather than a scalar structure (where every field has size 1xN) you might like to consider using a 1xN non-scalar structure, which means you don't need those cell arrays any more.
"I need to plot all the variables vs Q.... but I'd like to make the app more flexible because the number and name of parameters can vary."
Of course they can. There is absolutely no need for the variable you use in the code to have the same name as your meta-data. If you used a non-scalar structure then you could trivially concatenate them into matrices too (rather than lots of anti-pattern separate variables with ugly-numbered variable names), which would make plotting easier because you could use the inbuilt ability to plot matrices rather than trying to mess around with lots of separate variables and whatnot.
채택된 답변
Stephen23
2022년 3월 22일
편집: Stephen23
2022년 3월 23일
Data in a 3x1 structure array (rather than a scalar structure with nested cell arrays as you showed) means slightly simpler data access because you can use a simpler syntax for accessing the field data in comma-separated lists.
C = {'A0';'A1';'B0';'B1';'IL';'GL';'ID1';'GD1';'ED1';'ID2';'GD2';'ED2';'Chi2_r'};
S(1).Q = 7;
S(1).ParsNames = C;
S(1).ParsFit = rand(13,1);
S(1).eParsFit = rand(13,1);
S(2).Q = 9;
S(2).ParsNames = C;
S(2).ParsFit = rand(13,1);
S(2).eParsFit = rand(13,1);
S(3).Q = 10;
S(3).ParsNames = C;
S(3).ParsFit = rand(13,1);
S(3).eParsFit = rand(13,1);
Plot:
Q = [S.Q];
M = [S.ParsFit];
ax = axes();
ax.LineStyleOrder = {'-o','-+','-*'};
hold(ax,'on')
plot(ax,Q,M.')
legend(S(1).ParsNames)
댓글 수: 6
Stephen23
2022년 3월 24일
"However, I append below the main sequence of what I am doing in case you like to have a look."
Good work, it looks fine to me.
The main thing is, that you can see ways to use a loop to process your data groups.
추가 답변 (0개)
참고 항목
카테고리
Help Center 및 File Exchange에서 Data Preprocessing에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!