How to plot lines from a structure array faster?

27 views (last 30 days)
Darcy Cordell
Darcy Cordell on 12 Nov 2024 at 18:27
Answered: Walter Roberson on 12 Nov 2024 at 19:48
I have a structure array with a series of line segments with the following form:
S(1).Lat and S(1).Lon are both vector arrays of latitude and longitude points, respectively, with length N x 1
S(2).Lat and S(2).Lon are both vector arrays of latitude and longitude points, respectively, with length M x 1
and so on. In total there are 6279 separate line sem so the final line is stored in S(6279). Each Lat and Lon array is a different size so I cannot reshape to form a matrix.
Each line is defined by only about 14 coordinates, on average. So overall, I have less than 100000 points which need to be plotted. To me, this is not very many points and should be possible to plot very quickly. Some tests show that I don't understand how the plotting works:
Example #1: Execution time of 0.2 seconds. Random numbers from 0 to 1.
lat = rand(10^5,1);
lon = rand(10^5,1);
tic
worldmap('world');
plotm(lat,lon,'-k');
toc
Example #2: Execution time of 40 seconds. The only difference here is that random numbers are designed to cover the entire globe
lat = -90+180*rand(10^5,1);
lon = -180+(360+180)*rand(10^5,1);
tic
worldmap('world');
plotm(lat,lon,'-k');
toc
Example #3: Execution time of (forever). The difference here is that I've put the random numbers in a structure. Note that this is the fastest plotting method I've found online. I've let this run on my computer for >30 minutes and it still has not output anything.
%First, generate the random structure. (Completes in a fraction of a second)
S = [];
for i = 1:10000
nSeg = 10; %Note that here I am just setting the line segment length to 10 so that I
%get exactly 10^5 points to plot in total. In reality, nSeg
%is random integer centered on 14
S(i).Lat = -90+180*rand(nSeg,1);
S(i).Lon = -180+(360+180)*rand(nSeg,1);
end
%Time the plotting specifically:
tic
worldmap('world');
p = arrayfun(@(a) plotm(a.Lat,a.Lon,'-k'),S);
toc
Some questions:
(1) Why is Example #2 nearly 40 times slower than Example #1? Its the same number of points, just the location of the points change.
(2) Why is Example #3 so slow that it does not complete after >30 minutes (and still has not...)?
(3) Is there some way to speed up Example #3 to make this more useable? Currently, it is not feasible for me to plot this relatively small dataset!
Any help is much appreciated. Thanks!
  2 Comments
Walter Roberson
Walter Roberson on 12 Nov 2024 at 18:51
We do not know what N(i) is
Your code is timing the generation of random numbers, not just the plotting.
tic/toc cannot properly time plotting. tic/toc can time how long to dispatch the graphics into internal queues, but cannot time how long it takes to process the internal queues.
Could you confirm that you want a constant line color for all of the actual plotting you are doing?
Darcy Cordell
Darcy Cordell on 12 Nov 2024 at 19:12
Fixed the N(i) issue and the placement of the tic call. Interesting to know that it cannot time the plotting itself. For now, constant line color is okay. Although if there is a way to do it with multi-color lines that would be helpful too. Thanks!

Sign in to comment.

Answers (2)

Darcy Cordell
Darcy Cordell on 12 Nov 2024 at 18:46
I just figured out one solution and I will answer my own question in case others are interested. Still happy to hear if others have something more elegant or faster.
Example #4: Convert structure to cell array and single vector with NaNs. Total time ~40 seconds.
%Initialize structure as before in Example #3
S = [];
for i = 1:10000
S(i).Lat = -90+180*rand(10,1);
S(i).Lon = -180+(360+180)*rand(10,1);
end
%Begin timing the method
tic
nLines = length(S);
for i = 1:nLines
%Add a NaN to each line segment
S(i).Lat = [S(i).Lat; NaN];
S(i).Lon = [S(i).Lon; NaN];
end
%Convert to cell
Scell = squeeze(struct2cell(S));
%Get a long vector of lat and lon with NaNs breaking up segments
lat = vertcat(Scell{1,:});
lon = vertcat(Scell{2,:});
%Plot
worldmap('world');
plotm(lat,lon,'-k');
toc
Total time is about 40 seconds, similar to Example #2 in my original question.
Still would be interested to know if there is a further speed-up possible.
  1 Comment
Walter Roberson
Walter Roberson on 12 Nov 2024 at 19:36
Edited: Walter Roberson on 12 Nov 2024 at 19:43
Alternate formation without looping for adding the NaN.
for i = 10000:-1:1
S(i).Lat = -90+180*rand(10,1);
S(i).Lon = -180+(360+180)*rand(10,1);
end
tic
lat = cell2mat(reshape([{S.Lat}; num2cell(nan(1,size(S,2)))],[],1));
lon = cell2mat(reshape([{S.Lon}; num2cell(nan(1,size(S,2)))],[],1));
toc
Elapsed time is 0.024831 seconds.
tic
worldmap('world');
toc
Elapsed time is 1.170074 seconds.
tic
plotm(lat,lon,'-k');
toc
Elapsed time is 39.163956 seconds.
toc
Elapsed time is 39.165527 seconds.

Sign in to comment.


Walter Roberson
Walter Roberson on 12 Nov 2024 at 19:48
The difference in plotting times is due to the difference in range of coordinates. If you were to
plotm(lat/10, lon/10, '-k')
then the plotting would take less than 1 second. If you were to
plotm(lat/2, lon/2, '-k')
the plotting takes about 20 seconds.

Community Treasure Hunt

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

Start Hunting!