<jupyter_start><jupyter_text>Xarray-spatial User Guide: Zonal-----Xarray-spatial's zonal functions provide an easy way to generate statistics for zones within a raster aggregate. It's set up with a default set of calculations, or you can input any set of custom calculations you'd like to perform.[Generate terrain](Generate-Terrain-Data)[Zonal Statistics](Zonal-Statistics)-----------  Let's use datashader to render our images...To get started we'll bring in numpy and some functions from datashader to easily render our images.<jupyter_code>import numpy as np
import pandas as pd

import datashader as ds
from datashader.transfer_functions import shade
from datashader.transfer_functions import stack
from datashader.transfer_functions import dynspread
from datashader.transfer_functions import set_background
from datashader.colors import Elevation

import xrspatial<jupyter_output><empty_output><jupyter_text>Generate Terrain DataThe rest of the geo-related functions focus on raster data or data that's been aggregates into the row-column grid of cells for an image raster. To demonstrate using these raster-based functions, we'll first use xarray-spatial's generate_terrain to generate a fake elevation terrain raster. We use datashader's Canvas as a quick base to set up a new raster.<jupyter_code>from xrspatial import generate_terrain

W = 800
H = 600

cvs = ds.Canvas(plot_width=W, plot_height=H, x_range=(-20e6, 20e6), y_range=(-20e6, 20e6))
terrain = generate_terrain(canvas=cvs)

shade(terrain, cmap=['black', 'white'], how='linear')<jupyter_output><empty_output><jupyter_text>We can also apply datashader's Elevation colormap imported above to give a more intuitive terrain image.<jupyter_code>shade(terrain, cmap=Elevation, how='linear')<jupyter_output><empty_output><jupyter_text>Zonal StatisticsZonal statistics calculates summary statistics for specific areas or *zones* within an xarray.DataArray aggregate. Specific zones within an aggregate are defined by creating a corresponding aggregate of the same shape and setting the value at each cell to a unique non-zero integer representing a unique zone id. For example, if we set all the values in the top row of the zones aggregate to 3 and apply this to the original values aggregate, zonal stats will calculate statisitics for all the values in the corresponding top row of the values aggregate and return the results as stats for zone \3. The output of zonal stats is in the form of a pandas DataFrame, with a row for each zone. Let's set up an example.Imagine you go on a six-day hike.- We can represent the area with a terrain raster.- In that terrain, we can represent each day's path as a line segment from your start to finish point.- We can set this up with a pandas dataframe containing the start and finish points, which we then aggregate with Canvas.line. Let's take a look at these line zones overlayed on the fake terrain.<jupyter_code>from xrspatial import hillshade
from datashader.colors import Set1

cvs = ds.Canvas(plot_width=W, plot_height=H, x_range=(-20, 20), y_range=(-20, 20))

terrain = generate_terrain(canvas=cvs)
terrain_shaded = shade(terrain, cmap=Elevation, alpha=128, how='linear')

illuminated = hillshade(terrain)
illuminated_shaded = shade(illuminated, cmap=['gray', 'white'], alpha=255, how='linear')

zone_df = pd.DataFrame({
   'x': [-11, -5, 4, 12, 14, 18, 19],
   'y': [-5, 4, 10, 13, 13, 13, 10],
   'trail_segement_id': [11, 12, 13, 14, 15, 16, 17]
})

zones_agg = cvs.line(zone_df, 'x', 'y', ds.sum('trail_segement_id'))
zones_shaded = dynspread(shade(zones_agg, cmap=Set1), max_px=5)

stack(illuminated_shaded, terrain_shaded, zones_shaded)<jupyter_output><empty_output><jupyter_text>Now, we can apply zonal stats, after quickly correcting for nan values.<jupyter_code>from xrspatial import zonal_stats
zones_agg.values = np.nan_to_num(zones_agg.values, copy=False).astype(int)
zonal_stats(zones_agg, terrain)<jupyter_output><empty_output><jupyter_text>Calculate custom stats for each zone:We can also put in our own set of stats calculations to perform instead of the default ones above. - We set up a dict with our desired functions and input that as the third argument to `zonal_stats`.- Below, we try out a range function and min and max functions.<jupyter_code>custom_stats = dict(elevation_change=lambda zone: zone.max() - zone.min(),
                    elevation_min=np.min,
                    elevation_max=np.max)

zonal_stats(zones_agg, terrain, custom_stats)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08062015503875969, 'fraction_numerical': 0.016611295681063124, 'mean_word_length': 5.460658082975679, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '15885', 'license': 'MIT', 'n_tokens_mistral': 1443, 'n_tokens_neox': 1331, 'n_words': 534, 'path': 'examples/user_guide/3_Zonal.ipynb', 'repo_name': 'giancastro/xarray-spatial', 'size': '4515'}