Spatial weights are used across `momepy`

. This notebook will illustrate its use on three examples.

```
import momepy
import geopandas as gpd
import matplotlib.pyplot as plt
```

We will again use `osmnx`

to get the data for our example and after preprocessing of building layer will generate tessellation layer.

```
import osmnx as ox
gdf = ox.footprints.footprints_from_place(place='Kahla, Germany')
gdf_projected = ox.project_gdf(gdf)
buildings = momepy.preprocess(gdf_projected, size=30,
compactness=True, islands=True)
buildings['uID'] = momepy.unique_id(buildings)
limit = momepy.buffered_limit(buildings)
tessellation = momepy.Tessellation(buildings, unique_id='uID', limit=limit).tessellation
```

## First order contiguity

### Distance to neighbours

To calculate the mean distance to neighbouring buildings, we need queen contiguity weights of the first order capturing the relationship between immediate neighbours. Relationship between buildings is here represented by relationships between their tessellation cells.

```
sw1 = momepy.sw_high(k=1, gdf=tessellation, ids='uID')
```

```
buildings['neighbour_dist'] = momepy.NeighborDistance(buildings, sw1, 'uID').series
```

**Note:** If there is no neighbour for a building denoted in `spatial_weights`

, the value is set to `np.nan`

. In GeoPandas older than 0.7.0, rows with NaN have to be removed before plotting with natural breaks scheme.

```
buildings = buildings.dropna(subset=['neighbour_dist'])
```

```
f, ax = plt.subplots(figsize=(10, 10))
buildings.plot(ax=ax, column='neighbour_dist', scheme='naturalbreaks', k=15, legend=True, cmap='Spectral')
ax.set_axis_off()
plt.show()
```

## Higher order / distance

However, typical usage of spatial weights is to capture the vicinity of each feature. As illustrated in the previous notebook, there are multiple options on how to capture it. In this example, we will use queen contiguity of the higher order (3) based on morphological tessellation.

```
sw3 = momepy.sw_high(k=3, gdf=tessellation, ids='uID')
```

```
areas = momepy.Area(tessellation).series
mean_area = momepy.AverageCharacter(
tessellation, values=areas, spatial_weights=sw3, unique_id='uID')
tessellation['mean_area'] = mean_area.mean
```

```
f, ax = plt.subplots(figsize=(10, 10))
tessellation.plot(ax=ax, column='mean_area', legend=True, scheme='quantiles', k=15, cmap='Blues_r')
buildings.plot(ax=ax, color="white", alpha=0.4)
ax.set_axis_off()
plt.show()
```

In some cases, we might want to eliminate the effect of outliers. To do so, we can specify the range on which should `AverageCharacter`

calculate mean. Below we will measure only interquartile mean.

```
tessellation['mean_area_iq'] = momepy.AverageCharacter(
tessellation, areas, sw3, 'uID', rng=(25, 75)).mean
```

```
f, ax = plt.subplots(figsize=(10, 10))
tessellation.plot(ax=ax, column='mean_area_iq', legend=True, scheme='quantiles', k=15, cmap='Greens_r')
buildings.plot(ax=ax, color="white", alpha=0.4)
ax.set_axis_off()
plt.show()
```

Another option would be to calculate median only:

```
tessellation['med_area'] = momepy.AverageCharacter(
tessellation, areas, sw3, 'uID', mode='median').median
```

```
f, ax = plt.subplots(figsize=(10, 10))
tessellation.plot(ax=ax, column='med_area', legend=True, scheme='quantiles', k=15, cmap='Purples_r')
buildings.plot(ax=ax, color="white", alpha=0.4)
ax.set_axis_off()
plt.show()
```

```
circular_compactness = momepy.CircularCompactness(buildings)
buildings['weighted_circom'] = momepy.WeightedCharacter(
buildings, circular_compactness.series, sw3, 'uID', momepy.Area(buildings).series).series
```

```
f, ax = plt.subplots(figsize=(10, 10))
buildings.plot(ax=ax, column='weighted_circom', legend=True, scheme='quantiles', k=15, cmap='viridis')
ax.set_axis_off()
plt.show()
```

```
point = (40.731603, -73.977857)
dist = 1000
gdf = ox.footprints.footprints_from_point(point=point, distance=dist)
gdf_projected = ox.project_gdf(gdf)
buildings = momepy.preprocess(gdf_projected, size=30,
compactness=True, islands=True)
buildings['uID'] = momepy.unique_id(buildings)
limit = momepy.buffered_limit(buildings)
tessellation = momepy.Tessellation(buildings, unique_id='uID', limit=limit).tessellation
```

```
f, ax = plt.subplots(figsize=(10, 10))
tessellation.plot(ax=ax)
buildings.plot(ax=ax, color='white', alpha=.5)
ax.set_axis_off()
plt.show()
```

To get gross density, we need to know floor areas:

```
buildings['height'] = buildings['height'].fillna(0).astype(float)
buildings['floor_area'] = momepy.FloorArea(buildings, 'height').series
```

Now we merge floor areas to tessellation based on shared unique ID and generate spatial weights.

```
tessellation = tessellation.merge(buildings[['uID', 'floor_area']])
sw = momepy.sw_high(k=3, gdf=tessellation, ids='uID')
```

`Density`

is then following the same principle as illustrated above.

```
gross = momepy.Density(
tessellation, values='floor_area', spatial_weights=sw, unique_id='uID')
tessellation['gross_density'] = gross.series
```

```
f, ax = plt.subplots(figsize=(10, 10))
tessellation.plot(ax=ax, column='gross_density', legend=True, scheme='naturalbreaks', k=15)
buildings.plot(ax=ax, color='white', alpha=.5)
ax.set_axis_off()
plt.show()
```

In a similar way can be done gross coverage.

```
buildings['area'] = momepy.Area(buildings).series
tessellation = tessellation.merge(buildings[['uID', 'area']])
```

```
coverage = momepy.Density(
tessellation, values='area', spatial_weights=sw, unique_id='uID')
tessellation['gross_coverage'] = coverage.series
```

```
f, ax = plt.subplots(figsize=(10, 10))
tessellation.plot(ax=ax, column='gross_coverage', legend=True)
buildings.plot(ax=ax, color='white', alpha=.5)
ax.set_axis_off()
plt.show()
```