Search code examples
rmatlabanimationggplot2gganimate

How to animate 3D scatter plot by adding each point at a time in R or MATLAB


I have a set of 3D coordinates here. The data has 52170 rows and 4 columns. Each row represent one point. The first column is point index number, increasing from 1 to 52170. The second to fourth columns are coordinates for x, y, and z axis, respectively. The first 10 lines are as follow:

seq    x               y        z
1   7.126616    -102.927567 19.692112
2   -10.546907  -143.824966 50.77417
3   7.189214    -107.792068 18.758278
4   7.148852    -101.784027 19.905006
5   -14.65788   -146.294952 49.899158
6   -37.315742  -116.941185 12.316169
7   8.023512    -103.477882 19.081482
8   -14.641933  -145.100098 50.182739
9   -14.571636  -141.386322 50.547684
10  -15.691803  -145.66481  49.946281

I want to create a 3D scatter plot in which each point is added sequentially to this plot using R or MATLAB. The point represented by the first line is added first, then the point represented by the second line, ..., all the way to the last point.

In addition, I wish to control the speed at which points are added.

For 2D scatter plot, I could use the following code:

 library(gganimate)
 x <- rnorm(50, 5, 1)
 y <- 7*x +rnorm(50, 4, 4)
 ind <- 1:50
 data <- data.frame(x, y, ind)

ggplot(data, aes(x, y)) + geom_point(aes(group = seq_along(x))) + transition_reveal(ind)

But I cannnot find information on how to do this for 3D scatter plot. Can anyone show me how this could be done? Thank you.


Solution

  • This is an answer for MATLAB

    In a general fashion, animating a plot (or 3d plot, or scatter plot, or surface, or other graphic objects) can be done following the same approach:

    • Do the first plot/plot3/scatter/surf, and retrieve its handle. The first plot can incorporate the first "initial" sets of points or even be empty (use NaN value to create a plot with invisible data point).
    • Set axis limits and all other visualisation options which are going to be fixed (view point, camera angle, lightning...). No need to set the options which are going to evolove during the animation.
    • In a loop, update the minimum set of plot object properties: XData, YData ( ZData if 3D plot, CData if the plot object has some and you want to animate the color).

    The code below is an implementation of the approach above adapted to your case:

    %% Read data and place coordinates in named variables
    csvfile = '3D scatter plot.csv' ;
    data = csvread(csvfile,2) ;
    % [optional], just to simplify notations further down
    x = data(:,2) ;
    y = data(:,3) ;
    z = data(:,4) ;
    
    %% Generate empty [plot3] objects
    figure
    % create an "axes" object, and retrieve the handle "hax"
    hax = axes ;
    % create 2 empty 3D point plots:
    % [hp_new]   will contains only one point (the new point added to the graph)
    % [hp_trail] will contains all the points displayed so far
    hp_trail  = plot3(NaN,NaN,NaN,'.b','Parent',hax,'MarkerSize',2) ;
    hold on
    hp_new    = plot3(NaN,NaN,NaN,'or','Parent',hax,'MarkerSize',6,'MarkerEdgeColor','r','MarkerFaceColor','g','LineWidth',2) ;
    hold off
    
    %% Set axes limits (to limit "wobbling" during animation)
    xl = [min(x) max(x)] ;
    yl = [min(y) max(y)] ;
    zl = [min(z) max(z)] ;
    set(hax, 'XLim',xl,'YLim',yl,'ZLim',zl)
    
    view(145,72)    % set a view perspective (optional)
    
    %% Animate
    np = size(data,1) ;
    
    for ip=1:np
        % update the "new point" graphic object
        set( hp_new , 'XData',x(ip), 'YData',y(ip), 'ZData',z(ip) )
    
        % update the "point history" graphic object
        % we will display points from index 1 up to the current index ip
        % (minus one) because the current index point is already displayed in
        % the other plot object
        indices2display = 1:ip-1 ;
        set(hp_trail ,...
            'XData',x(indices2display), ...
            'YData',y(indices2display), ...
            'ZData',z(indices2display) )
    
        % force graphic refresh
        drawnow
    
        % Set the "speed"
        % actually the max speed is given by your harware, so we'll just set a
        % short pause in case you want to slow it down
        pause(0.01) % <= comment this line if you want max speed
    end
    

    This will produce:

    enter image description here