Grid Manipulations (merge, split, refine, transform)

Notes

Most grid transformations such as merge and transpose return a new object, allowing consecutive operations to be chained together. Optionally, you can pass inplace=True to the call signature to modify the existing object and return None. Both approaches are demonstrated below.

In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas
from shapely.geometry import Point, Polygon
import geopandas

import pygridgen as pgg
import pygridtools as pgt

Basic merging operations

The function below create our 3 test model grids moving counter-clockwise in the figure shown two cells down.

In [2]:
def to_gdf(df):

    return (
        df.assign(geometry=df.apply(lambda r: Point(r.x, r.y), axis=1))
          .drop(columns=['x', 'y'])
          .pipe(geopandas.GeoDataFrame)
    )


def make_test_grids():
    domain1 = pandas.DataFrame({'x': [2, 5, 5, 2], 'y': [6, 6, 4, 4], 'beta': [1, 1, 1, 1]})
    domain2 = pandas.DataFrame({'x': [6, 11, 11, 5], 'y': [5, 5, 3, 3], 'beta': [1, 1, 1, 1]})
    domain3 = pandas.DataFrame({'x': [7, 9, 9, 7], 'y': [2, 2, 0, 0], 'beta': [1, 1, 1, 1]})

    grid1 = pgt.make_grid(domain=to_gdf(domain1), nx=6, ny=5, rawgrid=False)
    grid2 = pgt.make_grid(domain=to_gdf(domain2), nx=8, ny=7, rawgrid=False)
    grid3 = pgt.make_grid(domain=to_gdf(domain3), nx=4, ny=10, rawgrid=False)

    return grid1, grid2, grid3

Display positions of grids relative to each other

In [3]:
grid1, grid2, grid3 = make_test_grids()

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = grid1.plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
_ = grid2.plot_cells(ax=ax, cell_kws=dict(cmap='Greens'))
_ = grid3.plot_cells(ax=ax, cell_kws=dict(cmap='Reds'))
../_images/tutorial_03_MergingSpliting_5_0.png

Merge grids 1 and 2 together, horizontally

By default, the bottom rows are aligned and the cell mask is not updated. We do that manually for now.

In [4]:
one_two = grid1.merge(grid2, how='horiz')
fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = one_two.plot_cells(ax=ax, cell_kws=dict(cmap='BuPu'))
_ = grid3.plot_cells(ax=ax, cell_kws=dict(cmap='Reds'))
../_images/tutorial_03_MergingSpliting_7_0.png

Use the shift parameter to center grid 2

Use shift=-1 since we’re sliding grid 2’s i-j indexes downward relative to grid 1

In [5]:
one_two = grid1.merge(grid2, how='horiz', shift=-1)

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = one_two.plot_cells(ax=ax, cell_kws=dict(cmap='BuPu'))
_ = grid3.plot_cells(ax=ax, cell_kws=dict(cmap='Reds'))
../_images/tutorial_03_MergingSpliting_9_0.png

Vertically merge grid 2 and grid 3

Notice that by default, the grids are left-aligned and the bottom of grid 3 ties into the top of grid 2

In [6]:
two_three = grid2.merge(grid3, how='vert', shift=2)
fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = grid1.plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
_ = two_three.plot_cells(ax=ax, cell_kws=dict(cmap='YlOrBr'))
../_images/tutorial_03_MergingSpliting_11_0.png

Try again, switching the order of the grids

Notice the change in sign of the shift parameter.

In [7]:
two_three = grid3.merge(grid2, how='vert', shift=-2)

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = grid1.plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
_ = two_three.plot_cells(ax=ax, cell_kws=dict(cmap='YlOrBr'))
../_images/tutorial_03_MergingSpliting_13_0.png

Alternatively, you can switch the arguments and use where='-' to indicate that the “other” grid is below the first.

And the sign of the shift parameter returns to its original value.

In [8]:
two_three = grid2.merge(grid3, how='vert', where='-', shift=2)

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = grid1.plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
_ = two_three.plot_cells(ax=ax, cell_kws=dict(cmap='YlOrBr'))
../_images/tutorial_03_MergingSpliting_15_0.png

Now merge all three in a single chained operation (inplace=False).

In [9]:
grid1, grid2, grid3 = make_test_grids()
all_grids = (
    grid2.merge(grid3, how='vert', where='-', shift=2)
         .merge(grid1, how='horiz', where='-', shift=11)
)

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = all_grids.plot_cells(ax=ax, cell_kws=dict(cmap='GnBu'))
../_images/tutorial_03_MergingSpliting_17_0.png

Split the final grid into two vertical parts

grid.split(<index of split>, axis=0)

In [10]:
grid_bottom, grid_top = all_grids.split(14, axis=0)

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = grid_bottom.plot_cells(ax=ax, cell_kws=dict(cmap='OrRd'))
_ = grid_top.plot_cells(ax=ax, cell_kws=dict(cmap='BuPu'))
../_images/tutorial_03_MergingSpliting_19_0.png

Splitting and linearly refining columns and rows

Split the final grid into two horizontal parts

grid.split(<index of split>, axis=1)

In [11]:
grid_left, grid_right = all_grids.split(8, axis=1)

fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = grid_left.plot_cells(ax=ax, cell_kws=dict(cmap='Oranges'))
_ = grid_right.plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
../_images/tutorial_03_MergingSpliting_21_0.png

Refine individual rows of the grid cells

grid.refine(<index of cell>, axis=0, n_points=<num. of divisions>)

In [12]:
fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = (
    all_grids
        .insert(13, axis=0, n_nodes=2)
        .plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
)
../_images/tutorial_03_MergingSpliting_23_0.png

Refine individual columns of the grid cells

grid.refine(<index of cell>, axis=1, n_points=<num. of divisions>)

In [13]:
fig, ax = plt.subplots(figsize=(7.5, 7.5))
_ = (
    all_grids
        .insert(10, axis=1, n_nodes=4)
        .plot_cells(ax=ax, cell_kws=dict(cmap='Blues'))
)
../_images/tutorial_03_MergingSpliting_25_0.png

Chained operations

One big chained operation for fun

In [14]:
def make_fake_bathy(grid):
    j_cells, i_cells = grid.cell_shape
    y, x = np.mgrid[:j_cells, :i_cells]
    z = (y - (j_cells // 2))** 2 - x
    return z


fig, ax = plt.subplots(figsize=(7.5, 7.5))

g = (
  grid2.merge(grid3, how='vert', where='-', shift=2)
       .merge(grid1, how='horiz', where='-', shift=11)
       .insert(10, axis=1, n_nodes=4)
       .insert(13, axis=0, n_nodes=2)
       .transform(lambda x: x*5 + 2)
)

bathy = make_fake_bathy(g)
_ = g.plot_cells(ax=ax, cell_kws=dict(cmap='Blues', colors=bathy))
../_images/tutorial_03_MergingSpliting_27_0.png