User-defined functions: summarizing noise data

This example works with a model of sound levels for the United States produced by the US National Park Service. We want to compute the average noise level for each municipality in Hawaii, but the standard mean operation provided by exactextract is not appropriate for the logarithmic decibel scale used for sound levels.

To avoid working with large data files, we use the sound level grid provided for Hawaii, along with the TIGER shapefile of 2023 municipal boundaries (“county subdivisions”) published by the US Census Bureau:

[1]:
sound_fname = 'hawaii/HI_L50dBA_sumDay_exi.tif'
municipalities_fname = 'hawaii/tl_2023_15_cousub.zip'

The sound boundaries are published in UTM 4N (meters), while the municipal boundaries use NAD 1983 geographic coordinates. Rather than pass the filenames to exact_extract, we will first load the datasets and reproject the municipal boundaries to the UTM coordinate system used by the sound grid.

[2]:
from exactextract import exact_extract
from matplotlib import pyplot
import rasterio
import rasterio.plot
import geopandas as gpd

sound_ds = rasterio.open(sound_fname)
municipalities = gpd.read_file(municipalities_fname).to_crs(sound_ds.crs)

fig, ax = pyplot.subplots()
ax.set_xlim([0.3e6, 1.0e6])
ax.set_ylim([2.0e6, 2.5e6])

rasterio.plot.show(sound_ds, ax=ax)
municipalities.plot(ax=ax, facecolor='none', edgecolor='black', linewidth=0.2)
[2]:
<Axes: >
_images/noise_average_udf_3_1.png

The following function can be used to compute the mean sound levels:

[3]:
import numpy as np

def mean_sound_db(values, coverage):
    # transform values, take average, transform result
    values = np.power(10, values)
    mean = np.average(values, weights=coverage)
    return np.log10(mean)

The user-defined function can now be used in the same way as a built-in summary operation. Unsurprisingly, we see that Honolulu is the loudest municipality in Hawaii.

[4]:
results = exact_extract(sound_ds, municipalities, mean_sound_db, include_cols=['GEOID', 'NAME'], output='pandas')
results.sort_values(by=['mean_sound_db'], ascending=False)
[4]:
GEOID NAME mean_sound_db
11 1500390810 Honolulu 50.403354
33 1500390270 Ewa 49.420535
34 1500990900 Kahului 49.416380
32 1500393420 Wahiawa 49.414049
13 1500391800 Koolaupoko 48.554184
5 1500993060 Puunene 47.855280
37 1500993870 Wailuku 47.531631
21 1500190630 Hilo 47.491786
3 1500792160 Lihue 47.213052
42 1500993330 Spreckelsville 47.006436
12 1500393600 Waianae 46.891559
30 1500992250 Makawao-Paia 46.169428
7 1500791080 Kapaa 46.048761
28 1500792970 Puhi-Hanamaulu 45.986987
4 1500793780 Wailua-Anahola 45.556824
29 1500990360 Haiku-Pauwela 45.062474
19 1500192610 North Kona 44.449442
31 1500993690 Waihee-Waikapu 44.227507
41 1500991980 Lahaina 43.614811
10 1500393510 Waialua 43.020145
1 1500790180 Eleele-Kalaheo 42.995253
9 1500391710 Koolauloa 42.980143
2 1500791260 Kaumakani-Hanapepe 42.904206
39 1500991530 Kihei 42.618990
6 1500790540 Hanalei 42.488026
27 1500791620 Koloa-Poipu 42.177167
35 1500991890 Kula 42.043837
26 1500791440 Kekaha-Waimea 41.944628
14 1500190720 Honokaa-Kukuihaele 41.780611
40 1500990090 East Molokai 41.377057
22 1500191350 Keaau-Mountain View 41.020687
20 1500193150 South Kohala 40.443613
15 1500192520 North Kohala 40.338913
25 1500192880 Papaikou-Wailea 39.910005
16 1500192790 Pahoa-Kalapana 39.805841
36 1500992070 Lanai 39.660176
17 1500193240 South Kona 39.441267
24 1500192700 Paauhau-Paauilo 39.416518
43 1500993960 West Molokai 39.159257
38 1500990450 Hana 39.091584
0 1500590990 Kalawao 38.723797
23 1500192430 North Hilo 38.371793
18 1500191170 Kau 37.412745
8 1500792340 Niihau 35.633805