Reputation: 7245
I have a geotiff file.
import xarray as xr
urbanData = xr.open_rasterio('myGeotiff.tif')
plt.imshow(urbanData)
Here the link to the file.
I can convert the file as a dataframe with coordinates as points
ur = xr.DataArray(urbanData, name='myData')
ur = ur.to_dataframe().reset_index()
gdfur = gpd.GeoDataFrame(ur, geometry=gpd.points_from_xy(ur.x, ur.y))
However I would like to get a dataframe that contains the geometry of the pixels as polygons and not as points. Is it possible?
Upvotes: 3
Views: 5008
Reputation: 711
With geocube 0.4+:
import rioxarray
from geocube.vector import vectorize
data = rioxarray.open_rasterio("myGeotiff.tif").squeeze()
data.name = "myData"
gdf = vectorize(data)
Upvotes: 0
Reputation: 481
Somewhat to my surprise, I haven't really found a package which wrap rasterio.features
to take DataArrays and produce GeoDataFrames.
These might be very useful though:
https://corteva.github.io/geocube/stable/
https://corteva.github.io/rioxarray/stable/
I generally use something like this:
import affine
import geopandas as gpd
import rasterio.features
import xarray as xr
import shapely.geometry as sg
def polygonize(da: xr.DataArray) -> gpd.GeoDataFrame:
"""
Polygonize a 2D-DataArray into a GeoDataFrame of polygons.
Parameters
----------
da : xr.DataArray
Returns
-------
polygonized : geopandas.GeoDataFrame
"""
if da.dims != ("y", "x"):
raise ValueError('Dimensions must be ("y", "x")')
values = da.values
transform = da.attrs.get("transform", None)
if transform is None:
raise ValueError("transform is required in da.attrs")
transform = affine.Affine(*transform)
shapes = rasterio.features.shapes(values, transform=transform)
geometries = []
colvalues = []
for (geom, colval) in shapes:
geometries.append(sg.Polygon(geom["coordinates"][0]))
colvalues.append(colval)
gdf = gpd.GeoDataFrame({"value": colvalues, "geometry": geometries})
gdf.crs = da.attrs.get("crs")
return gdf
Note that you should squeeze the band dimensions from your xarray first to make it 2D, after reading it with xr.open_rasterio
:
urbanData = xr.open_rasterio('myGeotiff.tif').squeeze('band', drop=True)
Upvotes: 2