Getting Started

Load SimpleFeatures.jl

We'll load the package in these examples as SF, shorthand for SimpleFeatures

import SimpleFeatures as SF

Read & write data

Most GIS types can be read and written using the functions st_read and st_write, respectively. Parquet files can be read/written using the functions st_read_parquet and st_write_parquet.

x = SF.st_read("data/test.gpkg")

SimpleFeature
---------
geomtype:  wkbPolygon
crs:       PROJCRS["NAD83(2011) / UTM zone 17N",BASEGEOGCRS["NAD83(2011)",DATUM["NAD83 (National Spatial Refere..."
---------
features:  
1000×2 DataFrame
  Row │ geom                          lyr.1 
      │ sfgeom                        Int32 
──────┼─────────────────────────────────────
    1 │ POLYGON ((853787 3905499,...      1
    2 │ POLYGON ((853800 3905499,...      1
    3 │ POLYGON ((853803 3905499,...      1
  ⋮   │              ⋮                  ⋮
  998 │ POLYGON ((904045 3905468,...      1
  999 │ POLYGON ((905355 3905468,...      1
 1000 │ POLYGON ((905561 3905469,...      1
                            994 rows omitted
SF.st_write("data/new_test.gpkg", x)

"data/new_test.gpkg"

DataFrame operations

Many common DataFrames operations work with SimpleFeature objects. If the operation you want (e.g., Grouped DataFrames operations) isn't offered yet, you can access and manipulate the DataFrame of the SimpleFeature object directly by appending .df to your object.

Supported operations:

  • Indexing
  • select(!)
  • transform(!)
  • rename(!)
  • subset(!)
  • nrow, ncol
  • combine
  • first, last
  • eachrow (but you can just iterate on a SimpleFeature object b/c we internally convert DataFrameRows to DataFrames.)

Check out DataFramesMeta.jl for some nice macros for many of these functions - they should work directly on SimpleFeature objects!

Spatial operations

SimpleFeatures offers some basic spatial functions and will offer more in future releases.

Check out Reference for a full list of functions available functions. Below are a few examples.

Cast polygons to linestrings

In this example, SimpleFeatures will cast each polygon to a multilinestring and then to a linestrings. Some polygons had holes (multiple lines per polygon), so the resulting DataFrame has more rows than the original. In cases such as this, SimpleFeatures adds a column of the geometry type + "ID" (e.g. _MultiLineStringID) that preserves which multigeometry type the split geometry belonged to.

lines = SF.st_cast(df, "linestring")

SimpleFeature
---------
geomtype:  wkbLineString
crs:       PROJCRS["NAD83(2011) / UTM zone 17N",BASEGEOGCRS["NAD83(2011)",DATUM["NAD83 (National Spatial Refere..."
---------
features:  
1022×3 DataFrame
  Row │ lyr.1  _MultiLineStringID  geom                         
      │ Int32  Int64               sfgeom                       
──────┼─────────────────────────────────────────────────────────
    1 │     1                   1  LINESTRING (853787 390549...
    2 │     1                   2  LINESTRING (853800 390549...
    3 │     1                   3  LINESTRING (853803 390549...
  ⋮   │   ⋮            ⋮                        ⋮
 1020 │     1                 998  LINESTRING (904045 390546...
 1021 │     1                 999  LINESTRING (905355 390546...
 1022 │     1                1000  LINESTRING (905561 390546...
                                               1016 rows omitted

Buffer

Using the linestrings from the st_cast example above, we will add a 10m buffer.

buffered_lines = SF.st_buffer(lines, 10) # buffer distance is in units of the crs. Meters in this example

SimpleFeature
---------
geomtype:  wkbPolygon
crs:       PROJCRS["NAD83(2011) / UTM zone 17N",BASEGEOGCRS["NAD83(2011)",DATUM["NAD83 (National Spatial Refere..."
---------
features:  
1022×3 DataFrame
  Row │ lyr.1  _MultiLineStringID  geom                         
      │ Int32  Int64               sfgeom                       
──────┼─────────────────────────────────────────────────────────
    1 │     1                   1  POLYGON ((853787 3905509,...
    2 │     1                   2  POLYGON ((853800 3905509,...
    3 │     1                   3  POLYGON ((853803 3905509,...
  ⋮   │   ⋮            ⋮                        ⋮
 1020 │     1                 998  POLYGON ((904045 3905478,...
 1021 │     1                 999  POLYGON ((905355 3905478,...
 1022 │     1                1000  POLYGON ((905556.62823740...
                                               1016 rows omitted

Reproject

Let's reproject the polygons we just made with st_buffer.

reprojected_buffer = SF.st_transform(x, GeoFormatTypes.EPSG(5070))

SimpleFeature
---------
geomtype:  wkbPolygon
crs:   5070
---------
features:  
1000×2 DataFrame
  Row │ lyr.1  geom                         
      │ Int32  sfgeom                       
──────┼─────────────────────────────────────
    1 │     1  POLYGON ((1693276.9257186...
    2 │     1  POLYGON ((1693289.637015 ...
    3 │     1  POLYGON ((1693292.5703908...
  ⋮   │   ⋮                 ⋮
  998 │     1  POLYGON ((1742412.4620032...
  999 │     1  POLYGON ((1743692.7581942...
 1000 │     1  POLYGON ((1743893.9246629...
                            994 rows omitted

Intersection

Say we have two sets of features (two different SimpleFeature objects, x and y), and we'd like to find their intersection and preserve their traits. We can do this with st_intersection.

intersection = SF.st_intersection(x, y)

SimpleFeature
---------
geomtype:  wkbPolygon
crs:       PROJCRS["NAD83(2011) / UTM zone 17N",BASEGEOGCRS["NAD83(2011)",DATUM["NAD83 (National Spatial Refere..."
---------
features:  
357×3 DataFrame
 Row │ lyr.1  lyr.1_1  geom                         
     │ Int32  Int32    sfgeom                       
─────┼──────────────────────────────────────────────
   1 │     1        1  POLYGON ((853789 3905499,...
  ⋮  │   ⋮       ⋮                  ⋮
 357 │     0        0  POLYGON ((857155 3905468,...
                                    355 rows omitted

In this example, y is a buffered subset of x, so both input objects had the same column "lyr.1". When this happens, a suffix will be added to the column from y and it will be joined with x.

Area

I wonder what the area of overlap was from the Intersection example? Let's check it out! The result is in units of the crs.

area_list = SF.st_area(intersection)

357-element Vector{Float64}:
  2.0
  2.0
  2.0
  2.0
  1.0
  1.0
  ⋮
 36.0
  1.0
  1.0
  1.0
  1.0
  1.0

Plotting

Plot a SimpleFeature object using Plots. It will use an equal aspect ratio.

using Plots

x = SF.st_read("example.gpkg")

plot(x)

If you want to specify the fill of geometries based on a column, pass the name of the column to fill_col.

Specify a color palette from ColorSchemes by passing a palette to fill.

julia plot(x, fill = palette(:viridis), fill_col = :cool_value)