Rasters.jl icon indicating copy to clipboard operation
Rasters.jl copied to clipboard

One can not rasterize non-numeric attributes into an array

Open alex-s-gardner opened this issue 1 year ago • 7 comments

using NaturalEarth, Rasters, GeometryOps
countries = naturalearth("admin_0_countries", 110);

dx = Dim{:X}(-180:180)
dy = Dim{:Y}(-90:90)

# you can not rasterize non-numeric attributes into an array 
ras = rasterize(first, countries; res=1.0, fill=:NAME, missingval="test", crs=EPSG(4326));

# but you can create raster of non-numerical values
ras = Raster(fill("test", (dx, dy)))

#but again you can not raterize on-numeric attributes, even if one initializes a non-numeric array
ras = rasterize!(first, ras, countries; fill=:NAME, missingval="test", crs=EPSG(4326));
ERROR: MethodError: no method matching zero(::Type{String})
The function `zero` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  zero(::Type{Union{}}, Any...)
   @ Base number.jl:310
  zero(::Type{Dates.DateTime})
   @ Dates ~/.julia/juliaup/julia-1.11.0-rc1+0.aarch64.apple.darwin14/share/julia/stdlib/v1.11/Dates/src/types.jl:458
  zero(::Type{Dates.Date})
   @ Dates ~/.julia/juliaup/julia-1.11.0-rc1+0.aarch64.apple.darwin14/share/julia/stdlib/v1.11/Dates/src/types.jl:459
  ...

Stacktrace:
 [1] _reduce_init(f::typeof(first), ::Type{String})
   @ Rasters ~/Documents/GitHub/Rasters.jl/src/methods/rasterize.jl:15
 [2] Rasters.Rasterizer(geom::Vector{…}, fill::Symbol, fillitr::Vector{…}; reducer::Function, op::Nothing, missingval::String, shape::Nothing, eltype::Nothing, init::Nothing, boundary::Symbol, filename::Nothing, verbose::Bool, progress::Bool, threaded::Bool, kw::@Kwargs{…})
   @ Rasters ~/Documents/GitHub/Rasters.jl/src/methods/rasterize.jl:133
 [3] Rasters.Rasterizer(data::GeoJSON.FeatureCollection{…}; fill::Symbol, geomcolumn::Nothing, kw::@Kwargs{…})
   @ Rasters ~/Documents/GitHub/Rasters.jl/src/methods/rasterize.jl:168
 [4] Rasterizer
   @ ~/Documents/GitHub/Rasters.jl/src/methods/rasterize.jl:145 [inlined]
 [5] rasterize(data::GeoJSON.FeatureCollection{…}; to::Nothing, fill::Symbol, threaded::Bool, kw::@Kwargs{…})
   @ Rasters ~/Documents/GitHub/Rasters.jl/src/methods/rasterize.jl:419
 [6] rasterize(reducer::Function, data::GeoJSON.FeatureCollection{…}; kw::@Kwargs{…})
   @ Rasters ~/Documents/GitHub/Rasters.jl/src/methods/rasterize.jl:396
 [7] top-level scope
   @ ~/Documents/GitHub/ItsLivePlayground.jl/src/issue_with_cellarea.jl:1
Some type information was truncated. Use `show(err)` to see complete types.

alex-s-gardner avatar Sep 20 '24 00:09 alex-s-gardner

Can you do that in other languages?

But I think there will be a way around it. I just assumed numbers.

rafaqz avatar Sep 20 '24 06:09 rafaqz

I highly doubt this can be done in any other language... but it would certainly be a nice to have

alex-s-gardner avatar Sep 20 '24 14:09 alex-s-gardner

I think you could hack around this using categorical arrays for now, you'd basically rasterize the category in as an integer, then rebuild the raster with rebuild(raster, data = CategoricalArray(parent(raster), data_lookup)). But it would be pretty annoying to write.

asinghvi17 avatar Oct 14 '24 17:10 asinghvi17

Actually it works if you define some methods. But there are quite a few method ambiguities. Maybe we should have a default fallback, just to make things work?

julia> Rasters._reduce_init(f::Function, ::Type{String}, missingval) = ""

julia> Rasters._reduce_init(f, ::Type{String}, missingval) = ""

julia> Rasters._reduce_init(f::Nothing, ::Type{String}, missingval) = ""

julia> ras = rasterize(first, countries; res=1.0, fill=:NAME, missingval="test", crs=EPSG(4326))
Burning each geometry to a BitArray slice... 100%|██████████████████████████████████████████████████| Time: 0:00:01
╭───────────────────────────────╮
│ 361×174 Raster{String,2} NAME │
├───────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── dims ┐
  ↓ X Projected{Float64} -180.0:1.0:180.0 ForwardOrdered Regular Intervals{Start},
  → Y Projected{Float64} -90.0:1.0:83.0 ForwardOrdered Regular Intervals{Start}
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── metadata ┤
  Metadata of Dict{Any, Any}()
├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── raster ┤
  extent: Extent(X = (-180.0, 181.0), Y = (-90.0, 84.0))
  missingval: "test"
  crs: EPSG:4326
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
    ↓ →  -90.0            -89.0            -88.0            -87.0            -86.0            -85.0            …  72.0      73.0      74.0      75.0      76.0      77.0      78.0      79.0      80.0      81.0      82.0      83.0
 -180.0     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"       "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"
 -179.0     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"       "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"
 -178.0     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"       "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"
    ⋮                                                                          ⋮                               ⋱                       ⋮                                                 ⋮
  177.0     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"       "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"
  178.0     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "test"             "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"
  179.0     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "Antarctica"     "test"        …    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"
  180.0     "test"           "test"           "test"           "test"           "test"           "test"             "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"    "test"

I would propose something on the lines of:

_reduce_init(f, x, missingval) = _placeholder_value(x)
_placeholder_value(x) = zero(x)
_placeholder_value(x::String) = ""
# ...

then users can define _placeholder_value and this just works.

If, without defining those methods, you define init in rasterize, it errors out in _get_eltype_missingval. So we could replace all references to zero with references to _placeholder_value.

asinghvi17 avatar Oct 14 '24 17:10 asinghvi17

Rasterizing the continent names 😂

Maybe we can call it _zeroval and allow it as a zeroval keyword later on.

But we'll have to remember what it's zeroness is actually used for to get the name right, I don't! Something somewhere in how the reductions work. But I also think in many cases it's not even used

rafaqz avatar Oct 14 '24 18:10 rafaqz

I think this could just be the init value in most cases?

asinghvi17 avatar Oct 14 '24 22:10 asinghvi17

Yeah need to look at the alg some time. Sometimes there is a reason it's different and after three rewrites there isn't anymore but the code is still there

rafaqz avatar Oct 15 '24 00:10 rafaqz

I am not sure what fixed this, but this is working now on the main of 0.14.7

felixcremer avatar Nov 14 '25 10:11 felixcremer

Probably https://github.com/rafaqz/Rasters.jl/pull/1033 fixed it?

tiemvanderdeure avatar Nov 14 '25 10:11 tiemvanderdeure

Oh wow I forgot I ran into this twice 🤣

asinghvi17 avatar Nov 14 '25 12:11 asinghvi17