Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

One can not rasterize non-numeric attributes into an array #752

Open
alex-s-gardner opened this issue Sep 20, 2024 · 7 comments
Open

One can not rasterize non-numeric attributes into an array #752

alex-s-gardner opened this issue Sep 20, 2024 · 7 comments

Comments

@alex-s-gardner
Copy link
Contributor

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.
@rafaqz
Copy link
Owner

rafaqz commented Sep 20, 2024

Can you do that in other languages?

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

@alex-s-gardner
Copy link
Contributor Author

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

@asinghvi17
Copy link
Collaborator

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
Copy link
Collaborator

asinghvi17 commented Oct 14, 2024

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.

@rafaqz
Copy link
Owner

rafaqz commented Oct 14, 2024

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

@asinghvi17
Copy link
Collaborator

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

@rafaqz
Copy link
Owner

rafaqz commented Oct 15, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants