Skip to content

Commit 6e07cf0

Browse files
felixcremerFelix Cremerasinghvi17
authored
Fix building pyramids and add cat method (#75)
* Fix building pyramids * Convert missing to nan before plotting Co-authored-by: Anshul Singhvi <[email protected]> * Update dependencies * Add cat for Pyramids This also improves the computation of the aggregated dimensions for points Co-authored-by: Anshul Singhvi <[email protected]> --------- Co-authored-by: Felix Cremer <[email protected]> Co-authored-by: Anshul Singhvi <[email protected]>
1 parent aa6bff7 commit 6e07cf0

File tree

4 files changed

+62
-21
lines changed

4 files changed

+62
-21
lines changed

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,22 @@ ArchGDAL = "0.10.4"
3535
CairoMakie = "0.12"
3636
Colors = "0.12"
3737
DimensionalData = "0.28, 0.29"
38-
DiskArrayEngine = "0.1.2"
38+
DiskArrayEngine = "0.1.2, 0.2"
3939
DiskArrayTools = "0.1.10"
4040
DiskArrays = "0.4.2"
4141
Extents = "0.1.3"
4242
FillArrays = "1.11"
4343
Flatten = "0.4.3"
4444
GeoInterface = "1.3.4"
45-
Makie = "0.21.2"
45+
Makie = "0.21.2, 0.22, 0.23, 0.24"
4646
OffsetArrays = "1.14"
4747
Proj = "1.7.1"
4848
Rasters = "0.11.8, 0.12, 0.13"
4949
Statistics = "1.10"
5050
Test = "1.10"
5151
TestItemRunner = "0.2.3"
5252
YAXArrayBase = "0.6.1, 0.7"
53-
YAXArrays = "0.5.6"
53+
YAXArrays = "0.5.6, 0.6"
5454
Zarr = "0.9.3"
5555
julia = "1.9"
5656

ext/PyramidSchemeMakieExt.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ using PyramidScheme: Pyramid, switchkeys, levels, selectlevel, xkey, ykey
66
using DimensionalData: DimensionalData as DD
77
using DimensionalData.Dimensions: XDim, YDim
88
using Extents: Extent, extent, intersects
9+
miss2nan(x) = ismissing(x) ? NaN : x
910
"""
1011
plot(pyramids)
1112
Plot a Pyramid.
1213
This will plot the coarsest resolution level at the beginning and will plot higher resolutions after zooming into the plot.
1314
This is expected to be used with interactive Makie backends.
1415
"""
15-
function plot(pyramid::Pyramid;colorbar=true, kwargs...)
16+
function plot(pyramid::Pyramid;colorbar=true, size=(1155, 1043), kwargs...)
1617
#This should be converted into a proper recipe for Makie but this would depend on a pyramid type.
17-
fig = Figure()
18+
fig = Figure(;size)
1819
lon, lat = DD.dims(DD.parent(pyramid))
1920
ax = Axis(fig[1,1], limits=(extrema(lon), extrema(lat)), aspect=DataAspect())
2021
hmap = plot!(ax, pyramid;kwargs...)
@@ -28,19 +29,17 @@ end
2829
function plot!(ax, pyramid::Pyramid;interp=false, kwargs...)#; rastercrs=crs(parent(pyramid)),plotcrs=EPSG(3857), kwargs...)
2930
tip = levels(pyramid)[end-2][:,:]
3031
#@show typeof(tip)
32+
subtypes = Union{typeof.(pyramid.levels)..., typeof(parent(pyramid))}
3133
data = Observable{DD.AbstractDimMatrix}(tip)
3234
xval = only(values(extent(pyramid, XDim)))
3335
yval = only(values(extent(pyramid, YDim)))
3436
rasdataext = Extent(X=xval, Y=yval)
3537
rasext = extent(pyramid)
36-
xk = xkey(rasext)
37-
yk = ykey(rasext)
3838
on(ax.scene.viewport) do viewport
3939
limext = extent(ax.finallimits[])
4040

4141
datalimit = switchkeys(limext, rasext)
42-
43-
data.val = selectlevel(pyramid, datalimit, target_imsize=viewport.widths)
42+
data.val = miss2nan.(selectlevel(pyramid, datalimit, target_imsize=viewport.widths))
4443
notify(data)
4544
end
4645
on(ax.finallimits) do limits
@@ -53,7 +52,7 @@ function plot!(ax, pyramid::Pyramid;interp=false, kwargs...)#; rastercrs=crs(par
5352
rasdata = selectlevel(pyramid, datalimit, target_imsize=ax.scene.viewport[].widths)
5453
# Project selected data to plotcrs
5554
#data.val = Rasters.resample(rasdata, crs=plotcrs, method=:bilinear )
56-
data.val = rasdata
55+
data.val = miss2nan.(rasdata)
5756
end
5857
notify(data)
5958
end

src/PyramidScheme.jl

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ using YAXArrays: Cube, YAXArray, to_dataset, savedataset, setchunks, open_datase
1616
using Zarr: Zarr, zcreate, zopen, writeattrs
1717
using DimensionalData: DimensionalData as DD
1818
using DimensionalData.Dimensions: XDim, YDim
19-
using Extents: Extent, extent
19+
using Extents: Extent, extent, intersects
2020
using FillArrays: Zeros
2121
using Proj
2222
using OffsetArrays
@@ -39,7 +39,7 @@ struct Pyramid{T,N,D,A,B<:DD.AbstractDimArray{T,N,D,A},L, Me} <: DD.AbstractDimA
3939
metadata::Me
4040
end
4141

42-
function Pyramid(data::DD.AbstractDimArray; resampling_method=mean skipmissing, kwargs...)
42+
function Pyramid(data::DD.AbstractDimArray; resampling_method= mean skipmissing, kwargs...)
4343
pyrdata, pyraxs = getpyramids(resampling_method, data; kwargs...)
4444
levels = DD.DimArray.(pyrdata, pyraxs)
4545
meta = Dict(deepcopy(DD.metadata(data)))
@@ -103,7 +103,7 @@ function DD.modify(f, pyr::Pyramid)
103103
Pyramid(pbase, plevels, pyr.metadata)
104104
end
105105
Base.read(pyr::Pyramid) = DD.modify(Array, pyr)
106-
@inline function DD.rebuild(A::Pyramid, data, dims::Tuple=dims(A), refdims=refdims(A), name=name(A))
106+
@inline function DD.rebuild(A::Pyramid, data, dims::Tuple=DD.dims(A), refdims=DD.refdims(A), name=DD.name(A))
107107
Pyramid(DD.rebuild(parent(A), data, dims, refdims, name, nothing), A.levels, A.metadata)
108108
end
109109

@@ -271,9 +271,20 @@ Compute the number of levels for the aggregation based on the size of `data`.
271271
compute_nlevels(data, tilesize=256) = max(0,ceil(Int,log2(maximum(size(data))/tilesize)))
272272

273273
function agg_axis(d,n)
274-
# TODO this might be problematic for explicitly set axes
275-
DD.set(d, LinRange(first(d), last(d), cld(length(d), n)))
274+
# TODO this might be problematic for Reversed axes
275+
# TODO this is only correct for points not intervals
276+
npoints = cld(length(d), n)
277+
half_stepsize = step(d) * (n-1) / 2
278+
@show half_stepsize
279+
sgn = DD.isreverse(d) ? -1 : 1
280+
DD.set(d, LinRange(first(d) + sgn * half_stepsize, last(d) - sgn * half_stepsize, npoints))
276281
end
282+
#=
283+
. .
284+
. <--- new point
285+
. .
286+
=#
287+
277288
"""
278289
gen_output(t,s)
279290
@@ -326,7 +337,11 @@ function buildpyramids(path::AbstractString; resampling_method=mean, recursive=t
326337
# Build a loop for all variables in a dataset?
327338
org = Cube(path)
328339
# We run the method once to derive the output type
329-
t = typeof(resampling_method(zeros(eltype(org), 2,2)))
340+
#tfunc = typeof(resampling_method(zeros(eltype(org), 2,2)))
341+
#t = Missing <: eltype(org) ? Union{Missing, tfunc} : tfunc
342+
343+
t = Base.infer_return_type(resampling_method, (Matrix{nonmissingtype(eltype(org))},))
344+
330345
n_level = compute_nlevels(org)
331346
input_axes = filter(x-> x isa SpatialDim, DD.dims(org))
332347
if length(input_axes) != 2
@@ -377,16 +392,17 @@ end
377392
Compute the data of the pyramids of a given data cube `ras`.
378393
This returns the data of the pyramids and the dimension values of the aggregated axes.
379394
"""
380-
function getpyramids(reducefunc, ras;recursive=true)
395+
function getpyramids(reducefunc, ras;recursive=true, tilesize=256)
381396
input_axes = DD.dims(ras)
382-
n_level = compute_nlevels(ras)
397+
n_level = compute_nlevels(ras, tilesize)
383398
if iszero(n_level)
384-
@info "Array is smaller than the tilesize no pyramids are computed"
385-
[ras], [dims(ras)]
399+
@info "Array is smaller than the tilesize no pyramidlevels are computed"
400+
[ras], [DD.dims(ras)]
386401
end
387402
pyramid_sizes = [ceil.(Int, size(ras) ./ 2^i) for i in 1:n_level]
388403
pyramid_axes = [agg_axis.(input_axes,2^i) for i in 1:n_level]
389-
outtype = typeof(reducefunc(rand(eltype(ras),2,2)))
404+
outtype = Base.infer_return_type(reducefunc, (Matrix{eltype(ras)},))
405+
#outtype = Missing <: eltype(ras) ? Union{Missing, outtypefunc} : outtypefunc
390406
outmin = output_arrays(pyramid_sizes, outtype)
391407
fill_pyramids(ras,outmin,reducefunc,recursive; threaded=true)
392408

@@ -402,6 +418,7 @@ Internal function to select the raster data that should be plotted on screen.
402418
"""
403419
function selectlevel(pyramid, ext;target_imsize=(1024, 512))
404420
pyrext = extent(pyramid)
421+
intersects(pyrext, ext) || return zero(pyramid.levels[end])
405422
basepixels = map(keys(pyrext)) do bb
406423
pyrspan = pyrext[bb][2] - pyrext[bb][1]
407424
imsize = ext[bb][2] - ext[bb][1]
@@ -473,5 +490,15 @@ function tms_json(pyramid)
473490
push!(tms, "orderedAxes" => pyramidaxes())
474491
return tms
475492
end
493+
function Base.cat(A1::Pyramid, As::Pyramid...;dims)
494+
println("Inside pyr cat")
495+
@show typeof(levels.(As, 1))
496+
catlevels = [cat(A1.levels[i], levels.(As, i)...; dims) for i in eachindex(A1.levels)]
497+
catbase = cat(parent(A1), parent.(As)...; dims)
498+
Pyramid(catbase, catlevels, merge(DD.metadata(A1), DD.metadata.(As)...))
499+
end
500+
501+
502+
476503
include("broadcast.jl")
477504
end

test/runtests.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,21 @@ end
122122
end
123123

124124

125+
@testitem "cat Pyramids" begin
126+
using PyramidScheme: PyramidScheme as PS
127+
using DimensionalData
128+
pyr1 = Pyramid(rand(X(1:128),Y(1:128)), tilesize=16)
129+
pyrcat = cat(pyr1, pyr1, dims=Dim{:new}([1,2]))
130+
pyrcat3 = cat(pyr1, pyr1, pyr1, dims=Dim{:new}([1,2,3]))
131+
pyr2 = Pyramid(rand(X(129:256), Y(1:128)), tilesize=16)
132+
pyrcat2 = cat(pyr1, pyr2, dims=X)
133+
for l in 1:3
134+
@test PS.levels(pyrcat,l) == cat(PS.levels(pyr1, l), PS.levels(pyr1, l), dims=Dim{:new}([1,2]))
135+
@test PS.levels(pyrcat3, l) == cat(PS.levels(pyr1, l), PS.levels(pyr1, l), PS.levels(pyr1, l), dims=Dim{:new}([1,2,3]))
136+
@test PS.levels(pyrcat2, l) == cat(PS.levels(pyr1, l), PS.levels(pyr2, l), dims=X)
137+
end
138+
end
139+
125140
#=
126141
@testitem "Comparing zarr pyramid with tif pyramid" begin
127142
using PyramidScheme: PyramidScheme as PS

0 commit comments

Comments
 (0)