How do I speed up plotting of interactable scatter points?

조회 수: 15 (최근 30일)
Daniel Ko
Daniel Ko 2019년 8월 23일
답변: MOHAMMED BELAL 2020년 1월 11일
Hello,
I have the following code:
for ii = 1:length(tempSpikes)
p(ii) = plot(app.Trace, tempSpikes(ii)*app.msConvert, app.xi(app.m.mainCh,tempSpikes(ii)),'k*');
end
set(p, 'ButtonDownFcn', {@pointSelected, app.Trace, p})
set(app.Trace,'UserData', []);
This plot loop plots 100s to 1000s of individual markers that can be clicked on using the callback pointselected.
pointselected is a function that just flags which markers have been selected/deselected.
This plotting process takes a long time (>10 sec), and using figure tools like zoom and pan are very slow also.
Is there a way to speed this up? I tried replacing the plot command with scatter and that was 3 times as slow.
Thanks!
Edit: The plot I have has the xaxis range from 0 to 2e5 while the yaxis ranges from -1000 to 1000 at a aspect ratio of 2:1. So using ginput and distance finding is not ideal as the distance in the xaxis is much greater per pixel causing unexpected points to be chosen if the mouse is slightly off the point.
Also ideally I would like the points to be clickable and unclickable infinitely until I press a button to act on the data. I may be zooming in and out between clicking points and clicking other buttons on the GUI. ginput locks me into point collection mode.

채택된 답변

Stephen23
Stephen23 2019년 8월 23일
편집: Stephen23 2019년 8월 23일
Actually one single plot or line call can generate multiple line objects even if each one line only contains one point, the trick is to provide both X and Y matrices as:
  • the 1st row are the data points to be plotted,
  • the 2nd row are NaN.
This forces MATLAB to recognise each column as one point. Here is a working example:
X = rand(1,1000);
X(2,:) = NaN;
Y = rand(1,1000);
Y(2,:) = NaN;
H = plot(X,Y,'*');
set(H,'ButtonDownFcn',@(o,e)set(o,'Marker','o'))
Giving this plot (without any obvious delay when plotted):
In this example I have already clicked on four points in the top left-hand corner, where the marker was changed into circles by the callback. The callback works quickly, there is no significant delay after clicking on a point.
  댓글 수: 1
Daniel Ko
Daniel Ko 2019년 8월 24일
This works fantastically! Thanks. Good technique to keep in mind.

댓글을 달려면 로그인하십시오.

추가 답변 (4개)

darova
darova 2019년 8월 23일
Creates handler for each point
x = rand(3,1);
y = rand(3,1);
h = plot([x x*0]',[y y*0]','.r');
Select points
x = rand(10,1);
y = rand(10,1);
plot(x,y,'.r')
g = ginput(3);
D = pdist2([x y],g);
[~,ix] = min(D);
hold on
plot(x(ix),y(ix),'or')
hold off
  댓글 수: 4
Daniel Ko
Daniel Ko 2019년 8월 23일
Why would I accept an answer that doesn't answer the question fully?
darova
darova 2019년 8월 23일
How do you want to select points then? Without using mouse?

댓글을 달려면 로그인하십시오.


Yair Altman
Yair Altman 2019년 8월 23일
Try to use the vectorized version of plot to plot all the data points in a single function call rather than a loop, and also try using a simpler marker object (e.g. '+' rather than '*'):
p = plot(app.Trace, tempSpikes*app.msConvert, app.xi(app.m.mainCh,tempSpikes), 'k+');
You can also try to replace the plot function with the lower-level line function, which is faster than either plot or scatter (example).
Alternatively, you could possibly also use the scatter function, which has an undocumented speedup option, which is quite old so might not work in your case, but it's worth a try (link).
Similarly, there are multiple other ways to improve plotting performance of plot/line (link).
  댓글 수: 1
Daniel Ko
Daniel Ko 2019년 8월 23일
Thanks for the links.
Vectorising the plot seems to creates one line object instead of an array of line objects one for each point so the ButtonDownFcn acts on all of the points at once. What I want is for all the individual points/markers to be separate for the callback.
Am I doing the vectorisation wrong? Or is this what I should expect? Putting NaNs between values in the input arrays did not work either.

댓글을 달려면 로그인하십시오.


Yair Altman
Yair Altman 2019년 8월 23일
Indeed - you get a single line object with multiple data points, this is the main reason for the speedup. In your callback you can determine which data-point was clicked by checking the click-location's proximity to the data points, something similar to the following:
hAxes = gca;
clickedPos = get(hAxes,'CurrentPoint');
xSize = diff(hAxes.XLim);
ySize = diff(hAxes.YLim);
% compute distance of clicked point from all data points
dist = hAxes.PlotBoxAspectRatio(1)^2 * ((clickedPos(1,1)-p.XData)./xSize).^2 ...
+ hAxes.PlotBoxAspectRatio(2)^2 * ((clickedPos(1,2)-p.YData)./ySize).^2;
% select the data point which is relatively closest to the clicked point
[minDist, dataPointIdx] = min(dist);

MOHAMMED BELAL
MOHAMMED BELAL 2020년 1월 11일
hello how i can plot Sobel,Prewitt,Laplacian Edge Detectors performance and process time for comparison.
Any help ?
thank you.

카테고리

Help CenterFile Exchange에서 Graphics Object Programming에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by