Javascript required
Skip to content Skip to sidebar Skip to footer

Read Field Values of a Shapefile Gdal

Shapefile (Vector) Handling¶

This section introduces geospatial analysis of shapefiles with gdal, ogr, and osr. For interactive reading and executing code blocks Binder and discover geo01-shp.ipynb, or install Python and JupyterLab locally.

Use flusstools

The core functions featured in this department are besides implemented in flusstools. To use those functions, brand sure flusstools is installed and import information technology as follows: from flusstools import geotools . Some of the functions shown in this tutorial tin then exist used with geotools.function_name() .

Load an Existing Shapefile¶

OSGeo's ogr module is an splendid source for handling shapefiles. Later importing the libraries, the correct driver for treatment shapefiles ( "ESRI Shapefile" ) with Python needs to exist chosen. Next, with the commuter object ( ogr.GetDriverByName("SHAPEFILE") ), we can open up (instantiate) a shapefile (object with shp_driver.Open("SHAPEFILE") ), which contains layer information. It is precisely the layer data (i.e., references to shapefile attributes) that we desire to work with. Therefore we take to instantiate a shapefile layer object with shp_dataset.GetLayer() .

                            from              osgeo              import              ogr              shp_driver              =              ogr              .              GetDriverByName              (              "ESRI Shapefile"              )              shp_dataset              =              shp_driver              .              Open              (              "geodata/shapefiles/cities.shp"              )              shp_layer              =              shp_dataset              .              GetLayer              ()            

Practice not use from gdal import ogr

Importing ogr with from gdal import ogr is deprecated since GDAL v3. Therefore, ogr must be imported from osgeo .

Create a New Shapefile¶

ogr too enables creating a new bespeak, line, or polygon shapefile. The post-obit code block defines a function for creating a shapefile, where the optional keyword argument overwrite is used to command whether an existing shapefile with the same name should exist overwritten (default: True ). The command shp_driver.CreateDataSource(SHP-FILE-DIR) creates a new shapefile and the residue of the function adds a layer to the shapefile if the optional keyword arguments layer_name and layer_type are provided. Both optional keywords must be strings, where layer_name can be any proper name for the new layer. layer_type must be either "betoken" , "line" , or "polygon" to create a betoken, (poly)line, or polygon shapefile, respectively. The role uses the geometry_dict dictionary to assign the correct ogr.SHP-TYPE to the layer. There are more options for extending the create_shp(...) function listed on pcjerick's Github pages.

                            from              osgeo              import              ogr              import              bone              def              create_shp              (              shp_file_dir              ,              overwrite              =              Truthful              ,              *              args              ,              **              kwargs              ):              """                              :param shp_file_dir: STR of the (relative shapefile directory (ends on ".shp")                              :param overwrite: [optional] BOOL - if Truthful, existing files are overwritten                              :kwarg layer_name: [optional] STR of the layer_name - if None: no layer will be created (max. 13 chars)                              :kwarg layer_type: [optional] STR ("indicate, "line", or "polygon") of the layer_name - if None: no layer will be created                              :output: returns an ogr shapefile layer                              """              shp_driver              =              ogr              .              GetDriverByName              (              "ESRI Shapefile"              )              # check if output file exists if aye delete it              if              bone              .              path              .              exists              (              shp_file_dir              )              and              overwrite              :              shp_driver              .              DeleteDataSource              (              shp_file_dir              )              # create and return new shapefile object              new_shp              =              shp_driver              .              CreateDataSource              (              shp_file_dir              )              # create layer if layer_name and layer_type are provided              if              kwargs              .              get              (              "layer_name"              )              and              kwargs              .              become              (              "layer_type"              ):              # create dictionary of ogr.SHP-TYPES              geometry_dict              =              {              "point"              :              ogr              .              wkbPoint              ,              "line"              :              ogr              .              wkbMultiLineString              ,              "polygon"              :              ogr              .              wkbMultiPolygon              }              # create layer              try              :              new_shp              .              CreateLayer              (              str              (              kwargs              .              get              (              "layer_name"              )),              geom_type              =              geometry_dict              [              str              (              kwargs              .              get              (              "layer_type"              )              .              lower              ())])              except              KeyError              :              print              (              "Error: Invalid layer_type provided (must be 'betoken', 'line', or 'polygon')."              )              except              TypeError              :              print              (              "Error: layer_name and layer_type must be string."              )              except              AttributeError              :              print              (              "Error: Cannot access layer - opened in other programme?"              )              return              new_shp            

The create_shp function is as well provided with flusstools ( flusstools.geotools.create_shp() ) and aids to create a new shapefile (brand certain to get the directory right):

                            a_new_shp_file              =              create_shp              (              r              ""              +              bone              .              getcwd              ()              +              "/geodata/shapefiles/new_polygons.shp"              ,              layer_name              =              "basemap"              ,              layer_type              =              "polygon"              )              # release data source              a_new_shape_file              =              None            

Important

A shapefile name may non accept more than thirteen characters and a field name may not take more than x characters (read more in Esri'southward shapefile docs).

Shapefiles can as well be created and fatigued in QGIS and the following figures guide through the procedure of creating a polygon shapefile. We will not demand the resulting shapefile in this department anymore, simply later for making information technology interact with raster datasets.

The first step to making a shapefile with QGIS is patently to run QGIS and create a new project. The post-obit example uses water depth and period velocity raster information every bit groundwork information to delineate the and so-called morphological unit of slackwater. Both the water depth and flow velocity rasters are office of the River Architect sample datasets (precisely located at RiverArchitect/SampleData/01_Conditions/2100_sample/ ). After downloading the sample data, they can be imported in QGIS by dragging the files from the Browser console into the Layers console. Then:

img img img img

Get and Set Shapefile Projections¶

The terminology used in the .prj files of a shapefile corresponds to the definitions in the geospatial information section. In Python, information about the coordinate system is bachelor through shp_layer.GetSpatialRef() of the ogr library:

                                shp_srs                =                shp_layer                .                GetSpatialRef                ()                print                (                shp_srs                )              
                GEOGCS["WGS 84",     DATUM["WGS_1984",         SPHEROID["WGS 84",6378137,298.257223563,             Dominance["EPSG","7030"]],         AUTHORITY["EPSG","6326"]],     PRIMEM["Greenwich",0,         AUTHORITY["EPSG","8901"]],     Unit of measurement["degree",0.0174532925199433,         Dominance["EPSG","9122"]],     Axis["Latitude",NORTH],     AXIS["Longitude",Due east],     Say-so["EPSG","4326"]]              

This GEOGCS definition of the above shapefile corresponds to Esri's well-known text (WKT). Since the shapefile format was developed by Esri, Esri's WKT (esriwkt) format must be used in .prj files. The Open up Geospatial Consortium (OGC) uses a unlike well-known text in their EPSG:XXXX definitions (e.1000., available at spatialreference.org).

                            GEOGCS              [              "WGS 84"              ,              DATUM              [              "WGS_1984"              ,              SPHEROID              [              "WGS84"              ,              6378137              ,              298.257223563              ,              AUTHORITY              [              "EPSG"              ,              "7030"              ]]              ,              AUTHORITY              [              "EPSG"              ,              "6326"              ]]              ,              PRIMEM              [              "Greenwich"              ,              0              ,              Authorisation              [              "EPSG"              ,              "8901"              ]]              ,              Unit              [              "degree"              ,              0.01745329251994328              ,              AUTHORITY              [              "EPSG"              ,              "9122"              ]]              ,              Potency              [              "EPSG"              ,              "4326"              ]]            

To redefine or newly define the coordinate organization of a shapefile, we can use spatialreference.org through Python's default urllib library.

Notation

Running the following code block requires an net connection.

                            import              urllib              # role to get spatialreferences with epsg code              def              get_esriwkt              (              epsg              ):              # usage get_epsg_code(4326)              try              :              with              urllib              .              asking              .              urlopen              (              "http://spatialreference.org/ref/epsg/              {0}              /esriwkt/"              .              format              (              epsg              ))              every bit              response              :              render              str              (              response              .              read              ())              .              strip              (              "b"              )              .              strip              (              "'"              )              except              Exception              :              pass              try              :              with              urllib              .              request              .              urlopen              (              "http://spatialreference.org/ref/sr-org/epsg              {0}              -wgs84-web-mercator-auxiliary-sphere/esriwkt/"              .              format              (              epsg              ))              equally              response              :              return              str              (              response              .              read              ())              .              strip              (              "b"              )              .              strip              (              "'"              )              # sr-org codes are available at "https://spatialreference.org/ref/sr-org/{0}/esriwkt/".format(epsg)              # for case EPSG:3857 = SR-ORG:6864 -> https://spatialreference.org/ref/sr-org/6864/esriwkt/ = EPSG:3857              except              Exception              :              impress              (              "Mistake: Could not discover epsg lawmaking on spatialreference.org. Returning default WKT(epsg=4326)."              )              return              'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],Unit of measurement["Caste",0.017453292519943295],UNIT["Meter",1]]'            

This function tin be used to create a new projection file:

                                # open the hypy-area shapefile                shp_file                =                "hypy-area"                # create new .prj file for the shapefile (.shp and .prj must take the same name)                with                open                (                "geodata/shapefiles/                {0}                .prj"                .                format                (                shp_file                ),                "west"                )                equally                prj                :                epsg_code                =                get_esriwkt                (                4326                )                prj                .                write                (                epsg_code                )                impress                (                "Wrote projection file : "                +                epsg_code                )              
                Wrote projection file : GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],Unit of measurement["Degree",0.017453292519943295]]              

An offline alternative for generating a .prj file is the osr library that comes along with gdal :

                            from              osgeo              import              osr              def              get_wkt              (              epsg              ,              wkt_format              =              "esriwkt"              ):              default              =              'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Caste",0.017453292519943295],UNIT["Meter",1]]'              spatial_ref              =              osr              .              SpatialReference              ()              try              :              spatial_ref              .              ImportFromEPSG              (              epsg              )              except              TypeError              :              print              (              "ERROR: epsg must be integer. Returning default WKT(epsg=4326)."              )              return              default              except              Exception              :              print              (              "Error: epsg number does not be. Returning default WKT(epsg=4326)."              )              return              default              if              wkt_format              ==              "esriwkt"              :              spatial_ref              .              MorphToESRI              ()              # return a nicely formatted WKT string (alternatives: ExportToPCI(), ExportToUSGS(), or ExportToXML())              return              spatial_ref              .              ExportToPrettyWkt              ()            

Transform (Re-projection) a Shapefile¶

A re-projection may be needed, for instance, to utilise a shapefile in EPSG:4326 (e.g., created with QGIS) in a web-GIS application (due east.1000., open street maps) that typically uses EPSG:3857 . To utilize a different projection to geometric objects of a shapefile, it is not enough to simply rewrite the .prj file. Therefore, the following example shows the re-project of the countries.shp shapefile from the Natural Earth quick showtime kit. The following workflow performs the reprojection:

  • Save shapefile to transform is located in the subdirectory geodata/shapefiles/countries.shp and open it in the Python script as described above.

  • Read and identify the spatial reference system used in the input shapefile:

    • Create a spatial reference object with in_sr = osr.SpatialReference(str(shapefile.GetSpatialRef())) .

    • Detect the spatial reference organization in EPSG format with AutoIdentifyEPSG() .

    • Assign the EPSG-formatted spatial reference organization to the spatial reference object of the input shapefile ( ImportFromEPSG(int(in_sr.GetAuthorityCode(None))) ).

  • Create the output spatial reference with out_sr = osr.SpatialReference() and use the target EPSG code ( out_sr.ImportFromEPSG(3857) ).

  • Create a coordinate transformation object ( coord_trans = osr.CoordinateTransformation(in_sr, out_sr) ) that enables re-projecting geometry objects subsequently.

  • Create the output shapefile, which will correspond to a copy of the input shapefile (employ the above-defined create_shp function with layer_name="basemap" and layer_type="line" ).

  • Copy the field names and types of the input shapefile:

    • Read the attribute layer from the input file's layer definitions with in_lyr_def = in_shp_lyr.GetLayerDefn()

    • Iterate through the field definitions and append them to the output shapefile layer ( out_shp_lyr )

  • Iterate through the geometry features in the input shapefile:

    • Employ the new (output) shapefile'south layer definitions ( out_shp_lyr_def = out_shp_lyr.GetLayerDefn() ) to append transformed geometry objects later.

    • Define an iteration variable in_feature as an example of in_shp_lyr.GetNextFeature .

    • In a while loop, instantiate every geometry ( geometry = in_feature.GetGeometryRef() ) in the input shapefile, transform the geometry ( geometry.Transform(coord_trans) ), convert it to an ogr.Characteristic() with the SetGeometry(geometry) method, re-create field definitions (nested for -loop), and suspend the new feature to the output shapefile layer ( out_shp_lyr_def.CreateFeature(out_feature) ).

    • At the end of the while -loop, look for the side by side feature in the input shapefile'due south attributes with in_feature = in_shp_lyr.GetNextFeature()

  • Unlock (release) all layers and shapefiles by overwriting the objects with None (nothing is written to whatsoever file every bit long as these variables exist!).

  • Assign the new projection EPSG:3857 using the in a higher place-defined get_wkt function.

                            from              osgeo              import              ogr              from              osgeo              import              osr              shp_driver              =              ogr              .              GetDriverByName              (              "ESRI Shapefile"              )              # open input shapefile and layer              in_shp              =              shp_driver              .              Open              (              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/countries.shp"              )              in_shp_lyr              =              in_shp              .              GetLayer              ()              # become input SpatialReference              in_sr              =              osr              .              SpatialReference              (              str              (              in_shp_lyr              .              GetSpatialRef              ()))              # auto-detect epsg              in_sr              .              AutoIdentifyEPSG              ()              # assign input SpatialReference              in_sr              .              ImportFromEPSG              (              int              (              in_sr              .              GetAuthorityCode              (              None              )))              # create SpatialReference for new shapefile              out_sr              =              osr              .              SpatialReference              ()              out_sr              .              ImportFromEPSG              (              3857              )              # create a CoordinateTransformation object              coord_trans              =              osr              .              CoordinateTransformation              (              in_sr              ,              out_sr              )              # create output shapefile and get layer              out_shp              =              create_shp              (              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/countries-spider web.shp"              ,              layer_name              =              "basemap"              ,              layer_type              =              "line"              )              out_shp_lyr              =              out_shp              .              GetLayer              ()              # await up layer (features) definitions in input shapefile              in_lyr_def              =              in_shp_lyr              .              GetLayerDefn              ()              # re-create field names of input layer attribute tabular array to output layer              for              i              in              range              (              0              ,              in_lyr_def              .              GetFieldCount              ()):              out_shp_lyr              .              CreateField              (              in_lyr_def              .              GetFieldDefn              (              i              ))              # instantiate feature definitions object for output layer (currently empty)              out_shp_lyr_def              =              out_shp_lyr              .              GetLayerDefn              ()              # iteratively suspend all input features in new project              in_feature              =              in_shp_lyr              .              GetNextFeature              ()              while              in_feature              :              # go the input geometry              geometry              =              in_feature              .              GetGeometryRef              ()              # re-projection (transform) geometry to new system              geometry              .              Transform              (              coord_trans              )              # create new output characteristic              out_feature              =              ogr              .              Characteristic              (              out_shp_lyr_def              )              # assign in-geometry to output feature and copy field values              out_feature              .              SetGeometry              (              geometry              )              for              i              in              range              (              0              ,              out_shp_lyr_def              .              GetFieldCount              ()):              out_feature              .              SetField              (              out_shp_lyr_def              .              GetFieldDefn              (              i              )              .              GetNameRef              (),              in_feature              .              GetField              (              i              ))              # add together the feature to the shapefile              out_shp_lyr              .              CreateFeature              (              out_feature              )              # ready next iteration              in_feature              =              in_shp_lyr              .              GetNextFeature              ()              # release shapefiles and layers              in_shp              =              None              in_shp_lyr              =              None              out_shp              =              None              out_shp_lyr              =              None              # create .prj file for  output shapefile for web application references              with              open              (              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/countries-spider web.prj"              ,              "w+"              )              as              prj              :              prj              .              write              (              get_wkt              (              3857              ))            

Challenge

Re-write the above lawmaking cake in a re_project(shp_file, target_epsg) function.

In the example of success, the lawmaking sequence in_sr.AutoIdentifyEPSG() returns 0 (i.e., it successfully recognized the EPSG number), just unfortunately, many EPSG numbers are non known to AutoIdentifyEPSG() . In the case that AutoIdentifyEPSG() did non function propperly, the method does non render 0 , but 7 , for example. A workaround for the limited functionality of srs.AutoIdentifyEPSG() is srs.FindMatches . srs.FindMatches returns a matching srs_match from a larger database, which is somewhat nested; for instance, utilize:

                            matches              =              srs              .              FindMatches              ()            

Then, matches looks similar this: [(osgeo.osr.SpatialReference, INT)] . Therefore, a complete workaround for srs.AutoIdentifyEPSG() (or in_sr.AutoIdentifyEPSG() in the code block higher up) looks like this:

                            # set epsg and create spatial reference object              epsg              =              3857              srs              =              osr              .              SpatialReference              ()              srs              .              ImportFromEPSG              (              epsg              )              # identify spatial reference              auto_detect              =              srs              .              AutoIdentifyEPSG              ()              if              auto_detect              is              not              0              :              srs              =              srs              .              FindMatches              ()[              0              ][              0              ]              # Find matches returns listing of tuple of SpatialReferences              srs              .              AutoIdentifyEPSG              ()              # Re-perform auto-identification            

Add Fields and Point Features to a Shapefile¶

A shapefile feature can exist a bespeak, a line, or a polygon, which has field attributes (e.one thousand., "id"=one to describe that this is polygon number i or associated to an id block 1). Field attributes tin be more than but an IDentifier and include, for example, the polygon surface area or city labels as in the to a higher place-shown example illustrating cities.shp ( shp_driver.Open("geodata/shapefiles/cities.shp") ).

To create a signal shapefile, we tin can use the above-introduced create_shp function (or flusstools.geotools.create_shp(shp_file_dir="") ) and set the projection with the get_epsg_code() function (also higher up introduced). The following lawmaking cake shows the usage of both functions to create a river.shp indicate shapefile that contains three points located at three rivers in cardinal Europe. The code block also illustrates the creation of a field in the attribute table and the creation of three betoken features. Here is how the code works:

  • The shapefile is located in the rivers_pts variable. Note that the layer_type already determines the type of geometries that can be used in the shapefile. For instance, adding a line or polygon feature to an ogr.wkbPoint layer will upshot in an Error 1 message.

  • The basemap (layer) is attributed to the variable lyr = river_pts.GetLayer() .

  • A string-type field is added and appended to the attribute table:

    • instantiate a new field with field_gname = ogr.FieldDefn("FIELD-NAME", ogr.OFTString) (call back: the field name may not have more than 10 characters!)

    • append the new field to the shapefile with lyr.CreateField(field_gname)

    • other field types than OFTString can exist: OFTInteger , OFTReal , OFTDate , OFTTime , OFTDateTime , OFTBinary , OFTIntegerList , OFTRealList , or OFTStringList .

  • Add three points stored in pt_names = {RIVER-NAME: (x-coordinate, y-coordinate)} in a loop over the dictionary keys:

    • for every new point, create a characteristic every bit a kid of the layer defintions with characteristic = ogr.Characteristic(lyr.GetLayerDefn())

    • set the value of the field proper noun for every indicate with feature.SetField(FIELD-NAME, FIELD-VALUE)

    • create a string of the new point in WKT format with wkt = "POINT(10-COORDINATE Y-COORDINATE)"

    • catechumen the WKT-formatted point into a point-blazon geometry with signal = ogr.CreateGeometryFromWkt(wkt)

    • set the new point every bit the new feature's geometry with feature.SetGeometry(point)

    • suspend the new feature to the layer with lyr.CreateFeature(feature)

  • Unlock (release) the shapefile by overwriting the lyr and river_pts variable with None .

Important

The operations are not written to the shapefile if the lyr and river_pts objects are not overwritten with None .

                            shp_dir              =              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/rivers.shp"              river_pts              =              create_shp              (              shp_dir              ,              layer_name              =              "basemap"              ,              layer_type              =              "point"              )              # create .prj file for the shapefile for spider web application references              with              open up              (              shp_dir              .              split up              (              ".shp"              )[              0              ]              +              ".prj"              ,              "w+"              )              as              prj              :              prj              .              write              (              get_esriwkt              (              3857              ))              # go basemap layer              lyr              =              river_pts              .              GetLayer              ()              # add string field "rivername"              field_gname              =              ogr              .              FieldDefn              (              "rivername"              ,              ogr              .              OFTString              )              lyr              .              CreateField              (              field_gname              )              # names and coordinates of central European union rivers in EPSG:3857 WG84 / Pseudo-Mercator              pt_names              =              {              "Aare"              :              (              916136.03              ,              6038687.72              ),              "Ain"              :              (              623554.12              ,              5829154.69              ),              "Inn"              :              (              1494878.95              ,              6183793.83              )}              # add together the three rivers equally points to the basemap layer              for              north              in              pt_names              .              keys              ():              # create Characteristic as child of the layer              pt_feature              =              ogr              .              Characteristic              (              lyr              .              GetLayerDefn              ())              # ascertain value north (river) in the rivername field              pt_feature              .              SetField              (              "rivername"              ,              n              )              # use WKT format to add a point geometry to the Feature              wkt              =              "Betoken(              %f                                          %f              )"              %              (              float              (              pt_names              [              n              ][              0              ]),              float              (              pt_names              [              n              ][              1              ]))              point              =              ogr              .              CreateGeometryFromWkt              (              wkt              )              pt_feature              .              SetGeometry              (              bespeak              )              # append the new characteristic to the basement layer              lyr              .              CreateFeature              (              pt_feature              )              # release files              lyr              =              None              river_pts              =              None            

The resulting rivers.shp shapefile tin be imported in QGIS forth with a DEM from the Natural Globe quick start kit.

img

Multiline (Polyline) Shapefile¶

Similar to the procedure for creating and calculation points to a new indicate shapefile, a (multi) line (or polyline) can be added to a shapefile. The create_shp function creates a multi-line shapefile when the layer type is defined as "line" ( flusstools.geotools.create_shp(shp_file_dir="", layer_type="line") ). The coordinate system is created with the higher up-defined get_gps_code function.

Tip

The term multi-line is used in OGC and ogr , while polyline is used in Esri GIS environments.

The following code block uses the coordinates of cities along the Rhine River, stored in a dictionary named station_names . The metropolis names are not used and only the coordinates are appended with line.AddPoint(X, Y) . As earlier, a field is created to give the river a name. The actual line feature is again created as a child of the layer with line_feature = ogr.Feature(lyr.GetLayerDefn()) . Running this code block produces a line that approximately follows the Rhine River between France and Germany.

                            shp_dir              =              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/rhine_proxy.shp"              rhine_line              =              create_shp              (              shp_dir              ,              layer_name              =              "basemap"              ,              layer_type              =              "line"              )              # create .prj file for the shapefile for spider web application references              with              open              (              shp_dir              .              split              (              ".shp"              )[              0              ]              +              ".prj"              ,              "west+"              )              as              prj              :              prj              .              write              (              get_wkt              (              3857              ))              # go basemap layer              lyr              =              rhine_line              .              GetLayer              ()              # coordinates for EPSG:3857 WG84 / Pseudo-Mercator              station_names              =              {              "Basel"              :              (              844361.68              ,              6035047.42              ),              "Kembs"              :              (              835724.27              ,              6056449.76              ),              "Breisach"              :              (              842565.32              ,              6111140.43              ),              "Rhinau"              :              (              857547.04              ,              6158569.58              ),              "Strasbourg"              :              (              868439.31              ,              6203189.68              )}              # create line object and add points from station names              line              =              ogr              .              Geometry              (              ogr              .              wkbLineString              )              for              stn              in              station_names              .              values              ():              line              .              AddPoint              (              stn              [              0              ],              stn              [              1              ])              # create field named "rives"              field_name              =              ogr              .              FieldDefn              (              "river"              ,              ogr              .              OFTString              )              lyr              .              CreateField              (              field_name              )              # create feature, geometry, and field entry              line_feature              =              ogr              .              Characteristic              (              lyr              .              GetLayerDefn              ())              line_feature              .              SetGeometry              (              line              )              line_feature              .              SetField              (              "river"              ,              "Rhine"              )              # add together feature to layer              lyr              .              CreateFeature              (              line_feature              )              lyr              =              None              rhine_line              =              None            

The resulting rhine_proxy.shp shapefile tin be imported in QGIS forth with a DEM and the cities signal shapefile from the Natural Earth quick first kit.

img

Polygon Shapefile¶

Polygons are surface patches that can exist created indicate-past-bespeak, line-by-line, or from a "Multipolygon" WKB definition. When creating polygons from points or lines, we desire to create a surface and this is why the corresponding geometry type is chosen wkbLinearRing for building polygons from both points or lines (rather than wkbPoint or wkbLine , respectively). The post-obit lawmaking block features an example for building a polygon shapefile delineating the hydraulic laboratory of the University of Stuttgart. The departure between the above example for creating a line shapefile are:

  • The project is EPSG:4326 .

  • The point coordinates are generated within an ogr.wkbLinearRing object step-past-step rather than in a loop over dictionary entries.

  • File, variable, and field names.

                            shp_dir              =              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/iws_va.shp"              va_geo              =              create_shp              (              shp_dir              ,              layer_name              =              "basemap"              ,              layer_type              =              "polygon"              )              # create .prj file for the shapefile for GIS map applications              with              open              (              shp_dir              .              split              (              ".shp"              )[              0              ]              +              ".prj"              ,              "w+"              )              as              prj              :              prj              .              write              (              get_wkt              (              4326              ))              # get basemap layer              lyr              =              va_geo              .              GetLayer              ()              # create polygon points              pts              =              ogr              .              Geometry              (              ogr              .              wkbLinearRing              )              pts              .              AddPoint              (              9.103686              ,              48.744251              )              pts              .              AddPoint              (              9.104689              ,              48.744198              )              pts              .              AddPoint              (              9.104667              ,              48.743960              )              pts              .              AddPoint              (              9.103557              ,              48.744009              )              # create polygon geometry              poly              =              ogr              .              Geometry              (              ogr              .              wkbPolygon              )              # build polygon geometry from points              poly              .              AddGeometry              (              pts              )              # add together field to allocate building type              field              =              ogr              .              FieldDefn              (              "building"              ,              ogr              .              OFTString              )              lyr              .              CreateField              (              field              )              poly_feature_defn              =              lyr              .              GetLayerDefn              ()              poly_feature              =              ogr              .              Characteristic              (              poly_feature_defn              )              poly_feature              .              SetGeometry              (              poly              )              poly_feature              .              SetField              (              "edifice"              ,              "Versuchsanstalt"              )              lyr              .              CreateFeature              (              poly_feature              )              lyr              =              None              va_geo              =              None            

Build Shapefile from JSON¶

Loading geometry information from in-line defined variables is cumbersome in do, where geospatial information are often provided on public platforms (due east.g., land apply or cover). The following example uses a JSON file generated with map service data from the Baden-Württemberg State Institute for the Surroundings, Survey and Nature Conservation (LUBW), where polygon nodes are stored in WKB polygon geometry format ( "MultiPolygon (((node1_x node1_y, nodej_x, nodej_y, ... ...)))" ):

  • The JSON file (download hq100-dreisam.json and relieve it to a subdirectory called /geodata/json/ )is read with Pandas and the shapefile is created, as before, with the create_shp function.

  • The projection is EPSG:25832 .

  • 2 fields are added in the course of

    • "tbg_name" (the original cord name of the polygons in the LUBW data), and

    • "area" (a existent number field, in which the polygon area is calculated in m2 using polygon.GetArea() ).

  • The polygon geometries are derived from the WKB*formatted definitions in the "wkb_geom" field of the pandas dataframe object dreisam_inundation .

                            # become data from json file              dreisam_inundation              =              pd              .              read_json              (              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/json/hq100-dreisam.json"              )              # create shapefile              shp_dir              =              r              ""              +              os              .              path              .              abspath              (              ''              )              +              "/geodata/shapefiles/dreisam_hq100.shp"              dreisam_hq100              =              create_shp              (              shp_dir              ,              layer_name              =              "basemap"              ,              layer_type              =              "polygon"              )              # create .prj file for the shapefile for GIS map applications              with              open              (              shp_dir              .              split              (              ".shp"              )[              0              ]              +              ".prj"              ,              "due west+"              )              every bit              prj              :              prj              .              write              (              get_wkt              (              25832              ))              # get basemap layer              lyr              =              dreisam_hq100              .              GetLayer              ()              # add cord field "tbg_name"              lyr              .              CreateField              (              ogr              .              FieldDefn              (              "tbg_name"              ,              ogr              .              OFTString              ))              # add string field "surface area"              lyr              .              CreateField              (              ogr              .              FieldDefn              (              "area"              ,              ogr              .              OFTReal              ))              for              wkt              ,              tbg              in              zilch              (              dreisam_inundation              [              "wkt_geom"              ],              dreisam_inundation              [              "TBG_NAME"              ]):              # create Feature as child of the layer              characteristic              =              ogr              .              Characteristic              (              lyr              .              GetLayerDefn              ())              # assign tbg_name              feature              .              SetField              (              "tbg_name"              ,              tbg              )              # use WKT format to add a polygon geometry to the Feature              polygon              =              ogr              .              CreateGeometryFromWkt              (              wkt              )              # define default value of 0 to the area field              feature              .              SetField              (              "area"              ,              polygon              .              GetArea              ())              characteristic              .              SetGeometry              (              polygon              )              # append the new feature to the basement layer              lyr              .              CreateFeature              (              feature              )              lyr              =              None              dreisam_hq100              =              None            

Tip

Open the new dreisam_hq100.shp in QGIS and explore the attribute table.

Too GeoJSON data can be used to create an ogr.Geometry with ogr.createFromGeoJson(FILENAME) :

                                from                osgeo                import                ogr                geojson_data                =                """{"type":"Betoken","coordinates":[1013452.282805,6231540.674235]}"""                betoken                =                ogr                .                CreateGeometryFromJson                (                geojson_data                )                print                (                "Ten=                %d                , Y=                %d                                  (EPSG:3857)"                %                (                bespeak                .                GetX                (),                point                .                GetY                ()))              
                X=1013452, Y=6231540 (EPSG:3857)              

Calculate Geometric Attributes¶

The above code cake illustrates the usage of polygon.GetArea() to summate the polygon area in yard\(^2\). The ogr library provides many more functions to calculate geometric attributes of features and here is a summary:

  • Unify multiple polygons
    wkt_... = ...
    polygon_a = ogr.CreateGeometryFromWkt(wkt_1)
    polygon_b = ogr.CreateGeometryFromWkt(wkt_2)
    polygon_union = polygon_a.Marriage(polygon_b)

  • Intersect 2 polygons
    polygon_intersection = polygon_a.Intersection(polygon_b)

  • Envelope (minimum and maximum extents) of a polygon
    env = polygon.GetEnvelope()
    impress("minX: %d, minY: %d, maxX: %d, maxY: %d" % (env[0],env[ii],env[1],env[3])

  • Convex hull (envelope surface) of multiple geometries (points, lines, polygons)
    all_polygons = ogr.Geometry(ogr.wkbGeometryCollection)
    for feature in POLYGON-SOURCE-LAYER: all_polygons.AddGeometry(characteristic.GetGeometryRef())
    convexhull = all_polygons.ConvexHull()
    Save convexhull to shapefile (use the create_shp function equally shown in the higher up examples or read more at pcjerick's Github pages)
    Tip: To create a tight hull (e.thou., of a signal cloud), await for concavehull functions.

  • Length (of a line)
    wkt = "LINESTRING (415128.5 5320979.5, 415128.6 5320974.5, 415129.75 5320974.7)"
    line = ogr.CreateGeometryFromWkt(wkt)
    print("Length = %d" % line.Length())

  • Area (of a polygon): polygon.GetArea() (see above example)

  • Example to calculate centroid coordinates of polygons.

Of import

The units of the geometric attribute (e.g., chiliad\(^two\), U.S. anxiety, or others) are calculated based on the definitions in the .prj file <prjp> (remember the definition of projections in WKT format in the Projections and Coordinate Systems section).

Export to Other Formats¶

The higher up examples bargain with .shp files merely, but other formats can exist useful (e.g., to create spider web applications or export to Google Globe). To this end, the following paragraphs illustrate the creation of GeoJSON and KML files. Several other conversions can be performed, not only between file formats but also between feature types. For instance, polygons can exist created from point clouds (amidst others with the ConvexHull method mentioned above). Interested students can larn more virtually conversions in Michael Diener's Python Geospatial Analysis Cookbook.

GeoJSON¶

GeoJSON files can be easily created as before, even without activating a commuter:

                                triangle                =                ogr                .                Geometry                (                ogr                .                wkbLinearRing                )                triangle                .                AddPoint                (                -                11717151.498691                ,                2356192.894805                )                triangle                .                AddPoint                (                -                11717120.446149                ,                2355586.175893                )                triangle                .                AddPoint                (                -                11719392.059083                ,                2354012.050842                )                polygon                =                ogr                .                Geometry                (                ogr                .                wkbPolygon                )                polygon                .                AddGeometry                (                triangle                )                with                open up                (                r                ""                +                os                .                path                .                abspath                (                ''                )                +                "/geodata/geojson/pitillal-triangle.geojson"                ,                "w+"                )                every bit                gjson                :                gjson                .                write                (                polygon                .                ExportToJson                ())              

For more than robust file treatment and defining a projection, activate the driver ogr.GetDriverByName("GeoJSON") . Thus, the creation and manipulation of GeoJSON files work similarly to the shapefile handlers shown above.

                                gjson_driver                =                ogr                .                GetDriverByName                (                "GeoJSON"                )                # make spatial reference                sr                =                osr                .                SpatialReference                ()                sr                .                ImportFromEPSG                (                3857                )                # create GeoJSON file                gjson                =                gjson_driver                .                CreateDataSource                (                "pitillal-full.geojson"                )                gjson_lyr                =                gjson                .                CreateLayer                (                "pitillal-full.geojson"                ,                geom_type                =                ogr                .                wkbPolygon                ,                srs                =                sr                )                # get layer feature definitions                feature_def                =                gjson_lyr                .                GetLayerDefn                ()                # create new characteristic                new_feature                =                ogr                .                Feature                (                feature_def                )                # assign the triangle from the above code cake                new_feature                .                SetGeometry                (                polygon                )                # add together new feature to Layer                gjson_lyr                .                CreateFeature                (                new_feature                )                # shut links to data sources                gjson                =                None                gjson_lyr                =                None              

KML (Google Earth)¶

To display bespeak, line, or polygon features in Google Globe, features can be plugged into Google's KML (Keyhole Markup Language), similar to the creation of a GeoJSON file, and with the office geometry.ExportToKML :

                                triangle                =                ogr                .                Geometry                (                ogr                .                wkbLinearRing                )                triangle                .                AddPoint                (                -                11717151.498691                ,                2356192.894805                )                triangle                .                AddPoint                (                -                11717120.446149                ,                2355586.175893                )                triangle                .                AddPoint                (                -                11719392.059083                ,                2354012.050842                )                polygon                =                ogr                .                Geometry                (                ogr                .                wkbPolygon                )                polygon                .                AddGeometry                (                triangle                )                #geojson = poly.ExportToJson()                with                open                (                r                ""                +                os                .                path                .                abspath                (                ""                )                +                "/geodata/pitillal-triangle.kml"                ,                "w+"                )                as                gjson                :                gjson                .                write                (                polygon                .                ExportToKML                ())              

Moreover, similar to GeoJSON files and shapefiles, KML files can be generated more robustly (with a defined project, for example). All you need to do is initiating the KML commuter ( kml_driver = ogr.GetDriverByName("KML") ) and ascertain a KML data source ( kml_file = kml_driver.CreateDataSource(FILENAME.KML) ).

Read Field Values of a Shapefile Gdal

Source: https://hydro-informatics.com/jupyter/geo-shp.html