Plots.spy seems to not allocate, although its a bit difficult to confirm because @edit spy(x) does not really lead to anywhere useful.
julia> using BenchmarkTools, Plots, SparseArrays
julia> x = sprand(Float64, 500, 500, 0.01)
julia> @benchmark Plots.spy(x)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
Range (min … max): 164.625 μs … 23.158 ms ┊ GC (min … max): 0.00% … 97.84%
Time (median): 199.167 μs ┊ GC (median): 0.00%
Time (mean ± σ): 231.186 μs ± 569.189 μs ┊ GC (mean ± σ): 12.81% ± 5.26%
▁▃▃▅▄▅▆▇██▇▇█▆▄▅▄▃▂▁▁
▂▂▂▁▂▃▄▅▆▅██████████████████████▇▇▆▅▅▅▄▅▃▃▃▃▃▃▃▃▂▂▃▂▂▂▂▂▂▂▂▂▂ ▅
165 μs Histogram: frequency by time 260 μs <
Memory estimate: 296.45 KiB, allocs estimate: 1286.
julia> x_alloc = Matrix(x)
julia> julia> @benchmark Plots.spy(x_alloc)
BenchmarkTools.Trial: 7196 samples with 1 evaluation per sample.
Range (min … max): 300.791 μs … 51.989 ms ┊ GC (min … max): 0.00% … 98.56%
Time (median): 465.625 μs ┊ GC (median): 0.00%
Time (mean ± σ): 693.803 μs ± 1.509 ms ┊ GC (mean ± σ): 31.62% ± 16.23%
▃█▃ ▁
███▆▁▃▁▃▁▄▃▁▄▄▃▁▄▃▁▁▁▁▁▁▁▁▁▁▃▄▆▆▅▃▄▆▄▅▅▅▅▅▆▆▆▅▅▆▅▆▅▄▄▅▄▅▄▅▅▅ █
301 μs Histogram: log(frequency) by time 7.06 ms <
Memory estimate: 2.28 MiB, allocs estimate: 1284.
The output of spy is a bit different than that of heatmap, but when fiddling with the markersize and permuting the matrix you could probably approximate it.
Yes, probably. For the moment I added a safeguard to just avoid plotting. But I think that “heatmap” using a memory proportional to the size of the dense matrix is an implementation detail. For instance, a scatter plot can easily look pretty much the same and use only the actual values for plotting.