Rash
Rash

Reputation: 4336

Continuous plot in MATLAB

I have a loop in my code and I want to plot some variables,

In each iteration I plot a new point and I want it to be connected to the previous point.

Here is an example code (In this code the loop is unnecessary but in actual code, it's not).

n  = 500;
Fs = 1000;
f1 = 10;
t  = 0;
dt = 1 / Fs;
for i = 1 : n
    s = sin(2 * pi * f1 * t);
    t = t + dt;
    plot(t,s,'bo'); hold on;
    axis([0 t(end) -1 1]);
end

enter image description here

The right one is what I want.

I thought of using line but that would get messy (I would have to change i and use 4 points in each line command).

I't seems like a simple question, maybe I'm missing something.

Thanks for any help.

Upvotes: 2

Views: 4581

Answers (3)

craigim
craigim

Reputation: 3914

This is similar to the answer by @Nras, but is faster and easier to read. I've got several programs that do this sort of thing, and depending on how long your calculation loop is, the graphics update can actually be a significant and annoying bottleneck.

If you know how long your vector is ultimately going to be, you can pre-allocate your plot and then update using the handle command:

n  = 500;
Fs = 1000;
f1 = 10;
t  = 0;
dt = 1 / Fs;

s = nan(1,n);
emptyvec = nan(1,n);
h1 = plot(emptyvec,emptyvec,'-bo');
h2 = handle(line(emptyvec,emptyvec,'Color','r','Marker','x','LineStyle','--'));
h1 = handle(h1);


for i = 1 : n
    t = t + dt;
    s = sin(2 * pi * f1 * t);
    h1.XData(i) = t;
    h1.YData(i) = s;
    h2.XData(i) = t;
    h2.YData(i) = s^2;
    drawnow
end

MATLAB ignores 'nan' when calculating the limits, so preallocating with nan makes the call to xlim unnecessary. Also, the pause is unnecessary when I run this. Your mileage may vary. I personally prefer to do something like this:

h = plot(t,emptyvec);

As long as t is known and isn't crazy long, this gives me an idea of not only how the calculation is doing, but also gives me a sort of progress bar. If it is crazy long, I might populate t in chunks or use XData and YData as a circular buffer by using ii = mod(i,100); as the index (for instance), which will produce an oscilloscope type effect. Also, there is a time penalty for constantly recalculating the axis limits.

If you don't know how long your vector will be (if it's in a while loop, for instance), you can either preallocate with a vector that you know will be longer, allocate in chunks, or just do the circular buffer thing.

For multiple plots, preallocate use the line function for each additional line. Unlike plot, you can just wrap the more primitive line function in the handle function directly.

Note that if you're using MATLAB 2014b or greater (I'm not), then the new HG2 graphics system uses objects for handles rather than doubles, so the handle command, which converts the numeric handle to an object handle, is superfluous and the dot notation may be used directly. Also note that handle used this way is undocumented

Upvotes: 4

Nras
Nras

Reputation: 4311

You can use the plot handle and then update the properties 'XData' and 'YData' accordingly. Therefore you can plot the first point before the loop and generate the plot handle. After that, the plot handle is available and the plot can be adjusted within the loop.

n  = 500;
Fs = 1000;
f1 = 10;
t  = (0 : n - 1) / Fs;
s = zeros(size(t));
s(1) = sin(2 * pi * f1 * t(1));
figure
handle = plot(s(1), t(1), 'bo-'); %// the plot handle
for i = 2 : n
    s(i) = sin(2 * pi * f1 * t(i));
    set(handle, 'XData', t(1:i), 'YData', s(1:i)) %// update the plot data
    axis([0 t(end) -1 1]);
    pause(0.1) %// small pause to see animation
end

Upvotes: 4

chipaudette
chipaudette

Reputation: 1675

I would replace your existing plot line with this one

plot(t(1:i),s(1:i)); hold on;

That will plot all of the points from index 1 until the current index. Then, by removing the 'bo', it'll plot using the default format, which is the line that you desire.

Finally, if you want this to actually be animated on the screen (like a movie), you'll need to add a drawnow command before the end of your loop. You also might want to add a pause(0.25) after the draw, to insert a quarter-second delay so that your eye has a chance to see the newly drawn image before it gets overwritten by the next drawing of the image.

Upvotes: 1

Related Questions