Search code examples
matlabmatlab-figurepoint-cloudsscatter3d

How to update a scatter3 plot (in a loop) in Matlab


Quite a simple question but just couldn't find the answer online... I want to visualise a point cloud gathered from a lidar. I can plot the individual frames but wanted to loop them to create a "animation". I know how to do it for normal plots with drawnow but can't get it working with a scatter3. If I simply call scatter3 again like I have done in the commented code then the frame that I am viewing in the scatter plot jumps around with every update (Very uncomfortable). How do i get the scatter3 plot to update to the new points without changing the UI of the scatter ie. Still be able to pan and zoom around the visualised point cloud while it loops through.

EDIT: The file is a rosbag file, I cannot attach it because it is 170MB. The problem doesn't happen when using scatter3 in a loop with a normal array seems to be something with using scatter3 to call a PointCloud2 type file using frame = readMessages(rawBag, i).

EDIT: The problem does not seem to be with the axis limits but rather with the view of the axis within the figure window. When the scatter is initialised it is viewed with the positive x to the right side, positive y out of the screen and positive z upwards, as shown in view 1. Then after a short while it jumps to the second view, where the axis have changed, positive x is now out of the screen, positive y to the right and positive z upwards (both views shown in figures). This makes it not possible to view in a loop as it is constantly switching. So basically how to update the plot without calling scatter3(pointCloudData)?


rawBag = rosbag('jackwalking.bag');

frame = readMessages(rawBag, 1);
scatter3(frame{1});
hold on

for i = 1:length(readMessages(rawBag))
    disp(i)
    frame = readMessages(rawBag, i);

    % UPDATE the 3D Scatter %
    % drawnow does not work?
    % Currently using:
    scatter3(frame{1})
    pause(.01)
end

View 1

View 2


Solution

  • The trick is to not use functions such as scatter or plot in an animation, but instead modify the data in the plot that is already there. These functions always reset axes properties, which is why you see the view reset. When modifying the existing plot, the axes are not affected.

    The function scatter3 (as do all plotting functions) returns a handle to the graphics object that renders the plot. In the case of scatter3, this handle has three properties of interest here: XData, YData, and ZData. You can update these properties to change the location of the points:

    N = 100;
    data = randn(N,3) * 40;
    
    h = scatter3(data(:,1),data(:,2),data(:,3));
    for ii = 1:500
       data = data + randn(N,3);
       set(h,'XData',data(:,1),'YData',data(:,2),'ZData',data(:,3));
       drawnow
       pause(1/5)
    end
    

    The new data can be totally different too, it doesn't even need to contain the same number of points.

    But when modifying these three properties, you will see the XLim, YLim and ZLim properties of the axes change. That is, the axes will rescale to accommodate all the data. If you need to prevent this, set the axes' XLimMode, YLimMode and ZLimMode to 'manual':

    set(gca,'XLimMode','manual','YLimMode','manual','ZLimMode','manual')
    

    When manually setting the limits, the limit mode is always set to manual.