How to name different groupes of variables in one vector with indices of another?
1 回表示 (過去 30 日間)
古いコメントを表示
Hello!
I have the following code:
Generator = [3111 3112 3111].' % Gen1 = 3111, Gen2 = 3112, Gen3 = 3111 Input which could be in a different order or more inputs
mod1 ={'\Delta \omega' '\Delta \delta'} % statevariables of one modell
mod2 = {'\Delta \psi' '\Delta v' '\Delta Tw'} % statevariables of second modell
master_mod = {mod1, mod2}
v = [master_mod{mod(Generator,10)}]
The ouput is a 1×7 cell array, which I'm using later to name bars in a bar plot. I'd like to add the index of the Generator to the coresponding variable, so I would get an array like this:. I tried to use num2string but I could only figure out super slow code with a for loop which didn't really work (got 21 instead of 7 cells...).
How can I add the little indices to my variables?
2 件のコメント
dpb
2019 年 8 月 12 日
That's kinda' cute for that far...I had to scratch my head some over how the mod() thingie was working! :)
Interesting problem...I don't have time at this instant but will try to look in again later this evening if somebody else hasn't already solved it...
採用された回答
Adam Danz
2019 年 8 月 12 日
編集済み: Adam Danz
2019 年 8 月 13 日
Updated interpretation
Generator = [3111 3112 3111].';
mod1 ={'\Delta \omega' '\Delta \delta'};
mod2 = {'\Delta \psi' '\Delta v' '\Delta Tw'};
master_mod = {mod1, mod2};
v = master_mod(mod(Generator,10));
vSubscript = cellfun(@(x,d)cellfun(@(x0,d)sprintf('%s_{%d}',x0,d), x,repmat({d},size(x)),'UniformOutput',false),v,num2cell(1:numel(v)),'UniformOutput',false);
newLabels = [vSubscript{:}];
Result
newLabels =
1×7 cell array
Columns 1 through 2
{'\Delta \omega_{1}'} {'\Delta \delta_{1}'}
Columns 3 through 5
{'\Delta \psi_{2}'} {'\Delta v_{2}'} {'\Delta Tw_{2}'}
Columns 6 through 7
{'\Delta \omega_{3}'} {'\Delta \delta_{3}'}
Old interpretation
If you add 1 space to the end of each string, you can replace the empty spaces with subscripts like this.
Generator = [3111 3112 3111].'
mod1 ={'\Delta \omega ' '\Delta \delta '} % 1 space after each sub-string
mod2 = {'\Delta \psi ' '\Delta v ' '\Delta Tw '} % 1 space after each sub-string
% ^ ^ ^ ^ ^ ^ % spaces shown
master_mod = {mod1, mod2}
v = [master_mod{mod(Generator,10)}];
subscripts = 1:numel(v);
indices = strsplit(sprintf('_{%d} ',subscripts)); % underscore will become subscript
newLabels = strrep(v,' ',indices(1:end-1)); % add indices
set(gca, 'XTickLabel', newLabels)
11 件のコメント
Adam Danz
2019 年 8 月 13 日
編集済み: Adam Danz
2019 年 8 月 13 日
Yes, it's possible. But first, two warnings.
- It's possible that there are some inefficiencies in what you're doing. Creating complex labels, then removing some, etc. Just a general reminder to stay organized and efficient even if it requires putting more time into reorganizing code.
- The solution below requires an exact match (except for upper/lower case).
idx = strcmpi(string_xlabel, '\Delta \delta_{3}');
string_xlabel(idx) = [];
Unrelated to that, I agree with Guillaume that a nested cellfun(cellfun()) is ugly and compose() might be cleaner.
Guillaume
2019 年 8 月 13 日
編集済み: Guillaume
2019 年 8 月 13 日
for i=1:length(string_xlabel)
if string_xlabel(i) == {'\Delta\delta_{3}'}
string_xlabel = string_xlabel - string_xlabel(i)
end
end
is certainly never going to work. You don't use == to compare char vectors (or cell arrays) and deleting elements has never been done with the subtraction operator. Plus deleting elements while you're iterating over the element indices is a sure way to get your index out of sync with the elements.
The easiest:
string_xlabel(strcmp(string_xlabel, '\Delta\delta_{3}')) = [];
Note that if it's several elements that need removing:
string_xlabel(ismember(string_xlabel, {'\Delta\delta_{3}', '\Delta\omega_{5}'})) = []; %remove all occurences of dd3 or do5
その他の回答 (1 件)
Guillaume
2019 年 8 月 13 日
編集済み: Guillaume
2019 年 8 月 13 日
It's annoying that compose doesn't accept positions identifiers in the format string, otherwise this could have been done in just one line.
I'd just use a loop, arrayfun or cellfun, wihichever you prefer. First, the format string, I see no point in having a cell array of cell arrays of char vectors. Just have one format for each possibility (which it looks like is just 2 at the moment):
formats = {'\\Delta\\omega_{%1$d}\\Delta\\delta_{%1$d}', ... need the \\ to avoid it being interpreted by sprintf.
'\\Delta\\psi_{%1$d}\\Deltav_{%1$d}\\DeltaTw_{%1$d}'};
With a loop:
labels = cell(size(Generator));
for labelidx = 1:numel(Generator)
labels{labelidx} = sprintf(formats{mod(Generator(labelidx), 10)}, labelidx);
end
With arrayfun:
labels = arrayfun(@(f, n) sprintf(formats{f}, n), mod(Generator, 10), (1:numel(Generator))', 'UniformOutput', false)
With cellfun:
labels = cellfun(@sprintf, formats(mod(Generator, 10)), num2cell(1:numel(Generator)), 'UniformOutput', false)
edited format to have the digits subscripted
2 件のコメント
Guillaume
2019 年 8 月 13 日
編集済み: Guillaume
2019 年 8 月 13 日
In that case:
formats = {{'\\Delta\\omega_{%d}', '\\Delta\\delta_{%d}'}, ... need the \\ to avoid it being interpreted by sprintf.
{'\\Delta\\psi_{%d}', '\\Deltav_{%d}', '\\DeltaTw_{%d}'}};
We can now use compose since there's no need for positional identifiers
With a loop:
labels = cell(size(Generator));
for labelidx = 1:numel(Generator)
labels{labelidx} = compose(formats{mod(Generator(labelidx), 10)}, labelidx);
end
With arrayfun:
labels = arrayfun(@(f, n) compose(formats{f}, n), mod(Generator, 10), (1:numel(Generator))', 'UniformOutput', false)
With cellfun:
labels = cellfun(@compose, formats(mod(Generator, 10)), num2cell(1:numel(Generator)), 'UniformOutput', false)
Basically, the same as before but with compose instead of sprintf since compose is happy to work with multiple format strings at once.
参考
カテゴリ
Help Center および File Exchange で Loops and Conditional Statements についてさらに検索
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!