Visualizing large 3D dataset with scatter plot

2019-05-16 15:45发布

I'm running a simulation in MATLAB in which I have a large 3D dataset that changes each time step. I'm trying to visualize the data using a 3D scatter plot with points that take on different locations, sizes, colors, and transparency levels as the simulation proceeds. The size and color information are redundant.

Rendering and rotating the figure in MATLAB is slow and choppy. My computer has a 4 GHz i7-4790 CPU and a NVIDIA GeForce GTX 750 Ti graphics card. I am using Matlab R2016a on Windows 7. I checked my MATLAB OpenGL settings and the hardware support level is full. (Hardware OpenGL is necessary for transparency.) Moreover, I'm monitoring my GPU usage using GPU-Z, and during plotting and rotation, the GPU load peaks at only 25-30%.

Here is my code sample:

load sample_data2
channels_matrix = cat(1, channels{:});
num_channels = length(channels);
channel_lengths = cellfun(@(x) size(x, 1), channels);

figure(1);
for i = 1:num_channels
    g = plot3(channels{i}(:, 1), channels{i}(:, 2), channels{i}(:, 3), 'k');
    set(g, 'LineWidth', 1.5)
    hold on;
    text(channels{i}(1, 1), channels{i}(1, 2), channels{i}(1, 3), num2str(i))
end
caxis([0 1])
colorbar
drawnow

numDivisions = 8;
ptsPerDivision = numel(grid_x)/numDivisions;
T = 1000;
numplotpts = 2E4;
for t = 1:T
    plot_signal = nan(size(grid_x));
    plot_signal(sort(randsample(numel(grid_x), numplotpts))) =...
        sort(rand(numplotpts, 1));
    tic
    for i = 1:numDivisions
        temp = plot_signal(dists_idx((i-1)*ptsPerDivision+1:i*ptsPerDivision));
        yplot = grid_y(dists_idx((i-1)*ptsPerDivision+1:i*ptsPerDivision));
        xplot = grid_x(dists_idx((i-1)*ptsPerDivision+1:i*ptsPerDivision));
        zplot = grid_z(dists_idx((i-1)*ptsPerDivision+1:i*ptsPerDivision));
        if t == 1
            h(i) = scatter3(yplot(~isnan(temp)), xplot(~isnan(temp)),...
                zplot(~isnan(temp)), 50*temp(~isnan(temp)), temp(~isnan(temp)), ...
                'filled', 'MarkerFaceAlpha', exp(-i)^0.25);
        else
            h(i).XData = yplot(~isnan(temp));
            h(i).YData = xplot(~isnan(temp));
            h(i).ZData = zplot(~isnan(temp));
            h(i).SizeData = 50*temp(~isnan(temp));
            h(i).CData = temp(~isnan(temp));
        end
    end
    drawnow
    toc
end

and here is a link to the data. Is there any way to speed up the rendering and make rotation smoother? I noticed that fixing the size of all data points to a single scalar greatly speeds up rendering and rotation. Is it possible to keep the size as it is in the code and still have the figure render and rotate quickly?

Edit: A related question I posted.

2条回答
萌系小妹纸
2楼-- · 2019-05-16 16:08

It sounds like the timer function is a good place to try next in order to get a sense of your simulation's progression and then making an AVI once you are satisfied with how things look.

MATLAB's got some great documentation for it with a variety of options for consecutive calls are made and the spacing between them. Check out the ExecutionMode and Period properties.

查看更多
霸刀☆藐视天下
3楼-- · 2019-05-16 16:08

I'm not sure this will solve all the problem, but as a first step I would suggest taking all calculations out of the loop that is used for drawing. Here is a suggestion how to do it:

load sample_data2
clf
channels_matrix = cat(1, channels{:});
num_channels = length(channels);
channel_lengths = cellfun(@(x) size(x, 1), channels);

figure(1);
for k = 1:num_channels
    g = plot3(channels{k}(:, 1), channels{k}(:, 2), channels{k}(:, 3), 'k');
    set(g, 'LineWidth', 1.5)
    hold on;
    text(channels{k}(1, 1), channels{k}(1, 2), channels{k}(1, 3), num2str(k))
end
caxis([0 1])
colorbar
drawnow

numDivisions = 8;
ptsPerDivision = numel(grid_x)/numDivisions;
T = 1000;
numplotpts = 2E4;

% -> chnages starts here:

% first loop for creating random indices
plot_signal = nan(size(grid_x));
rand_numplotpts =sort(rand(numplotpts,T),1);
rand_inds = zeros(numplotpts,T);
for t = 1:T % one loop for creating random indices
    rand_inds(:,t) = sort(randperm(numel(grid_x),numplotpts));
end
plot_signal(rand_inds(:,t)) = rand_numplotpts(:,t);

% second loop for drawing the first instance:
for k = 1:numDivisions
    temp = plot_signal(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
    yplot = grid_y(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
    xplot = grid_x(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
    zplot = grid_z(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
    h(k) = scatter3(yplot(~isnan(temp)), xplot(~isnan(temp)),...
        zplot(~isnan(temp)), 50*temp(~isnan(temp)), temp(~isnan(temp)), ...
        'filled', 'MarkerFaceAlpha', exp(-k)^0.25);
end

% third loop to calculate all timesteps:
[X,Y,Z,S,C] = deal(nan(size(temp,1),numDivisions,T));
for t = 2:T 
    plot_signal(rand_inds(:,t)) = rand_numplotpts(:,t);
    for k = 1:numDivisions
        temp = plot_signal(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
        yplot = grid_y(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
        xplot = grid_x(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
        zplot = grid_z(dists_idx((k-1)*ptsPerDivision+1:k*ptsPerDivision));
        non_nan_inds = ~isnan(temp);
        inds = 1:sum(non_nan_inds);
        X(inds,k,t) = yplot(non_nan_inds);
        Y(inds,k,t) = xplot(non_nan_inds);
        Z(inds,k,t) = zplot(non_nan_inds);
        S(inds,k,t) = 50*temp(non_nan_inds);
        C(inds,k,t) = temp(non_nan_inds);
    end
end

% forth loop to draw all data:
for t = 2:T
    for k = 1:numDivisions
        h(k).XData = Y(:,k,t);
        h(k).YData = X(:,k,t);
        h(k).ZData = Z(:,k,t);
        h(k).SizeData = S(:,k,t);
        h(k).CData = C(:,k,t);
        drawnow
    end
end
查看更多
登录 后发表回答