Animate grid count with GeoPandas

Viewed 263

I'm trying to incorporate the following code into an animation. The data below is a workable example. I'm working with has both date and time as the timestamp.

I'm currently plotting count as a heat map. I'm hoping to use the timestamp column to display the variation of this count over time.

gdf_area = gpd.read_file('https://raw.githubusercontent.com/openpolis/geojson-italy/master/geojson/limits_IT_municipalities.geojson')#.loc[:, ["geometry"]]

BOXES = 50
a, b, c, d = gdf_area.total_bounds

gdf_grid = gpd.GeoDataFrame(
    geometry=[
        shapely.geometry.box(minx, miny, maxx, maxy)
        for minx, maxx in zip(np.linspace(a, c, BOXES), np.linspace(a, c, BOXES)[1:])
        for miny, maxy in zip(np.linspace(b, d, BOXES), np.linspace(b, d, BOXES)[1:])
    ],
    crs="epsg:4326",
)

gdf_grid.insert(0, 'timestamp', range(0, 0 + len(gdf_grid)))

# total area for the grid
xmin, ymin, xmax, ymax = gdf_grid.total_bounds

# how many cells across and down
n_cells = 30
cell_size = (xmax-xmin)/n_cells

# create the cells in a loop
grid_cells = []
for x0 in np.arange(xmin, xmax+cell_size, cell_size ):
        for y0 in np.arange(ymin, ymax+cell_size, cell_size):
            # bounds
            x1 = x0-cell_size
            y1 = y0+cell_size
            grid_cells.append(shapely.geometry.box(x0, y0, x1, y1))
        
cell = gpd.GeoDataFrame(grid_cells, columns = ['geometry'], crs = 'EPSG:4326')

merged = gpd.sjoin(gdf_grid, cell, how='left', predicate='within')

# make a simple count variable that we can sum
merged['gridCount'] = 1

# Compute stats per grid cell -- aggregate fires to grid cells with dissolve
dissolve = merged.dissolve(by = 'index_right', aggfunc = 'count')

# put this into cell
cell.loc[dissolve.index, 'gridCount'] = dissolve['gridCount'].values

fig, ax = plt.subplots()

im = cell.plot(column = 'gridCount', 
               cmap = 'viridis_r', 
               #vmax = 1000,
               alpha = 0.5,
               edgecolor = 'grey')

def animate(data):

    im.set_data(data)

    return im

anim = animation.FuncAnimation(fig, animate, frames = 10,
                               interval=50)

Output:

AttributeError: 'AxesSubplot' object has no attribute 'set_data'
1 Answers

I am not sure about the timestamp, but for the animate function you could call cell.plot() with the ax parameter set to your ax. The following created a animated gif with randomly generated gridCount values. You can adapt this code to generate the gridCount values based on the data parameter of the animate function.

from random import randint

import geopandas as gpd
import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
import shapely


gdf_area = gpd.read_file('https://raw.githubusercontent.com/openpolis/geojson-italy/master/geojson/limits_IT_municipalities.geojson')

BOXES = 50
a, b, c, d = gdf_area.total_bounds

gdf_grid = gpd.GeoDataFrame(
    geometry=[
        shapely.geometry.box(minx, miny, maxx, maxy)
        for minx, maxx in zip(np.linspace(a, c, BOXES), np.linspace(a, c, BOXES)[1:])
        for miny, maxy in zip(np.linspace(b, d, BOXES), np.linspace(b, d, BOXES)[1:])
    ],
    crs="epsg:4326",
)

# total area for the grid
xmin, ymin, xmax, ymax = gdf_grid.total_bounds

# how many cells across and down
n_cells = 30
cell_size = (xmax-xmin)/n_cells

# create the cells in a loop
grid_cells = []
for x0 in np.arange(xmin, xmax+cell_size, cell_size ):
        for y0 in np.arange(ymin, ymax+cell_size, cell_size):
            # bounds
            x1 = x0-cell_size
            y1 = y0+cell_size
            grid_cells.append(shapely.geometry.box(x0, y0, x1, y1))
cell = gpd.GeoDataFrame(grid_cells, columns = ['geometry'], crs = 'EPSG:4326')


fig = plt.figure()
ax = plt.axes()

def animate(data):
    cell['gridCount'] = [randint(1,10) for _ in range(0, len(cell))] 
    im = cell.plot(
        'gridCount', 
        cmap = 'viridis_r',         
        alpha = 0.5,
        edgecolor = 'grey',
        ax=ax,
    )
    return im

anim = animation.FuncAnimation(fig, animate,  frames = 10, interval=50)
anim.save('map.gif', writer='imagemagick')

Output:

random map animation

Related