Today I needed to convert raster to a shapefile with rectangular polygons representing each pixel of the raster in Python, including the pixels with value 0.

Related questions:

Solution attempt

I could not find an existing solution and so I wrote my own hacky solution using rasterio, shapely, and geopandas.

I am assuming that I know the raster file is in epsg:4326.

First import the libraries

import itertools
import rasterio
from shapely.geometry import box
import geopandas as gpd

Create rectangles using shapely

with rasterio.open(sample_raster) as dataset:
    data = dataset.read(1)

    t = dataset.transform

    move_x = t[0]
    # t[4] is negative, as raster start upper left 0,0 and goes down
    # later for steps calculation (ymin=...) we use plus instead of minus
    move_y = t[4]

    height = dataset.height
    width = dataset.width 

    polygons = []
    indices = list(itertools.product(range(width), range(height)))
    for x,y in indices:
        x_min, y_max = t * (x,y)
        x_max = x_min + move_x
        y_min = y_max + move_y
        polygons.append(box(x_min, y_min, x_max, y_max))

Extract the data

data_list = []
for x,y in indices:

Combine in a GeoDataFrame using geopandas

gdf = gpd.GeoDataFrame(data=data_list, crs={'init':'epsg:4236'}, geometry=polygons, columns=['value'])


This is a quick solution and I suspect not ideal. I have two questions

1) Is this solution correct? Are there some obvious or necessary improvements?

2) Is there a quicker / standard way to do this? Perhaps I have missed some library, or a function.

  • Q2 - There is not a standard way to do this. Raster and vector models are optimised for different types of data, raster tools handle this type of data easily, it is a mammoth task for vector tools.
    – vinh
    Jul 22 '19 at 16:03
  • Q1 - EPSG:4326 is longitude / latitude, an so is not projected. This may lead to some very odd effects at larger scales. For example, the pixels in this CRS are not squares.
    – vinh
    Jul 22 '19 at 16:05
  • @vinh Q1 sounds very interesting and possibly reveals a hole in my understanding. Could you elaborate on why that is the case, specifically how a 4326 raster pixel isn't a 'square' in lon/lat? I understand it would not be a square if projected, but not why it's not a square/rectangle when represented as a vector in 4326.
    – Dahn
    Jul 22 '19 at 16:18
  • Have a read of this question: gis.stackexchange.com/questions/711/…
    – vinh
    Jul 22 '19 at 16:23
  • @vinh Thanks. I understand that a rectangle of the "same size" in 4326 is actually of different real area depending on its location on earth. I do not see how that relates to representing raster pixels as vector polygons though.
    – Dahn
    Jul 22 '19 at 16:41