How to concatenate these subplots on one graph?

空扰寡人 提交于 2019-12-01 13:36:22

问题


Here is the a simpler version of my code.

.....
ch_array = [36, 40, 44, 48, 149, 161];
figure;

for i=1:length(ch_array) 
    ch = ch_array(i);     
    subplot(3, 3, i);
    eval(sprintf('plot(mean_a_%d_f, ''r'')', ch));
    hold on;
    eval(sprintf('plot(mean_b_%d_f, ''b'')', ch));
    xlabel('Subcarrier (f)');
    ylabel('Absolute values');
    eval(sprintf('title(''Channel: %d'')', ch));
end
.....

The mean_a and mean_b depend on the ch_array so that as a result, there are mean_a_36_f, mean_a_40_f,..., mean_a_161_f and the same thing with the mean_b.

This for loop plots graphs according to ch_array, the following figure:

As you can see, for each ch_array element is plotted the corresponding mean_a_ch and mean_b_ch.

Now, the purpose is these subplots to concatenate so that all are on one figure, but concatenated and not so how the hold on does. The concatenation should look like this:

where for the each concatenated plot will be denoted on the X axis, as can be seen on the pic.


回答1:


You have two problems. I'll start with the one you didn't ask about, since I'm worried you'll stop reading once I answer the other one.

You should not be using eval unless it's really necessary, and it's never necessary. eval is slow and insecure. If you eval malicious code, it can easily do serious harm to your system. In this case this is unlikely, but still using eval prevents MATLAB's just-in-time compiler to be able to optimize anything in the code inside, so you'll get the worst possible performance.

Now, you're claiming that you're stuck with eval because the variables are already set up dynamically. Note that this is a perfect example of an XY problem: you shouldn't end up with these data in the first place. Do them differently. If you're not in control of data creation, keep hitting the head of the person who is, so that they stop.

Anyway, once the damage is done, you can still quickly recover from the eval pit of doom. You need to save and reload your variables, which allows you to push them into a struct. This is nice, because struct fields can be accessed dynamically. Rewriting your original:

tmpfile = 'tmp.mat';
save(tmpfile,'mean_*_*_f'); % save relevant variables to tmp mat file
dat = load(tmpfile); % reload them into a struct named dat

ch_array = [36, 40, 44, 48, 149, 161]; % we could deduce these programmatically
figure;

for i=1:length(ch_array) 
    ch = ch_array(i);     
    subplot(3, 3, i);
    plot(dat.(sprintf('mean_a_%d_f',ch)), 'r'); % look, Ma, no eval!
    hold on;
    plot(dat.(sprintf('mean_b_%d_f',ch)), 'b');
    xlabel('Subcarrier (f)');
    ylabel('Absolute values');
    title(sprintf('Channel: %d',ch)); % seriously, this DID NOT need eval
end

Now, for your question. The problem is that plot(y) with this simple syntax plots y as a function of 1:numel(y): essentially plot(1:numel(y),y). What you want to do is manually shift the x points for each data set so they don't overlap:

figure;

offset = 0;
midpoints = zeros(size(ch_array));
for i=1:length(ch_array) 
    ch = ch_array(i);     

    % deduce data to plot
    tmpdat_a = dat.(sprintf('mean_a_%d_f',ch));
    tmpdat_b = dat.(sprintf('mean_b_%d_f',ch));
    x_a = offset+1:offset+numel(tmpdat_a);
    x_b = offset+1:offset+numel(tmpdat_b);

    % plot
    plot(x_a, tmpdat_a, 'r');
    hold on;
    plot(x_b, tmpdat_b, 'b');

    % store xtick position
    midpoints(i) = mean(mean(x_a), mean(x_b));

    % increment offset
    offset = offset + numel(max([tmpdat_a, tmpdat_b])) + 10; % leave a border of width 10, arbitrary now
end

xlabel('Subcarrier (f)');
ylabel('Absolute values');
xticks(midpoints);
xticklabels(arrayfun(@num2str, ch_array, 'uniformoutput', false));
title('All channels');


来源:https://stackoverflow.com/questions/44748386/how-to-concatenate-these-subplots-on-one-graph

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!