Why is scatter so slow for variable marker size?

I found something very strange and annoying. The following code generates 1000 points randomly in the plane, then moves them a bit at each timestep and plots the scatterplot as the system evolves.
% Test scatter plot times
clear
close all
% Fill [0, 1] x [0, 1] with points
rng(1); x = rand(1, 1000);
rng(2); y = rand(1, 1000);
rng(3); cz = rand(1, 1000)*50;
h = scatter(x, y, cz, 'filled', 'MarkerFaceColor', [0,0,0]);
% Replace line below to see speedup
% h = scatter(x, y, 50*ones(size(x)), 'filled', 'MarkerFaceColor', [0,0,0]);
xlim([0, 2]);
ylim([0, 2]);
dt = 0.01;
tic
for j = 1:10
x = x + dt;
y = y + dt;
set(h, 'XData', x, 'YData', y);
drawnow
end
toc
The key is that each scatter point has been given a certain size, specified by the vector cz. The for-loop takes:
Elapsed time is 5.160464 seconds.
However, if cz is replaced with a fixed vector of entries that are all 50, then the speedup is more than a factor of 10.
Elapsed time is 0.336361 seconds.
Increasing the number of points to 5000 drives the difference even further, with one run taking about 30 seconds and the other taking 1 second.
I'm wondering if there is an inefficiency or has Matlab really detected that the vector is entirely constant and uses a special routine to plot?

7 件のコメント

Adam Danz
Adam Danz 2019 年 5 月 17 日
Where are you placing "tic" and "toc"? I just ran a scatter plot with 200,000 points, all of which has random sizes, and it took less than a second.
Theo
Theo 2019 年 5 月 17 日
tic and toc are placed in the code above.
Could be my version of Matlab? I'm running 2016b.
dpb
dpb 2019 年 5 月 17 日
編集済み: dpb 2019 年 5 月 17 日
I reproduce the symptom albeit with only a 3.5X timing differential (1.75 : 0.5)
A different timing test here indicates the big change is owing to updating the X|YData arrays instead of scatter --
> tic;h = scatter(x, y, 50*ones(size(x)), 'filled', 'MarkerFaceColor', [0,0,0]);toc
Elapsed time is 0.053518 seconds.
>> tic;h = scatter(x, y, cz, 'filled', 'MarkerFaceColor', [0,0,0]);toc
Elapsed time is 0.022851 seconds.
>> tic;h = scatter(x, y, 50*ones(size(x)), 'filled', 'MarkerFaceColor', [0,0,0]);toc
Elapsed time is 0.064951 seconds.
>> tic;h = scatter(x, y, cz, 'filled', 'MarkerFaceColor', [0,0,0]);toc
Elapsed time is 0.017134 seconds.
>>
the fixed size is consistently longer than the variable when called directly.
Recasting the loop to redraw using scatter instead of set verifies the set route as being the culprit. With that, the relative speed advantage of random:fixed remains in the favor of random over fixed, even when pass a precomputed array instead of calling ones inside the loopl
WHY that should be is a mystery to me (and the crystal ball...) as is why such a huge disparity with updating the data arrays.
ADDENDUM:
OBTW, R2017b...
Adam Danz
Adam Danz 2019 年 5 月 17 日
@Theo , I see your tic/toc commands surrounding the for-loop, not the scatter() exectution. The "drawnow" command is a huge drag! That's sucking up a lot of time. Unless you need to see the plot develop, it's better to just leave that out.
Theo
Theo 2019 年 5 月 17 日
@Adam Danz: if I understand your point, then I don't think your point addresses my question. My question is indeed about the draw output. Otherwise I would not bother to be updating the figure XData and YData.
If you want a particular objective, then I would like like to create a movie or animation at each time step. Hence a draw command is required at each timestep.
The question remains of why the drawing takes so long for scatter plots of different marker sizes, and as @dpb notes the issue is even stranger.
Adam Danz
Adam Danz 2019 年 5 月 17 日
Ah, I see now.
dpb
dpb 2019 年 5 月 17 日
編集済み: dpb 2019 年 5 月 18 日
" why the drawing takes so long for scatter plots of different marker sizes"
I'm guessing it's not really the drawing that's the culprit given the time results with scatter directly, but somehow related to internal data storage between the variable-sized markers and the constant since the majority of the time issue is clearly with the use of set as opposed to just redrawing the plot from scratch.
For a workaround, I'd suggest just foregoing the set route in favor of calling scatter directly. Try something like
h = scatter(x, y, cz, 'filled', 'MarkerFaceColor', [0,0,0]);
for j = 1:10
x = x + dt; y = y + dt;
delete(h)
h = scatter(x, y, cz, 'filled', 'MarkerFaceColor', [0,0,0]);
end
You may have some more bookkeeping to do to keep limits and all and maybe set hold on will be helpful.
NB: I've not tried to create the simulation this way so above is "air code", just general way that I'd try to find a workaround.
Give it the weekend and a couple days and see if by any chance anybody from TMW stumbles by or somebody else has more intimate knowledge of scatter and HG2 and can shed some light--if not, seems like worthy of a "quality of implementation" support request.

サインインしてコメントする。

回答 (0 件)

カテゴリ

質問済み:

2019 年 5 月 17 日

編集済み:

dpb
2019 年 5 月 18 日

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by