Skip to content

Commit

Permalink
Merge branch 'main' into no_nan_extents
Browse files Browse the repository at this point in the history
  • Loading branch information
asinghvi17 authored Jan 22, 2025
2 parents 8722337 + f06ec24 commit 2821953
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 49 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v4
- uses: codecov/codecov-action@v5
with:
files: lcov.info
env:
Expand All @@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: "1"
version: "1.10"
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-docdeploy@v1
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/CIGeoInterfaceMakie.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
if: ${{ env.TESTS_SUCCESSFUL != 'true' }}
run: exit 1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v4
- uses: codecov/codecov-action@v5
with:
file: lcov.info
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/recipes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
if: ${{ env.TESTS_SUCCESSFUL != 'true' }}
run: exit 1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v4
- uses: codecov/codecov-action@v5
with:
file: lcov.info
env:
Expand Down
8 changes: 4 additions & 4 deletions GeoInterfaceMakie/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "GeoInterfaceMakie"
uuid = "0edc0954-3250-4c18-859d-ec71c1660c08"
authors = ["JuliaGeo and contributors"]
version = "0.1.8"
version = "0.1.9"

[deps]
GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
Expand All @@ -10,13 +10,13 @@ MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b"

[compat]
GeoInterface = "1"
GeometryBasics = "0.4.4"
MakieCore = "0.5.1, 0.6, 0.7.1, 0.8"
GeometryBasics = "0.4.4, 0.5"
MakieCore = "0.5.1, 0.6, 0.7.1, 0.8, 0.9"
julia = "1.6"

[extras]
LibGEOS = "a90b1aa1-3769-5649-ba7e-abc5a9d163eb"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
LibGEOS = "a90b1aa1-3769-5649-ba7e-abc5a9d163eb"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

Expand Down
20 changes: 13 additions & 7 deletions GeoInterfaceMakie/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,24 @@ end
]
fig = Figure()
for (i, geom) in enumerate(geoms)
Makie.plot!(Axis(fig[i, 1], title="$(GI.geomtrait(geom))"), geom)
if geom == multipoint
# `plot!` wont even work with the GeometryBasics version of this
continue
elseif geom == multipolygon
# Even the GeometryBasics version of this will fail
# though the conversion succeeds, so we skip this
geom == multipoint && continue
# Construct a plot inside an axis
Makie.plot(fig[i, 1], geom; axis = (; type = Axis, title = "$(GI.geomtrait(geom))"))

if geom == multipolygon
# `plot!` wont work with the GeometryBasics version of this either
# But `poly!` does
@test_nowarn Makie.poly!(Axis(fig[i, 2], title="Vector of $(GI.geomtrait(geom))"), [geom, geom])
@test_nowarn Makie.poly(fig[i, 2], [geom, geom]; axis = (; type = Axis, title = "Vector of $(GI.geomtrait(geom))"))
else
@test_nowarn Makie.plot!(Axis(fig[i, 2], title="Vector of $(GI.geomtrait(geom))"), [geom, geom])
@test_nowarn Makie.plot(fig[i, 2], [geom, geom]; axis = (; type = Axis, title = "Vector of $(GI.geomtrait(geom))"))
end
end

@test_nowarn Makie.update_state_before_display!(fig)
@test_nowarn Makie.colorbuffer(fig.scene)

fig
end

Expand Down
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
name = "GeoInterface"
uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
authors = ["JuliaGeo and contributors"]
version = "1.3.7"
version = "1.4.1"

[deps]
DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
Extents = "411431e0-e8b7-467b-b5e0-f676ba4f2910"
GeoFormatTypes = "68eda718-8dee-11e9-39e7-89f7f65f511f"

[compat]
DataAPI = "1"
Extents = "0.1.1"
GeoFormatTypes = "0.4"
julia = "1"
Expand Down
22 changes: 22 additions & 0 deletions docs/src/guides/developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ it could be useful to also implement some optional methods if they apply or are
If your package also supports geospatial operations on geometries--such as intersections--, please
also implement those interfaces where applicable.

GeoInterface also has some utility packages, `GeoInterfaceMakie` and `GeoInterfaceRecipes`,
which provide plotting support through their `@enable` macros.
If you wish to implement plotting support for your geometry, please create a [package extension](https://pkgdocs.julialang.org/v1/creating-packages/#Conditional-loading-of-code-in-packages-(Extensions))
that extends either `Makie` (for the Makie.jl ecosystem) or `RecipesBase` (for the Plots.jl ecosystem).
You can find some examples of this pattern in [Shapefile.jl](https://github.com/JuliaGeo/Shapefile.jl/blob/main/ext/ShapefileMakieExt.jl) and [GeoJSON.jl](https://github.com/JuliaGeo/GeoJSON.jl/blob/main/ext/GeoJSONMakieExt.jl).

Last but not least, we also provide an interface for rasters and features--geometries with properties--if applicable.

## Required for Geometry
Expand Down Expand Up @@ -86,6 +92,22 @@ GeoInterface.geometrycolumns(::customcollection) = (:geometry,) # can be multip

The `geometrycolumns` enables other packages to know which field in a row, or column in a table, contains the geometry or geometries.

It's important to note that the `geometrycolumns` should always return a `Tuple` of `Symbol`s. However, it does have a fallback method
that uses [DataAPI.jl](https://github.com/JuliaData/DataAPI.jl) metadata, if it exists, to retrieve the geometry columns. This relies on
the `"GEOINTERFACE:geometrycolumns"` metadata key. GeoInterface.jl compatible writers may set this metadata key if writing to a format
that does not have its own mechanism to store known geometry columns, like Arrow.

Optionally, the `crs` method can also be implemented:
```julia
GeoInterface.crs(::customcollection)
```

This should return a `GeoFormatTypes.CoordinateReferenceSystem` type, such as `EPSG(code::Int)`, `WellKnownText(GeoFormatTypes.CRS(), wkt::String)`,
or `ProjString(p4::String)`. See [GeoFormatTypes.jl](https://github.com/JuliaGeo/GeoFormatTypes.jl) for more information.

The `crs` method also has a fallback that uses [DataAPI.jl](https://github.com/JuliaData/DataAPI.jl) metadata, if it exists, to retrieve the CRS.
GeoInterface searches for the `"GEOINTERFACE:crs"` metadata key to retrieve the CRS.

## Geospatial Operations
```julia
distance(geomtrait(a), geomtrait(b), a, b)
Expand Down
2 changes: 2 additions & 0 deletions src/GeoInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module GeoInterface
using Extents: Extents, Extent
using GeoFormatTypes: CoordinateReferenceSystemFormat
using Base.Iterators: flatten
import DataAPI

export testgeometry, isgeometry, trait, geomtrait, ncoord, getcoord, ngeom, getgeom

Expand Down Expand Up @@ -55,6 +56,7 @@ include("fallbacks.jl")
include("utils.jl")
include("base.jl")
include("wrappers.jl")
include("metadata.jl")

using .Wrappers
using .Wrappers: geointerface_geomtype
Expand Down
7 changes: 5 additions & 2 deletions src/fallbacks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,11 @@ issimple(t::AbstractMultiPointTrait, geom) = allunique((getgeom(t, geom)))
issimple(t::AbstractMultiCurveTrait, geom) = all(issimple.(getgeom(t, geom)))
isclosed(t::AbstractMultiCurveTrait, geom) = all(isclosed.(getgeom(t, geom)))

crs(::Nothing, geom) = nothing
crs(::AbstractTrait, geom) = nothing
"The key used to retrieve and store the CRS from DataAPI.jl metadata, if no other solution exists in that format."
const GEOINTERFACE_CRS_KEY = "GEOINTERFACE:crs"

crs(::Nothing, geom) = _get_dataapi_metadata(geom, GEOINTERFACE_CRS_KEY, nothing) # see `metadata.jl`
crs(::AbstractTrait, geom) = _get_dataapi_metadata(geom, GEOINTERFACE_CRS_KEY, nothing) # see `metadata.jl`

# FeatureCollection
getfeature(t::AbstractFeatureCollectionTrait, fc) = (getfeature(t, fc, i) for i in 1:nfeature(t, fc))
Expand Down
17 changes: 16 additions & 1 deletion src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,28 @@ automatically delegate to this method.
isfeaturecollection(x::T) where {T} = isfeaturecollection(T)
isfeaturecollection(::Type{T}) where {T} = false

"""
The key used to retrieve and store the geometrycolumns from DataAPI.jl metadata, if no other solution exists in that format.
"""
const GEOINTERFACE_GEOMETRYCOLUMNS_KEY = "GEOINTERFACE:geometrycolumns"

"""
GeoInterface.geometrycolumns(featurecollection) => (:geometry,)
Retrieve the geometrycolumn(s) of `featurecollection`; the fields (or columns in a table)
which contain geometries that support GeoInterface.
This is always a `Tuple` of `Symbol`s.
"""
geometrycolumns(featurecollection) = (:geometry,)
function geometrycolumns(featurecollection)
gcs = _get_dataapi_metadata(featurecollection, GEOINTERFACE_GEOMETRYCOLUMNS_KEY, (:geometry,)) # see `metadata.jl`
return _aftercare_geometrycolumns(gcs)
end

_aftercare_geometrycolumns(gcs::Tuple{Vararg{Symbol}}) = gcs
_aftercare_geometrycolumns(gcs::Tuple{Vararg{String}}) = Symbol.(gcs)
_aftercare_geometrycolumns(gcs::String) = (Symbol(gcs),)
_aftercare_geometrycolumns(gcs::Symbol) = (gcs,)

"""
GeoInterface.geometry(feat) => geom
Expand Down
23 changes: 23 additions & 0 deletions src/metadata.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This file contains internal helper functions to get metadata from DataAPI objects.
# At some point, it may also contain methods to set metadata.

"""
Internal function.
## Extended help
_get_dataapi_metadata(geom, key, default)
Get metadata associated with key `key` from some object, `geom`, that has DataAPI.jl metadata support.
If the object does not have metadata support, or the key does not exist, return `default`.
"""
function _get_dataapi_metadata(geom::GeomType, key, default) where GeomType
if DataAPI.metadatasupport(GeomType).read # check that the type has metadata, and supports reading it
if key in DataAPI.metadatakeys(geom) # check that the key exists
return DataAPI.metadata(geom, key; style = false) # read the metadata
end
end
return default
end

9 changes: 8 additions & 1 deletion src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,25 @@ Test whether the required interface for your `geom` has been implemented correct
"""
function testgeometry(geom)
@assert isgeometry(geom) "$geom doesn't implement `isgeometry`."
@assert isgeometry(typeof(geom)) "Type{$(typeof(geom))} doesn't implement `isgeometry`."
type = geomtrait(geom)
@assert !isnothing(type) "$geom doesn't implement `geomtrait`."

@assert hasmethod(ncoord, (typeof(type), typeof(geom))) "$geom does not correctly implement two argument `ncoord`"

if type == PointTrait()
n = ncoord(geom)
@assert n == ncoord(type, geom) "$geom does not correctly implement three argument `getcoord`"
if n >= 1 # point could be empty
getcoord(geom, 1) # point always needs at least 2
c = getcoord(geom, 1) # point always needs at least 2
@assert c == getcoord(type, geom, 1) "$geom does not correctly implement three argument `getcoord`"
end
else
n = ngeom(geom)
@assert n == ngeom(type, geom) "$geom does not correctly implement two argument `ngeom`"
if n >= 1 # geometry could be empty
g2 = getgeom(geom, 1)
@assert g2 == getgeom(type, geom, 1) "$geom does not correctly implement three argument `getgeom`"
subtype = subtrait(type)
if !isnothing(subtype)
issub = geomtrait(g2) isa subtype
Expand Down
Loading

0 comments on commit 2821953

Please sign in to comment.