pelt
pelt

Reputation: 113

Matlab : Can Conditional plotting done in a loop be vectorized?

I am wanting to do conditional plotting of vertical lines, that change color based on the value of an integer vector. Those values are integers that range from 0-4.

Currently, I am using a loop to go through the tables to plot the lines. This works, but for LARGE amounts of data it takes time, and I'm wondering if it can be vectorized.

Attached is a stripped down version of the script to loop through a data vector(sample) that simply Loops through the vector, and plots a vertical line based on the value of the integer.

I will also attach the simple variable I created called 'SAMPLE' below to paste into your workspace.

for i=1:size(sample,1)
    if      sample(i)==1 
        line( [i i] ,[0 10], 'Marker','.','LineStyle','-','Color','r');
    elseif  sample(i)==2
        line( [i i] ,[0 10], 'Marker','.','LineStyle','-','Color','b');
    elseif  sample(i)==3
        line( [i i] ,[0 10], 'Marker','.','LineStyle','-','Color',[1 .5 0]);
    elseif sample(i)==4
        line( [i i] ,[0 10], 'Marker','.','LineStyle','-','Color','g');
    end
end

Variable:

sample=[[3;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;0;0;0;0]];

But is is possible to 'vectorize' plotting in this way w/o having to do it iteratively in a loop as I have done?

Picture of Desired Output

Upvotes: 1

Views: 115

Answers (2)

craigim
craigim

Reputation: 3914

Take advantage of the fact that when plotting a line, MATLAB will skip points whose value is NaN.

% Your vector
sample=[3;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;0;0;0;0];

% Your colors
colors = [
    1 0 0
    0 0 1
    1 .5 0
    0 1 0];

for idx = 1:4
    % Find the index of each of your integers
    X = find(sample == (idx));

    % Force X to be a row vector
    X = X(:)';

    % Stack two X's on top of one another with a third row filled
    % with NaNs. Fill in your Y values in the same way while
    % you're at it.
    Y = [zeros(size(X)); 10 + zeros(size(X)); nan(size(X))];
    X = [X; X; nan(size(X))]; %#ok<AGROW>

    % Matlab is column major. By using the colon here, you
    % produce a vector that is [X1 X1 nan X2 X2 nan ... etc.]
    X = X(:);
    Y = Y(:);

    % Draw the line
    line(X, Y, 'Marker', '.', 'LineStyle', '-', 'Color', colors(idx, :))
end

There's still a loop, but now you're just looping over the possible values instead of looping over the each value in the vector. I think you will find that this will scale much better.

Changing input to:

sample = zeros(1, 1e6);
for idx = 1:4
    sample(randi(1e6, 1, 1000)) = idx;
end

and benchmarking with timeit gives a time of 0.0065706 seconds on my machine, while the OP code benchmarks at 1.4861 seconds.

Upvotes: 2

Ander Biguri
Ander Biguri

Reputation: 35525

I'd change to something like:

colors=[1 0 0,
        0 1 0,
        1 0.5 0,
        0 0 1];

nnsamples=samples(samples~=0);

for ii=1:size(nnsamples,1)

        line( [ii ii] ,[0 10], 'Marker','.','LineStyle','-','Color',colors(nnsamples(ii),:));

end

Upvotes: 1

Related Questions