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

Support Base.filter on FeatureCollection #87

Closed
jfb-h opened this issue Apr 6, 2024 · 9 comments
Closed

Support Base.filter on FeatureCollection #87

jfb-h opened this issue Apr 6, 2024 · 9 comments

Comments

@jfb-h
Copy link

jfb-h commented Apr 6, 2024

It would be convenient if you could do something like filter(f -> f.NAME == "France", collection), but currently filtering is not supported.

Right now, I'm naivley pirating this like so:

function Base.filter(f::Function, fc::GeoJSON.FeatureCollection)
    features = [feat for feat in fc if f(feat)]
    GeoJSON.FeatureCollection(; bbox=nothing, features, crs=getfield(fc, :crs))
end

But I'm sure there is potential for improvement.

@rafaqz
Copy link
Member

rafaqz commented Apr 6, 2024

Is there a reason not to convert to a DataFrames.jl DataFrame and filter that?

@rafaqz rafaqz closed this as completed Apr 6, 2024
@rafaqz rafaqz reopened this Apr 6, 2024
@jfb-h
Copy link
Author

jfb-h commented Apr 6, 2024

Well my use case was GeoMakie, which works directly on FeatureCollections.

@asinghvi17
Copy link
Member

You can pass the geometry column of a dataframe to GeoMakie and it should just work.

@jfb-h
Copy link
Author

jfb-h commented Apr 6, 2024

It doesn't, though. Here's a reproducer:

using CairoMakie, GeoMakie, GeoMakie.GeoJSON
using DataFrames, HTTP

url = "https://raw.githubusercontent.com/" *
      "nvkelso/natural-earth-vector/master/geojson/" *
      "ne_10m_admin_0_countries.geojson"

df = GeoJSON.read(HTTP.get(url).body) |> DataFrame

let fig = Figure()
    ax = GeoAxis(fig[1, 1])
    poly!(ax, df.geometry)
    fig
end

this throws a conversion error:

ERROR: `Makie.convert_arguments` for the plot type Scatter and its conversion trait PointBased() was unsuccessful.

The signature that could not be converted was:
::Vector{Any}
[...]

I suspect it has to do with the geometry column having both polygon and multipolygon entries:

julia> df.geometry
258-element Vector{Union{GeoJSON.MultiPolygon{2, Float32}, GeoJSON.Polygon{2, Float32}}}:
 2D MultiPolygonwith 264 sub-geometries
 2D MultiPolygonwith 17 sub-geometries
 2D MultiPolygonwith 163 sub-geometries
 2D Polygonwith 1 sub-geometries
[...]

(there seems to be a space missing in the show method for polygons, btw.)

So I guess it might just be an XY problem, but maybe having filter(f, ::FeatureCollection) would still make sense?

@asinghvi17
Copy link
Member

ah yeah, somehow the type doesn't union to GeoJSON.AbstractGeometry, which is a bummer.

In this case you can do something like this:
https://github.com/MakieOrg/GeoMakie.jl/blob/3ba224449aea3c78d81931b5a9a177be360d1ec6/src/conversions.jl#L16

basically forcibly convert all of your geometries to multipolygons, so that the array has the correct type.

@rafaqz
Copy link
Member

rafaqz commented Apr 6, 2024

As an aside GeoMakie.jl could accept any Tables.jl compatible table and get the GeoInterface.geometrycolumns column too remove one step.

But yeah that dispatch on mixed geometry vectors is annoying in a lot of places.

@asinghvi17 would wrapping a mixed column as a GeometryCollection be another hack to make that work?

@asinghvi17
Copy link
Member

I'm not sure that GeoMakie would accept a geometrycollection, given that it has to go to multiple plot types. Perhaps after Makie v0.21 once we figure out this specapi thing...

We could special case it for the poly recipe so it only plots the polygon components of the geometrycollection though, that would probably work.

@rafaqz
Copy link
Member

rafaqz commented Apr 7, 2024

Anyway, I will close this. Operations like filter should just use a dataframe, we cant implement everything everywhere.

@asinghvi17
Copy link
Member

asinghvi17 commented Aug 18, 2024

If you want to use filter on a GeoJSON feature collection, you can use TableOperations.jl, which is implementation-agnostic - though it will probably be slower than DataFrames!

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