Masthead

SpPy - Spatial Python Package

Since it takes quite a bit of work to use the open source geospatial libraries, we have started investigating creating a Python library that wraps the open source libraries into a more easy to use package.

Goals

The goals of this effort are to see if we can create a package that:

Getting Started

Required Libraries

SpPy relies upon a number of open source libraries so you'll also need to make sure the following libraries are installed in your selected version of Python. We have had the most success using the Unofficial Windows Binaries for Python Extension Packages to install the libraries. For Python 3.x, the pip utility also appears to be working.

Using SpPy

SpPy is available from GitHub. We recommend downloading the entire project folder and place it in a folder that is accessible to your Python scripts. Then, add a path to the SpPy folder to your Python scripts. The following lines of code will then import the key SpPy libraries and import the shapely geometry types:

# Open source spatial libraries
import sys
sys.path.append("C:/Temp/SPPy") # add the path to the SpPy libraries

# Open source spatial libraries
from shapely.geometry import Point, LineString, Polygon,MultiPolygon # classes to work with vector data
import shapely

# SP Libraries
import SPPlot
import SPVectors
import SPView
import SPRasters
import SPReferencing

The libraries have the following purposes:

Folders

Below we have setup some file paths that will be used in the examples below.

#################################### 
OutputFolderPath="C:\\Temp\\" 
CountriesFilePath="C:\\Temp\\Examples\\Data\\ne_110m_admin_0_countries.shp" 
TestRasterFilePath="C:\\Temp\\Examples\\Data\\test_raster.tif" 
####################################

Working With Vector Data sets

To get information from a specific data set, you'll want to create an SPDatasetVector object and then load a file into it. This allows you to get information on the data set, modify it's contents, and save it back out again. Below is an example where we have setup a Temp folder with the SpPy library including the Examples.

TheDataset=SPVectors.SPDatasetVector() #create a new layer

TheDataset.Load(CountriesFilePath) # load the contents of the layer

print("Type: "+format(TheDataset.GetType())) # get the type of data in the dataset

print("CRS: "+format(TheDataset.GetCRS())) # return the corodinate reference system

print("NumFeatures: "+format(TheDataset.GetNumFeatures())) # get the number of features in the dataset

print("Bounds: "+format(TheDataset.GetBounds())) # get the spatial bounds of the features

NumAttributes=TheDataset.GetNumAttributes()

print("NumAttributes: "+format(NumAttributes)) # return the definitions for the attributes (this function will change in the future)

Index=0
while (Index < NumAttributes):
	print("Attribute: "+format(TheDataset.GetAttributeName(Index))+", Type: "+format(TheDataset.GetAttributeType(Index))+", Width: "+format(TheDataset.GetAttributeWidth(Index))) 
	Index+=1

# Save the result
TheDataset.Save(OutputFolderPath+"CountryClone.shp") 

One-Line Operations On Vector Data

The following operations will take one or more data sets as the input and then typically return a transformed data set. The data set can be a path to a file, an existing data set object in memory, or a shapely geometry object. The advantage of these functions over other approaches is that you can have a single line perform an entire task. Then, you can use the result in the next function. This allows a series of geospatial transformations to be put into a single file in a very concise and yet readable way.

You can also perform "single-layer operations" on one layer at a time in just a few lines of code as below. For these functions, the "InputFile" can be a file path to a vector data set (typically a shapefile), an SPDatasetVector object, or a shapely geometry object. The example below shows that the operations can be "daisy-chained" without having to save files unless needed.

BufferedDataset=SPVectors.Buffer(CountriesFilePath,10)
BufferedDataset.Save(OutputFolderPath+"Buffered_10.shp")

CentroidDataset=SPVectors.Centroid(CountriesFilePath)
CentroidDataset.Save(OutputFolderPath+"Centroid.shp")

ConvexHullDataset=SPVectors.ConvexHull(CountriesFilePath)
ConvexHullDataset.Save(OutputFolderPath+"ConvexHull.shp")

SimplifiedDataset=SPVectors.Simplify(CountriesFilePath,10)
SimplifiedDataset.Save(OutputFolderPath+"Simplify.shp")

Working with Attributes

The following functions work with loaded vector datasets and modify the attributes associated with each feature.

TheDataset=SPVectors.SPDatasetVector() #create a new layer
TheDataset.Load(CountriesFilePath) # load the contents of the layer

TheValue=TheDataset.GetAttributeValue("LABELRANK",0) # get the value of the atteribute "LABELRANK" for the feature in row 0
print("The Attribute="+format(TheValue))

TheDataset.SetAttributeValue("LABELRANK",0,0) # set the attribute "sum" for the feature in row 0

TheDataset.DeleteAttribute("scalerank") # Remove an attribute

TheDataset.AddAttribute("Test","str",254,"hi") # add a new attribute with the name, type, width, and default value

TheDataset.Save(OutputFolderPath+"AddAndRemoveAttributes.shp") # save the output

Selections and Subsetting

You can create selections of features in a dataset using boolean comparison function calls. The functions take the name of an attribute column and a value to compare each of the attribute values to. These functionswill return an array that contains True where the comparison is True for a feature's specified attribute and False otherwise. You can then use this array to subset the dataset to just the features that had True returned. Note that you can also perform operations on the selection arrays such as AND and OR to create more complex selection critieria.

TheDataset=SPVectors.SPDatasetVector() #create a new layer
TheDataset.Load(CountriesFilePath) # load the contents of the layer

Selection=TheDataset.SelectGreater("LABELRANK",2) # select the features with label rank greater than 2

# Below are four examples of selecting features
Selection=TheDataset.SelectGreaterThanOrEqual("LABELRANK",2) # select the features with label rank greater than or equal to 2

Selection=TheDataset.SelectLess("LABELRANK",2) # select the features with label rank less than or equal to 2.

Selection=TheDataset.SelectLessThanOrEqual("LABELRANK",2) # select the features with label rank less than 2.

Selection=TheDataset.SelectEqual("ADMIN","United States of America") # find the features that have the matching name

# Then, we can subset the dataset using a selection and write it out to a new shapefile
TheDataset.SubsetBySelection(Selection) # sub set the dataset to just contain features for the United States of America

TheDataset.Save(OutputFolderPath+"Selection.shp") # save the output

Deleting Features

You can delete individual features using the index (row in the attribute table) of the feature.

TheDataset=SPVectors.SPDatasetVector() #create a new layer
TheDataset.Load(CountriesFilePath) # load the contents of the layer

# delete the first feature in the dataset
TheDataset.DeleteFeature(0) # remove a feature based on its row index from 0

TheDataset.Save(OutputFolderPath+"OneFeatureDeleted.shp") # save the output

Creating Geometries, Datasets, and Shapefiles

One of the features of SpPy is that you can work with geometrics, datasets in memory, or files. The code below creates a shapely geometry, then creates a new dataset and adds the geometry to the dataset, and then saves the dataset to a shapefile. We'll use these objects in the examples below. Note that when a feature is added, the attributes for the feature are set to 0 or blank values.

# Create a rectangular polygon
Top=45
Bottom=18
Left=-125
Right=-100


BigBox=shapely.geometry.Polygon([(Left,Top), (Right,Top), (Right,Bottom), (Left,Bottom),(Left,Top)])


# Create a new layer (dataset)
BigBoxDataset=SPVectors.SPDatasetVector() #create a new layer


# add the rectangular polygon
BigBoxDataset.AddFeature(BigBox)


BigBoxDataset.Save(OutputFolderPath+"BigBox.shp") # save the output

Overlay Operations with Geometries

The code below shows that you can use geometries, like BigBox created above, to perform overlay operations on spatial data.

# Crop a shapefile with a polygon 
NewLayer=SPVectors.Intersection(OutputFolderPath+"Selection.shp",BigBox) # perform an intersection on a geometry to get the new layer
NewLayer.Save(OutputFolderPath+"IntersectionWithGeometry.shp") 

# Union the shapefile with the polygon
NewLayer=SPVectors.Union(OutputFolderPath+"Selection.shp",BigBox) # perform a union on a geometry to get the new layer
NewLayer.Save(OutputFolderPath+"UnionWithGeometry.shp") # save the output

# Find the difference between the shapefile and the polygon (erase the area of the BigBox)
NewLayer=SPVectors.Difference(OutputFolderPath+"Selection.shp",BigBox) # 
NewLayer.Save(OutputFolderPath+"DifferenceWithGeometry.shp") # save the output

Overlay Operations with Datasets

You can also perform overlay operations on datasets.

NewLayer=SPVectors.Difference(OutputFolderPath+"USA.shp",BigBoxDataset) # 
   NewLayer.Save(OutputFolderPath+"DifferenceWithDataset.shp") # save the output  

Overlay Operations with Shapefiles

Finally, you can perform operations on shapefiles as well.

NewLayer=SPVectors.Difference(OutputFolderPath+"USA.shp",OutputFolderPath+"BigBox.shp") 
   NewLayer.Save(OutputFolderPath+"DifferenceWithShapefile.shp") # save the output  

Working with Raster Data

The code below will load a raster into memory and then return basic data for the raster. The Start of the file is the same except we need access to one of

TheDataset=SPRasters.SPDatasetRaster()
TheDataset.Load(TestRasterFilePath)

print("Width in pixels: "+format(TheDataset.GetWidthInPixels()))

print("Height in pixels: "+format(TheDataset.GetHeightInPixels()))

print("Num Bands: "+format(TheDataset.GetNumBands()))

print("Projection: "+format(TheDataset.GetProjection()))

print("Resolution (x,y): "+format(TheDataset.GetResolution()))

TheBounds=TheDataset.GetBounds()
print("TheBounds (XMin,YMin,YMax,XMax): "+format(TheBounds))

TheDataset.Save(OutputFolderPath+"CopiedRaster.tif") 

Creating a new raster

The code below will create a raster of a given width and height.

WidthInPixels=100
HeightInPixels=100

TheDataset=SPRasters.SPDatasetRaster()
TheDataset.SetWidthInPixels(WidthInPixels)
TheDataset.SetHeightInPixels(HeightInPixels)
TheDataset.SetType(gdal.GDT_Float32)

TheBands=TheDataset.AllocateArray()
TheBands=TheBands[0]

Row=0
while (Row<HeightInPixels):
	Column=0
	while (Column<WidthInPixels):
		TheBands[Row][Column]=Column
		Column+=1
		Row+=1
print(TheBands)

TheDataset.SetUTM(10)
TheDataset.SetNorthWestCorner(400000,4000000)
TheDataset.SetResolution(30,30)
TheDataset.Save(OutputFolderPath+"NewRaster.tif")

Transforming Rasters

The raster functions are very flexible and can take file paths to a raster, a raster object, or a scalar value. Mathematical, boolean, and comparison functions are all available in SpPy. A few examples are below and the rest are listed in the reference at the end of this page.

# Find pixels that are less than 10 using a shapefile and a function

NewRaster=SPRasters.LessThan(TestRasterFilePath,10) # results in 1 for pixels in Raster1 are less than pixels in Raster2


# Find pixels that are less than 10 using a dataset and an overloaded operator
TheRaster=SPRasters.SPDatasetRaster() # create the dataset
TheRaster.Load(TestRasterFilePath) # load the data from a file


NewRaster=TheRaster < 10 # Use the less than operator instead of a function

NewRaster.Save(OutputFolderPath+"LessThan.tif") # save the resut to a file

Projecting

To change the CRS for a dataset, we use the Proj4 parameters. Note that the projection engine for rasteres, GDAL, requires the raster to be written to a file so you need to specify the output file path when projecting rasters and this is a different function call.

# here is how you would specify the projection for Alber's Equal Area
ProjectionCode="aea"
Parameters={
    "lon_0":0,
    "lat_1":60,
    "lat_2":40
}
# here is an example projecting the test raster back to geographic
ProjectionCode="longlat"
Parameters={
}
TheRaster=SPRasters.SPDatasetRaster()
TheRaster.Load(TestRasterFilePath)

NewLayer=SPReferencing.ProjectRaster(TheRaster,ProjectionCode,Parameters,OutputFolderPath+"Projected.tif")

Rendering

The SPView class allows dataset to be rendred into a view which can then be saved to a raster file or displayed in a window. Since the rendering requires symobology, the dataset is placed inside a layer object first and then sent to the view.

Note that this portion of SpPy is in development (as most of it is ;-)

TheDataset=SPVectors.SPDatasetVector() #create a new layer

TheDataset.Load(CountriesFilePath) # load the contents of the layer


TheBounds=TheDataset.GetBounds()
MinX=TheBounds[0]
MinY=TheBounds[1]
MaxX=TheBounds[2]
MaxY=TheBounds[3]
TheView=SPView.SPView(500,500)
TheView.SetBounds(MinX,MaxX,MinY,MaxY) # 


TheLayer=SPVectors.SPLayerVector()
TheLayer.SetDataset(TheDataset)
TheLayer.Render(TheView)
TheView.Save(OutputFolderPath+"RenderedVectors.png")

API Reference

Below is an initial reference for the available functions.

SPVectors.SPDatasetVector

The functions below are available for an SPDatasetVector object.

Name Description
Data Management  
Load(FilePath) Load data from the specified file path
Save(FilePath) Save the data set to the specified path
Type=GetType() Returns the type of vector data from the OGC standards (e.g. "Polygon", "Point", "MultiPolygon", etc).
SetType(NewType) Sets the type of vector data from the OGC standards (e.g. "Polygon", "Point", "MultiPolygon", etc). Should only be called before data has been added to the data set.
CRS=GetCRS() Returns the coordinate reference system information (see https://fiona.readthedocs.io/en/latest/manual.html)
SetCRS(CRS)  
   
Attribute management  
Value=GetAttributeValue(AttributeName,Row) Return the value of the attribute with the specific name and row index.
SetAttributeValue(AttributeName,Row,NewValue) Set the value of the attribute with the specified name and row index to the NewValue.
Num=GetNumAttributes() Returns the number of attribute columns defined for the data set.
Name=GetAttributeName(ColumnIndex) Returns the attribute name for the specified attribute column
Type=GetAttributeType(ColumnIndex) Returns the attribute type ("str","int""float") for the specified attribute column
Width=GetAttributeWidth(ColumnIndex) Returns the width of the attribute (really its precision)
AddAttribute(Name,Type,Width=None,Default=None) Add a new attribute column with the specified parameters
DeleteAttribute(Name) Delete the attribute row of the specified name
RowIndex=GetAttributeColumn(Name) Return an index to the attribute column that has the specified name
Selection=SelectEqual(AttributeName,Value) Return a selection list with True where the attribute values are equal to the specified value and False otherwise
Selection=SelectGreater(AttributeName,Value) Return a selection list with True where the attribute values are greater than to the specified value and False otherwise
Selection=SelectGreaterThanOrEqual(AttributeName,Value) Return a selection list with True where the attribute values are greater than or equal to the specified value and False otherwise
Selection=SelectLess(AttributeName,Value) Return a selection list with True where the attribute values are less than to the specified value and False otherwise
Selection=SelectLessThanOrEqual(AttributeName,Value) Return a selection list with True where the attribute values are less than or equal to the specified value and False otherwise
SubsetBySelection(Selection) Remove any features from the data set that have False in the selection array.
   
Feature/Geometry Management These functions are provided to make it easy to obtain information from the features geometries
NumFeatures=GetNumFeatures() Return the number of features/rows in the dataset
DeleteFeature(Row) Remove the specified feature, including its attributes, from the data set.
AddFeature(TheGeometry,TheAttributes=None): Add a new geometry to the data set. An optional list of attribute values can also be specified.
TheGeometry=GetGeometry(FeatureIndex) Return the shapely geometry object associated with the feature, if any
SplitFeatures() Breaks up features that are collections or contain muiltple geometries (i.e. "multi") into individual features.
Bounds=GetBounds() Return the spatial bounds of all the features.
   
Area=GetFeatureArea(FeatureIndex) Returns the area of the feature
Bounds=GetFeatureBounds(FeatureIndex) Returns the spatial bounds of the feature
Length=GetFeatureLength(FeatureIndex) Returns the length of all the line segments in the feature
EmptyFlag=IsFeatureEmpty(FeatureIndex) Returns True if the feature does not contain any coordinates
ValidFlag=IsFeatureValid(FeatureIndex) Returns True if the feature contains a valid geometry (e.g. no overlapping segments)

SPVector

The following functions are available in the SPVector library. These functions take one or more inputs that can be paths to files, data sets loaded into memory, or shapely geometries.

Single-Dataset Operations  
OutputDataset=Buffer(InputDataset,Amount)  
OutputDataset=Simplify(InputDataset,Tolerance, PreserveTopology=True)  
OutputDataset=ConvexHull(InputDataset)  
OutputDataset=Centroid(InputDataset)  
   
Overlay Operations  
OutputDataset=Intersection(InputDataset1,InputDataset2)  
OutputDataset=Union(InputDataset1,InputDataset2)  
OutputDataset=Difference(InputDataset1,InputDataset2)  
OutputDataset=SymmetricDifference(InputDataset1,InputDataset2)  

SPRasterDataset

Provides functions to work with raster data sets. The operations that work on rasters can take a path to a file, an existing raster object, or a scalar value for operators.

Name Description
RasterDataset operations  
RasterDataset.Load(FilePath) Loads the data from a file into the dataset
RasterDataset.Save(FilePath) Saves the data from the dataset into a file
WidthInPixels=RasterDataset.GetWidthInPixels() Retursn the number of columns of pixels in the data
RasterDataset.SetWidthInPixels(NewWidth) Sets the overall width of the raster in pixels. Only should be called if the raster data has not been allocated yet.
HeightInPixels=RasterDataset.GetHeightInPixels() Returns the overall width of the raster in pixels. Only should be called if the raster data has not been allocated yet.
RasterDataset.SetHeightInPixels(NewHeight) Sets the number of rows of pixels in the data
NumBands=RasterDataset.GetNumBands() Returns the number of bands of data in the raster (i.e. gray=1, RGB=3).
CRS=RasterDataset.GetProjection() Note: Needs to change to GetCRS()
X,Y=RasterDataset.GetResolution() Returns the resolution (spatial reference units per pixels) as a tuple
RasterDataset.SetResolution((X,Y))  
Bounds=RasterDataset.GetBounds()  
RasterDataset.SetNorthWestCorner(X,Y)  
Band=RasterDataset.GetBand(BandIndex) Returns an array with the band data for the specified index (0 for first, 1 for second, etc.)
Bands=RasterDataset.GetBands() Return an array of arrays with the data for all the bands.
RasterDataset.SetBands(Bands) Sets an array of arrays with the data for all the bands. This function should be used carefully as the dimensions and type of the band data must match the settings in the object.
Min,Max=RasterDataset.GetMinMax(BandIndex) REturns the minimum and maximum values for the data in the specific bands.
GDALType=RasterDataset.GetType()

Returns the type of sample values based on GDAL definitions: gdal.GDT_Byte, gdal.GDT_UInt16,gdal.GDT_Int16,gdal.GDT_UInt32,gdal.GDT_Int32,gdal.GDT_Float32,dal.GDT_Float64,gdal.GDT_CFloat64

Note: Do we support all these types?

RasterDataset.SetType(New)

Sets the type of sample values based on GDAL definitions (see above)

RasterDataset.AllocateArray() Allocates the pixel data for the current data set
   

 

SPRaster Public Functions

The following functions are available in the SPRaster library as single-line operations. The inputs can be paths to files or data sets loaded into memory.

Math Operations  

OutputRaster=Add(Input1,Input2)

Outputraster=Input1+Input2

Adds the pixels in the two rasters together or add a scalar value to the pixels in the first raster.

OutputRaster=Subtract(Input1,Input2)

OutputRaster=Input1 - Input2

Subtract the pixels in the two rasters from one another or subtract a scalar value from the raster.

OutputRaster=Multiply(Input1,Input2)

OutputRaster=Input1 * Input2

Mutiply the pixels in the two rasters together or mutiply a scalar value to the pixels in the raster.

OutputRaster=Divide(Input1,Input2)

OutputRaster=Input1 / Input2

Divide the raster Input1 by the raster or scalar value in Input2.
   
Comparisons  

OutputRaster=Equal(Input1,Input2)

OutputRaster=Input1==Input2

Creates a new raster with True (1) for pixels that are equal in both rasters and 0 otherwise.

OutputRaster=LessThan(Input1,Input2)

OutputRaster=Input1<Input2

 

OutputRaster=GreaterThan(Input1,Input2)

OutputRaster=Input1>Input2

 

OutputRaster=LessThanOrEqual(Input1,Input2)

OutputRaster=Input1<=Input2

 

OutputRaster=GreaterThanOrEqual(Input1,Input2)

OutputRaster=Input1>=Input2

 
   
OutputRaster=Minimum(Input1,Input2) Returns a new raster where each pixel is the minimum value of the two overlapping pixels in the inputs.
OutputRaster=Maximum(Input1,Input2)  
   
Boolean Operations  

OutputRaster=And(Input1,Input2)

Returns a new raster where each pixel is the logical result of anding the overlapping pixels in the inputs.
OutputRaster=Or(Input1,Input2)  
OutputRaster=Not(Input1)  
   
Conversions  
OutputRaster=RoundInteger(Input1) Returns a new raster where the pixels have been rounded to the nearest integer.
OutputRaster=RoundFix(Input1) Round to nearest integer towards zero.
OutputRaster=RoundFloor(Input1) Returns a new raster where the pixels have been truncated to the lowest value (i.e. 0.5 -> 0, 0.6 -> 0)
OutputRaster=RoundCeiling(Input1) Returns a new raster where the pixels have been truncated to the highest nvalue (i.e. 0.5 -> 1, 0.6 -> 1)
OutputRaster=RoundTruncate(Input1) Returns a new raster where the pixels have been truncated (i.e. 0.5 -> 0, 0.6 -> 0)
   
Exponential functions  
OutputRaster=NaturalLog(Input1)  
OutputRaster=Log(Input1)  
OutputRaster=Exponent(Input1) Returns a new raster with pixels that are the result of raising the value e to the value in the input raster.
OutputRaster=Power(Input1,Power) Returns a new raster with pixels that are the result of raising the values in the input by the specified Power (i.e. New=Old ^Power).
OutputRaster=Square(Input1)  
OutputRaster=SquareRoot(Input1)  
OutputRaster=AbsoluteValue(Input1)  
   
Conversions  
OutputVector=Polygonize(Input1) Need to finish this jjg

 

Resampling - under development

This class provides resampling for raster data

Name Description
NewDataset=Zoom(Input1,ZoomFactor)  
ExtractByPixels(InputRasterDataset,StartColumn,StartRow,EndColumn,EndRow)  

SPReferencing

Provides functions to project datasets.

Name Description
NewDataset=SPReferencing.Project(InputDataset,ProjectionCode,Parameters,LatNewPole=90) Projecs the dataset to the desired spatial reference

Notes

Missing: Question, what is the core and what can be added with additional classes

© Copyright 2018 HSU - All rights reserved.