MATLAB Answers

1

scrolling plot speed and axis jitter

Asked by Jim Hokanson on 4 Nov 2017
Latest activity Commented on by Jim Hokanson on 6 May 2019
I'd like to create auto-scrolling plots in which data scrolls by, automatically, as it gets collected (from a DAQ). Before worrying about adding data I wanted to first check how plots behave with a pre-defined data vector where I adjust the x-limits to simulate scrolling. Just to clarify, I don't intend to have any manual scrolling, just calls to adjust the axis limits.
This is the baseline code for plotting:
t = 0:1/1000:20;
s = rand(1,length(t)).*sin(0.67*2*pi*t);
ax(1) = subplot(3,1,1);
h1 = plot(t,s);
toc
ax(2) = subplot(3,1,2);
h2 = plot(t,s);
ax(3) = subplot(3,1,3);
h3 = plot(t,s);
Now I'd like to do something like the following:
update_tick = 0;
set(ax,'ylim',[-1 1])
tic
for t2 = 0:0.01:18
set(ax,'xlim',[t2 t2+2]) %Move the data view
update_tick = update_tick + 1;
%At some interval rerender the ticks
if mod(update_tick,5) == 0
xtick = t2:0.1:t2+2;
set(ax,'XTick',xtick)
end
drawnow
%pause(0.005)
end
toc
The code above changes to the x-limits to simulate scrolling/new data and occasionally updates the displayed ticks.
This code however is horribly slow. This takes about 50 seconds to run on my computer. It gets faster if the drawnow is replaced with pause (about 12s) but I have other things to do in the DAQ collection loop and I'd like this number to be closer to 1-2 seconds. For reference, Matlab 2017b documentation states that using the pause function is equivalent to the drawnow command, but I find I like this explanation better (basically a drawnow if possible within allotted time): https://www.mathworks.com/matlabcentral/answers/7309-is-pause-a-superset-of-drawnow#answer_192103
Additionally, as the plotting is occurring the axes are shaking just slightly which is really annoying.
Any suggestions on speeding up the code?

  3 Comments

I should add plotting appears to be proportional to the plot size and I like to have larger plots :)
Update: These numbers aren't as bad if I choose I more realistic update rate like 0.05 or 0.1 (step size for t2), rather than 0.01. Still, is it possible to make this faster? For reference a value of 0.1 with drawnow is 5 seconds (i.e. 1/10 of the 50s from above).
Update: Answers to faster plotting in Matlab generally focus on reducing object creation and manipulating the underlying data directly. Eventually I would like to add data dynamically, but this is focused on updating the scene.
I have tried a few things with surprisingly little luck.
  • set(ax,'DrawMode','fast') (obsolete, alias now for SortMethod?)
  • set(ax,'SortMethod','childorder') - not critical for single lines
  • set(ax,'NextPlot','replacechildren')
  • set(ax,'Clipping','off')
  • set(gcf,'GraphicsSmoothing','off')
  • set(gcf,'Renderer','opengl')
  • set(gcf,'Renderer','painters')
  • opengl hardwarebasic
  • set(ax,'Visible','off')
The only thing that made any difference was turning off the axes visibility, which isn't ideal.

Sign in to comment.

1 Answer

Answer by Joshua Robinson on 29 Apr 2019

Your main problem is that you're forcing matlab to recalculate and update the position and names of all the ticks every couple of iterations. So even if t2 changed by a little bit, every single tick is recalculated.
Instead it would make more sense to only update the tick values that actually change as t2 moves along (aka the first and last ticks).
The quickest way to achieve this is to round t2 to the nearest tick value and add a tick offset array to the rounded t2 value ala...
dtick = 0.1;
tickbase = (0:dtick:2);
% main loop
for t2=tmin:dt:tmax;
% BLAH BLAH BLAH
% calculate new ticks
nearest_tick = dtick*round(t2/dtick);
xtick = nearest_tick + tick_offset;
set(ax,'XTick',xtick)
% BLAH BLAH BLAH
end
So the final code should be something along the lines of...
clear all
close all
t = 0:1/1000:20;
s = rand(1,length(t)).*sin(0.67*2*pi*t);
ax(1) = subplot(3,1,1);
h1 = plot(t,s);
toc
ax(2) = subplot(3,1,2);
h2 = plot(t,s);
ax(3) = subplot(3,1,3);
h3 = plot(t,s);
% my edit
ax(1).XGrid = 'on';
ax(1).YGrid = 'on';
ax(2).XGrid = 'on';
ax(2).YGrid = 'on';
ax(3).XGrid = 'on';
ax(3).YGrid = 'on';
dtick = 0.1;
tick_offset = (0:dtick:2);
update_tick = 0;
set(ax,'ylim',[-1 1])
tic
for t2 = 0:dtick:18
set(ax,'xlim',[t2 t2+2]) %Move the data view
update_tick = update_tick + 1;
% %At some interval rerender the ticks
if mod(update_tick,5) == 0
nearest_tick = dtick*round(t2/dtick); % Code from above
xtick = nearest_tick + tick_offset;
set(ax,'XTick',xtick)
end
drawnow;
end
toc

  3 Comments

Thanks for the answer. I'm not convinced that your suggestion does anything with respect to code execution time. If we had more control over string rendering, than only changing some values might impact speed. As it stands we currently specify a new xtick array for every update, and even though your version shares values with previous versions, it is not clear that Matlab actually cares about that. If you adjust your for loop time-step to match mine (0.01), the execution times are essentially identical.
That being said, in this example my choice of update rate and step size lead to changes in the display label, which are quite visually unpleasant and should be changed. Your code does address this issue.
Yeah sorry, I goofed. I thought I changed the step size back to what you had in the original code.
That being said, I'm curious if you actually need the step size to be 0.01. I don't know about your specific application but it seems like the end goal is to have the graph display one seconds worth of data for every second of real time. And as long as the animation is relatively smooth the exact step size doesn't matter, no?
For example, on my machine if I put the step size to 0.02 it displays the 20 seconds of data in roughly 20 seconds of real time. So you probably need to adjust how many images the loop attempts to draw per second. I think anywhere between 24-60 frames per second is smooth to the human eye.
You can also add in some logic that forces the main loop to pause unless the appropriate time per frame has passed. So that even if your step size is large (~0.1) the code won't rush to display all the information.
And of course the simpler the image is the faster Matlab can draw it. So having less ticks marks makes it so Matlab can push out images faster.
Thanks for the insight. The goal of this example was not to exactly replicate the code that I'm running, but rather to work out a strategy to minimize the time spent rendering the ticks. Thanks though.

Sign in to comment.