From d85bc7ec28e21742c3dc73f46d7bac4ff41b550e Mon Sep 17 00:00:00 2001 From: "C. Brenhin Keller" Date: Wed, 25 Dec 2024 21:27:59 -0500 Subject: [PATCH] Add image_from_paths/image_from_paths! --- src/Images.jl | 62 ++++++++++++++++++++++++++++++++++++++++++++++ test/testImages.jl | 13 ++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/Images.jl b/src/Images.jl index c14a849..04b847f 100644 --- a/src/Images.jl +++ b/src/Images.jl @@ -1,3 +1,65 @@ +## --- Calculate a 2d path density image from x-y path distributions + + """ + ```julia + image_from_paths(xpoints::AbstractMatrix, ypoints::AbstractMatrix; + xresolution::Int=1800, + yresolution::Int=1200, + xrange=nanextrema(xpoints), + yrange=nanextrema(ypoints), + ) + ``` + Produce a 2d image (histogram) of path densities given a set of x and y paths + stored column-wise in separate matrices `xpoints` and `ypoints`. + + ### Examples + ```julia + julia> nsims = 1000 + 1000 + + julia> xdist = rand(10, nsims); + + julia> ydist = rand(10, nsims); + + julia> imgcounts, xbincenters, ybincenters = image_from_paths(xpaths, ypaths; xresolution=50, yresolution=50) + ([8 15 … 9 11; 12 4 … 14 11; … ; 9 15 … 9 9; 10 17 … 10 14], -3.715247394908744:0.1523101612461508:3.747950506152645, -3.86556932981587:0.1497772964483582:3.4735181961536803) + ``` + """ + image_from_paths(xpoints, ypoints; xresolution::Int=1800, yresolution::Int=1200, xrange=nanextrema(xpoints), yrange=nanextrema(ypoints)) = image_from_paths!(copy(xpoints), copy(ypoints); xresolution, yresolution, xrange, yrange) + export image_from_paths + + function image_from_paths!(xpoints::AbstractMatrix, ypoints::AbstractMatrix; xresolution::Int=1800, yresolution::Int=1200, xrange=nanextrema(xpoints), yrange=nanextrema(ypoints)) + @assert axes(xpoints, 1) == axes(ypoints, 1) + nsims = size(xpoints, 2) + @assert axes(xpoints, 2) == axes(ypoints, 2) == Base.OneTo(nsims) + + # Interpolate paths to match image resolution + xbinedges = range(first(xrange), last(xrange), length=xresolution+1) + xq = cntr(xbinedges) + ybinedges = range(first(yrange), last(yrange), length=yresolution+1) + yq = cntr(ybinedges) + xinterpdist = Array{Float64}(undef, xresolution, nsims) + for i in Base.OneTo(nsims) + linterp1s!(view(xinterpdist,:,i), view(xpoints, :, i), view(ypoints, :, i), xq) + end + yinterpdist = Array{Float64}(undef, yresolution, nsims) + for i in Base.OneTo(nsims) + linterp1s!(view(yinterpdist,:,i), view(xpoints, :, i), view(ypoints, :, i), yq) + end + + # Calculate composite image, scanning both by x and y + imgcounts = zeros(Int, yresolution, xresolution) + for i in Base.OneTo(xresolution) # scan by x (one column at a time) + histcounts!(view(imgcounts,:,i), view(xinterpdist,i,:), ybinedges) + end + for j in Base.OneTo(yresolution) # scan by y (one row at a time) + histcounts!(view(imgcounts,j,:), view(yinterpdist,j,:), xbinedges) + end + + return imgcounts, xq, yq + end + export image_from_paths! + ## --- Map colormaps to images """ diff --git a/test/testImages.jl b/test/testImages.jl index f1b3384..5fc7393 100644 --- a/test/testImages.jl +++ b/test/testImages.jl @@ -1,5 +1,18 @@ ## --- Images.jl + using Random + rng = Xoshiro(1234) + + nsims = 1000 + xpaths = rand(rng, 10, nsims) + ypaths = rand(rng, 10, nsims) + imgcounts, xq, yq = image_from_paths(xpaths, ypaths; xresolution=50, yresolution=50, xrange=(0,1), yrange=(0,1)) + + @test sum(imgcounts, dims=1) == [715 999 1107 1268 1424 1502 1624 1636 1810 1837 1858 1925 1970 2041 2112 2059 2114 2139 2175 2175 2193 2200 2237 2265 2217 2169 2242 2303 2257 2225 2236 2187 2127 2130 2121 2060 2023 2015 1948 1870 1858 1755 1731 1643 1476 1410 1250 1103 916 713] + @test sum(imgcounts, dims=2) == [715; 999; 1107; 1268; 1424; 1502; 1624; 1636; 1810; 1837; 1858; 1925; 1970; 2041; 2112; 2059; 2114; 2139; 2175; 2175; 2193; 2200; 2237; 2265; 2217; 2169; 2242; 2303; 2257; 2225; 2236; 2187; 2127; 2130; 2121; 2060; 2023; 2015; 1948; 1870; 1858; 1755; 1731; 1643; 1476; 1410; 1250; 1103; 916; 713;;] + @test xq == 0.01:0.02:0.99 + @test yq == 0.01:0.02:0.99 + using Colors: Color cmap = resize_colormap(viridis, 10)