Source code for gazar.shape

# -*- coding: utf-8 -*-
#
#  gazar.shape
#
#  Author : Alan D Snow, 2017.
#  License: BSD 3-Clause

"""gazar.shape
This module is a collection of GDAL functions for shapefiles.
Documentation can be found at `_gazar Documentation HOWTO`_.

.. _gazar Documentation HOWTO:
   https://github.com/snowman2/gazar

"""
# default modules
from os import path
# external modules
from osgeo import gdal, ogr, osr
# local modules
from .grid import (GDALGrid, load_raster, project_to_geographic,
                   utm_proj_from_latlon)


[docs]def reproject_layer(in_path, out_path, out_spatial_ref): """ Reprojects a shapefile layer. Based on: https://pcjericks.github.io/ py-gdalogr-cookbook/projection.html Parameters ---------- in_path: :obj:`str` The path to the input shapefile layer. out_path: :obj:`str` The path to the output shapefile layer. out_spatial_ref: :func:`osr.SpatialReference` The output spatial reference. """ driver = ogr.GetDriverByName('ESRI Shapefile') # get the input layer in_data_set = driver.Open(in_path) in_layer = in_data_set.GetLayer() # input SpatialReference in_spatial_ref = in_layer.GetSpatialRef() # create the CoordinateTransformation coord_trans = osr.CoordinateTransformation(in_spatial_ref, out_spatial_ref) # create the output layer output_shapefile = out_path if path.exists(output_shapefile): driver.DeleteDataSource(output_shapefile) out_data_set = driver.CreateDataSource(output_shapefile) out_layer = out_data_set.CreateLayer("", geom_type=ogr.wkbMultiPolygon) # add fields in_layer_defn = in_layer.GetLayerDefn() for i in range(0, in_layer_defn.GetFieldCount()): field_defn = in_layer_defn.GetFieldDefn(i) out_layer.CreateField(field_defn) # get the output layer's feature definition out_layer_defn = out_layer.GetLayerDefn() # loop through the input features in_feature = in_layer.GetNextFeature() while in_feature: # get the input geometry geom = in_feature.GetGeometryRef() # reproject the geometry geom.Transform(coord_trans) # create a new feature out_feature = ogr.Feature(out_layer_defn) # set the geometry and attribute out_feature.SetGeometry(geom) for i in range(0, out_layer_defn.GetFieldCount()): out_feature.SetField(out_layer_defn.GetFieldDefn(i).GetNameRef(), in_feature.GetField(i)) # add the feature to the shapefile out_layer.CreateFeature(out_feature) # dereference the features and get the next input feature out_feature = None in_feature = in_layer.GetNextFeature() # Save and close the shapefiles in_data_set = None out_data_set = None # write projection shapefile_basename = path.splitext(out_path)[0] projection_file_name = "{shapefile_basename}.prj" \ .format(shapefile_basename=shapefile_basename) with open(projection_file_name, 'w') as prj_file: prj_file.write(out_spatial_ref.ExportToWkt()) prj_file.close()
[docs]def rasterize_shapefile(shapefile_path, out_raster_path=None, shapefile_attribute=None, x_cell_size=None, y_cell_size=None, x_num_cells=None, y_num_cells=None, match_grid=None, raster_wkt_proj=None, convert_to_utm=False, raster_dtype=gdal.GDT_Int32, raster_nodata=-9999, as_gdal_grid=False): """ Convert shapefile to raster from specified attribute Parameters ---------- shapefile_path : :obj:`str` Path to shapefile. out_raster_path : :obj:`str`, optional Path to raster to be generated. shapefile_attribute: :obj:`str`, optional Attribute to be rasterized. x_cell_size: float, optional Longitude cell size in output projection. y_cell_size: float, optional Latitude cell size in output projection. x_num_cells: int, optional Number of cells in latitude. y_num_cells: int, optional Number of cells in longitude. match_grid: str or :func:`gdal.Dataset` or :func:`~GDALGrid`, optional Grid to match for output. raster_wkt_proj: :obj:`str`, optional WKT projections string for output grid. convert_to_utm: bool, optional Convert grid to UTM automatically. Default is False. raster_dtype: :func:`osgeo.gdalconst` Output grid datatype (GDT). Default is gdal.GDT_Int32. raster_nodata: float or int, optional No data value for output raster. Default is -9999, as_gdal_grid: bool, optional Return as :func:`~GDALGrid`. Default is False. Returns ------- None or :func:`~GDALGrid` It will return :func:`~GDALGrid` if `as_gdal_grid` is True. Otherwise, it will not return anything. Example Default:: from gloot.grid import rasterize_shapefile shapefile_path = 'shapefile.shp' new_grid = 'new_grid.tif' rasterize_shapefile(shapefile_path, new_grid, x_num_cells=50, y_num_cells=50, raster_nodata=0, ) Example GDALGrid to ASCII with UTM:: from gazar.grid import rasterize_shapefile shapefile_path = 'shapefile.shp' new_grid = 'new_grid.asc' gr = rasterize_shapefile(shapefile_path, x_num_cells=50, y_num_cells=50, raster_nodata=0, convert_to_utm=True, as_gdal_grid=True, ) gr.to_grass_ascii(new_grid, print_nodata=False) """ if as_gdal_grid: raster_driver = gdal.GetDriverByName('MEM') out_raster_path = '' elif out_raster_path is not None: raster_driver = gdal.GetDriverByName('GTiff') else: raise ValueError("Either out_raster_path or as_gdal_grid " "need to be set ...") # open the data source shapefile = ogr.Open(shapefile_path) source_layer = shapefile.GetLayer(0) x_min, x_max, y_min, y_max = source_layer.GetExtent() shapefile_spatial_ref = source_layer.GetSpatialRef() reprojected_layer = None # determine UTM projection from centroid of shapefile if convert_to_utm: # Make sure projected into global projection lon_min, lat_max = project_to_geographic(x_min, y_max, shapefile_spatial_ref) lon_max, lat_min = project_to_geographic(x_max, y_min, shapefile_spatial_ref) # get UTM projection for watershed raster_wkt_proj = utm_proj_from_latlon((lat_min + lat_max) / 2.0, (lon_min + lon_max) / 2.0, as_wkt=True) # reproject shapefile to new projection if raster_wkt_proj is not None: shapefile_basename = path.splitext(shapefile_path)[0] reprojected_layer = "{shapefile_basename}_projected.shp" \ .format(shapefile_basename=shapefile_basename) out_spatial_ref = osr.SpatialReference() out_spatial_ref.ImportFromWkt(raster_wkt_proj) reproject_layer(shapefile_path, reprojected_layer, out_spatial_ref) reprojected_shapefile = ogr.Open(reprojected_layer) source_layer = reprojected_shapefile.GetLayer(0) x_min, x_max, y_min, y_max = source_layer.GetExtent() shapefile_spatial_ref = source_layer.GetSpatialRef() if match_grid is not None: # grid to match match_ds, match_proj = load_raster(match_grid) match_geotrans = match_ds.GetGeoTransform() x_num_cells = match_ds.RasterXSize y_num_cells = match_ds.RasterYSize elif x_cell_size is not None and y_cell_size is not None: # caluclate nuber of cells in extent x_num_cells = int((x_max - x_min) / x_cell_size) y_num_cells = int((y_max - y_min) / y_cell_size) match_geotrans = (x_min, x_cell_size, 0, y_max, 0, -y_cell_size) match_proj = shapefile_spatial_ref.ExportToWkt() elif x_num_cells is not None and y_num_cells is not None: x_cell_size = (x_max - x_min) / float(x_num_cells) y_cell_size = (y_max - y_min) / float(y_num_cells) match_geotrans = (x_min, x_cell_size, 0, y_max, 0, -y_cell_size) match_proj = shapefile_spatial_ref.ExportToWkt() else: raise ValueError("Invalid parameters for output grid entered ...") # geotiff target_ds = raster_driver.Create(out_raster_path, x_num_cells, y_num_cells, 1, raster_dtype) target_ds.SetGeoTransform(match_geotrans) target_ds.SetProjection(match_proj) band = target_ds.GetRasterBand(1) band.SetNoDataValue(raster_nodata) # rasterize if shapefile_attribute is not None: err = gdal.RasterizeLayer(target_ds, [1], source_layer, options=["ATTRIBUTE={0}" .format(shapefile_attribute)]) else: err = gdal.RasterizeLayer(target_ds, [1], source_layer, burn_values=[1]) if err != 0: raise Exception("Error rasterizing layer: %s" % err) if raster_wkt_proj is not None and raster_wkt_proj != match_proj: # from http://gis.stackexchange.com/questions/139906/ # replicating-result-of-gdalwarp-using-gdal-python-bindings""" error_threshold = 0.125 # use same value as in gdalwarp resampling = gdal.GRA_NearestNeighbour # Call AutoCreateWarpedVRT() to fetch default values # for target raster dimensions and geotransform target_ds = gdal.AutoCreateWarpedVRT(target_ds, None, raster_wkt_proj, resampling, error_threshold) if not as_gdal_grid: # Create the final warped raster target_ds = gdal.GetDriverByName('GTiff') \ .CreateCopy(out_raster_path, target_ds) # clean up if reprojected_layer is not None: driver = ogr.GetDriverByName("ESRI Shapefile") if path.exists(reprojected_layer): driver.DeleteDataSource(reprojected_layer) if as_gdal_grid: return GDALGrid(target_ds)