I try to show the road network, which has over 400,000 segments. I first tried the package OpenStreetMapXPlot.jl. However, it takes very long time and cannot plot. Then, I tried to use GLMakie.jl
using Makie, GeometryTypes
scene = Scene()
for r in roads # over 400,000 roads
xs = ...
ys = ...
lines!(scene, xs, ys, color = :blue, linewidth = 1)
It takes a long time to plot 10,000 road segments. It seems also impossible to show the large network.
I use the software QGIS, which is developed using C++, to show the road network and it works very smooth.
Is GLMakie.jl the proper package to show the large road network? Or some other technology is better?
Maybe you can avoid the calls to the plotting functions inside the loop? Have you tried calling lines! only once on a large vector of xs and ys, potentially separated by NaNs?
For example, I get a 200x speed up doing that with Plots.jl on this example:
xs = [rand(100) for _ in 1:1000]
ys = [rand(100) for _ in 1:1000]
function plot1(xs, ys)
plt = plot()
for (x, y) in zip(xs, ys)
plot!(plt, x, y)
function plot2(xs, ys)
plot(reduce(vcat, xs), reduce(vcat, ys))
@btime plot1($xs, $ys) ; # 431.335 ms (2231129 allocations: 121.87 MiB)
@btime plot2($xs, $ys) ; # 2.844 ms (2530 allocations: 3.20 MiB)
# BTW in this case a simple call to plot(xs, ys) works, but it slow for me:
@btime plot($xs, $ys) ; # 205.678 ms (1374088 allocations: 72.29 MiB)
Thanks for your reply! plot2() is different from plot1(). plot1() draws 1000 separated lines, while plot2() draw one line, which links 1000 lines as one. This would be the reason while plot2() is much quicker.
The following are figures of three lines by these two function.
Awesome! The general rule is to have as few high level plot objects as possible, so that the gpu receives only a couple of large arrays. Then it will be fast. 100000 line plot objects have too much overhead
No, it’s the single call to plot that makes it quicker. As others have also said, you just need to concatenate your roads in a single array and separate the segments that need separation by NaNs and it should be fast with Plots. (I did not do the part adding the NaNs in my example.)
[EDIT] For example, to sort-of match the GLMakie one,
xs = [0.1f0 * randn() .+ x for x in 1:300 for y in 1:300 for i in 1:10]
ys = [0.1f0 * randn() .+ y for x in 1:300 for y in 1:300 for i in 1:10]
roads = [i % 10 == 0 for x in 1:300 for y in 1:300 for i in 1:10]
isnotroad = [i % 10 == 0 for x in 1:300 for y in 1:300 for i in 1:10]
xs[isnotroad] .= NaN
ys[isnotroad] .= NaN
@btime plot($xs, $ys) # 23.933 ms for me
For the record, the inspectdr() backend seems to plot at same speed as gr() in this case, while allowing interactive zooming in and out. However it is 30% slower here than Makie. Makie zoom is nicer as scales are updated, while inspectdr() provides the coordinates of the cursor.
using Plots; inspectdr(legend=false)
xs = [i % 10 == 0 ? NaN : 0.1f0 * randn() .+ x for x in 1:300 for y in 1:300 for i in 1:10]
ys = [i % 10 == 0 ? NaN : 0.1f0 * randn() .+ y for x in 1:300 for y in 1:300 for i in 1:10]
@btime Plots.plot($xs, $ys) # 18 ms (2436 allocations: 13.88 MiB)
# draw rectangle with RMB to zoom-in, CTRL+f to unzoom