Manipulating a structure for a more flexible plot
1 vue (au cours des 30 derniers jours)
Afficher commentaires plus anciens
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 commentaires
Stephen23
le 22 Mar 2022
Modifié(e) : Stephen23
le 22 Mar 2022
"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.
Réponse acceptée
Stephen23
le 22 Mar 2022
Modifié(e) : Stephen23
le 23 Mar 2022
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 commentaires
Stephen23
le 24 Mar 2022
"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.
Plus de réponses (0)
Voir également
Catégories
En savoir plus sur Data Preprocessing dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!