Stem plot inside a for loop

3 visualizzazioni (ultimi 30 giorni)
Isma_gp
Isma_gp il 25 Gen 2019
Commentato: Isma_gp il 25 Gen 2019
Hi,
I have a structure (attached) with the data arranged as follows:
for k=1:n
structure.stormk.data
where data refers to 10 different doubles.
I need a stem plot with the format attached (picture). The x-axis will cover k=1:n storms, and the data is plotted for each of them as shown.
At the end I will end up with 10 of these plots (data), covering the k storms.
Can I get some help with this type of plot? Thanks
example_plot.png

Risposta accettata

Guillaume
Guillaume il 25 Gen 2019
Numbered variables, fields, etc. are almost always a bad idea. You end up writing meta-code to manipulate the variable, field, whatever names instead of writing code to manipulate the content of the variables. In your particular case, since the lexicographical order of your field names does not correspond to the numerical order, you're going to have to first use a special sort on your field names (I assume you want storm2 to be plotted before storm11). There's a simple way to have numbers associated with things in matlab, the indices of arrays.
So, instead of
LTA_stormplot_motions.storm1
LTA_stormplot_motions.storm2
LTA_stormplot_motions.storm3
you should have one storm field which is a structure array:
LTA_stormplot_motions.storm(1)
LTA_stormplot_motions.storm(2)
LTA_stormplot_motions.storm(3)
Or even simpler, since the structure would have only one field:
LTA_stormplot_motions(1)
LTA_stormplot_motions(2)
LTA_stormplot_motions
You should modify whatever code you used to create that structure to get the latter. If it's really not possible we can convert the former. You'll need a special sort function such as natsort by Stephen Colbeldick:
[~, order] = natsort(fieldnames(LTA_stormplot_motions)); %requires natsort from the fileexchange
LTA_stormplot_motions = orderfields(LTA_stormplot_motions, order);
LTA_stormplot_motions = structfun(@(f) f, LTA_stormplot_motions);
Note that I've ignored that storm 38 is missing from your structure. The above will renumber storm 39-77 to 38-76. If that's not desired, then it can be avoided.
Now for plotting, stem is not really designed to plot multiple datasets next to each other, so we're going to have to cheat. It may be better to have each dataset in their own axis next to each other. Otherwise, we have to do something similar to TADA's answer. If you don't need each stom as a separate stem plot (ie. separate entry in legend) it's even simpler:
spacing = 50; %spacing between each storm stem plot.
fignames = fieldnames(LTA_stormplot_motions);
for figidx = 1:numel(fignames)
fname = fignames{figidx}; %current field we're working on (also figure title)
figure;
title(fname, 'Interpreter', 'none');
stormdata = {LTA_stormplot_motions.(fname)};
stormlength = cellfun(@length, stormdata);
stormstart = [1, cumsum(stormlength(1:end-1) + spacing)];
x = cell2mat(arrayfun(@(s, l) s:s+l-1, stormstart, stormlength, 'UniformOutput', false));
y = cell2mat(stormdata);
stem(x, y);
xticks(stormstart + stormlength / 2);
xticklabels(compose('storm %d', 1:numel(stormdata)))
end
Of course, with 76 plots side by side everything is squished together.
  1 Commento
Isma_gp
Isma_gp il 25 Gen 2019
Thanks for all the explanations and the code.

Accedi per commentare.

Più risposte (1)

TADA
TADA il 25 Gen 2019
I didn't use your data because I have no idea what you want from it
if exist('fig1', 'var') && ishandle(fig1)
close(fig1);
end
fig1 = figure(1);
k = 10;
n = randi(4, 1, k) + 2; % random mock n data points per storm
intervalBetweenStorms = 20;
for i = 1:k
x = (1:n(i)) + i*intervalBetweenStorms;
y = normrnd(10, 2, 1, n(i));
stem(x, y, 'b', 'Marker', 'none');
hold on;
end
xticks((1:k)*intervalBetweenStorms);
xticklabels(strcat('Storm ', cellfun(@num2str, num2cell(1:k), 'UniformOutput', false)));

Categorie

Scopri di più su Line Plots in Help Center e File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by