def test_aggregation_partitions(s_points_frame, x_range, y_range): # Get original as pandas df = s_points_frame.compute() # Query subset query_ddf = s_points_frame.spatial_query(x_range, y_range) # Create canvas cvs = Canvas(x_range=x_range, y_range=y_range) # Aggregate with full pandas frame agg_expected = cvs.points(df, 'x', 'y') agg_query = cvs.points(query_ddf, 'x', 'y') agg = cvs.points(s_points_frame, 'x', 'y') assert agg.equals(agg_expected) assert agg.equals(agg_query)
def generate_terrain(x_range: tuple = (0, 500), y_range: tuple = (0, 500), width: int = 25, height: int = 30, canvas: ds.Canvas = None, seed: int = 10, zfactor: int = 4000, full_extent: Optional[str] = None) -> xr.DataArray: """ Generates a pseudo-random terrain which can be helpful for testing raster functions Parameters: ---------- x_range: tuple (default = (0, 500)) Range of x values. x_range: tuple (default = (0, 500)) Range of y values. width: int (default = 25) Width of output data array in pixels. height: int (default = 30) Height of output data array in pixels. canvas: ds.Canvas (default = None) Instance for passing output dimensions / ranges seed: int (default = 10) Seed for random number generator. zfactor: int (default = 4000) Multipler for z values. full_extent: str, optional (default = None) bbox<xmin, ymin, xmax, ymax>. Full extent of coordinate system. Returns: ---------- terrain: xarray.DataArray 2D array of generated terrain. Notes: ---------- Algorithm References: - This was inspired by Michael McHugh's 2016 PyCon Canada talk: https://www.youtube.com/watch?v=O33YV4ooHSo - https://www.redblobgames.com/maps/terrain-from-noise/ Examples: ---------- Imports >>> import datashader as ds >>> from datashader.transfer_functions import shade >>> from xrspatial import generate_terrain Create Canvas >>> cvs = ds.Canvas(plot_width=800, >>> plot_height=600, >>> x_range=(-20e6, 20e6), >>> y_range=(-20e6, 20e6)) Generate Terrain Data Array >>> terrain = generate_terrain(canvas = cvs) >>> print(terrain) <xarray.DataArray 'terrain' (y: 600, x: 800)> array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]]) Coordinates: * x (x) float64 -1.998e+07 -1.992e+07 ... 1.992e+07 1.997e+07 * y (y) float64 -1.997e+07 -1.99e+07 -1.983e+07 ... 1.99e+07 1.997e+07 Attributes: res: 1 """ def _gen_heights(bumps): out = np.zeros(len(bumps)) for i, b in enumerate(bumps): x = b[0] y = b[1] val = agg.data[y, x] if val >= 0.33 and val <= 3: out[i] = 0.1 return out def _scale(value, old_range, new_range): d = (value - old_range[0]) / (old_range[1] - old_range[0]) return d * (new_range[1] - new_range[0]) + new_range[0] mercator_extent = (-np.pi * 6378137, -np.pi * 6378137, np.pi * 6378137, np.pi * 6378137) crs_extents = {'3857': mercator_extent} if isinstance(full_extent, str): full_extent = crs_extents[full_extent] elif full_extent is None: full_extent = (canvas.x_range[0], canvas.y_range[0], canvas.x_range[1], canvas.y_range[1]) elif not isinstance(full_extent, (list, tuple)) and len(full_extent) != 4: raise TypeError('full_extent must be tuple(4) or str wkid') full_xrange = (full_extent[0], full_extent[2]) full_yrange = (full_extent[1], full_extent[3]) x_range_scaled = (_scale(canvas.x_range[0], full_xrange, (0.0, 1.0)), _scale(canvas.x_range[1], full_xrange, (0.0, 1.0))) y_range_scaled = (_scale(canvas.y_range[0], full_yrange, (0.0, 1.0)), _scale(canvas.y_range[1], full_yrange, (0.0, 1.0))) data = _gen_terrain(canvas.plot_width, canvas.plot_height, seed, x_range=x_range_scaled, y_range=y_range_scaled) data = (data - np.min(data)) / np.ptp(data) data[data < 0.3] = 0 # create water data *= zfactor # DataArray coords were coming back different from cvs.points... hack_agg = canvas.points(pd.DataFrame({'x': [], 'y': []}), 'x', 'y') agg = DataArray(data, name='terrain', coords=hack_agg.coords, dims=hack_agg.dims, attrs={'res': 1}) return agg
def generate_terrain(x_range: tuple = (0, 500), y_range: tuple = (0, 500), width: int = 25, height: int = 30, canvas: ds.Canvas = None, seed: int = 10, zfactor: int = 4000, full_extent: Optional[str] = None) -> xr.DataArray: """ Generates a pseudo-random terrain which can be helpful for testing raster functions. Parameters ---------- x_range : tuple, default=(0, 500) Range of x values. x_range : tuple, default=(0, 500) Range of y values. width : int, default=25 Width of output data array in pixels. height : int, default=30 Height of output data array in pixels. canvas : ds.Canvas, default=None Instance for passing output dimensions / ranges. seed : int, default=10 Seed for random number generator. zfactor : int, default=4000 Multipler for z values. full_extent : str, default=None bbox<xmin, ymin, xmax, ymax>. Full extent of coordinate system. Returns ------- terrain : xr.DataArray 2D array of generated terrain values. References ---------- - Michael McHugh: https://www.youtube.com/watch?v=O33YV4ooHSo - Red Blob Games: https://www.redblobgames.com/maps/terrain-from-noise/ Examples -------- .. plot:: :include-source: import datashader as ds import matplotlib.pyplot as plt from xrspatial import generate_terrain, aspect # Create Canvas W = 500 H = 300 cvs = ds.Canvas(plot_width = W, plot_height = H, x_range = (-20e6, 20e6), y_range = (-20e6, 20e6)) # Generate Example Terrain terrain_agg = generate_terrain(canvas = cvs) # Edit Attributes terrain_agg = terrain_agg.assign_attrs( { 'Description': 'Example Terrain', 'units': 'km', 'Max Elevation': '4000', } ) terrain_agg = terrain_agg.rename({'x': 'lon', 'y': 'lat'}) terrain_agg = terrain_agg.rename('Elevation') # Plot Terrain terrain_agg.plot(cmap = 'terrain', aspect = 2, size = 4) plt.title("Terrain") plt.ylabel("latitude") plt.xlabel("longitude") .. sourcecode:: python >>> print(terrain_agg[200:203, 200:202]) <xarray.DataArray 'Elevation' (lat: 3, lon: 2)> array([[1264.02249454, 1261.94748873], [1285.37061171, 1282.48046696], [1306.02305679, 1303.40657515]]) Coordinates: * lon (lon) float64 -3.96e+06 -3.88e+06 * lat (lat) float64 6.733e+06 6.867e+06 7e+06 Attributes: res: 1 Description: Example Terrain units: km Max Elevation: 4000 """ def _gen_heights(bumps): out = np.zeros(len(bumps)) for i, b in enumerate(bumps): x = b[0] y = b[1] val = agg.data[y, x] if val >= 0.33 and val <= 3: out[i] = 0.1 return out def _scale(value, old_range, new_range): d = (value - old_range[0]) / (old_range[1] - old_range[0]) return d * (new_range[1] - new_range[0]) + new_range[0] mercator_extent = (-np.pi * 6378137, -np.pi * 6378137, np.pi * 6378137, np.pi * 6378137) crs_extents = {'3857': mercator_extent} if isinstance(full_extent, str): full_extent = crs_extents[full_extent] elif full_extent is None: full_extent = (canvas.x_range[0], canvas.y_range[0], canvas.x_range[1], canvas.y_range[1]) elif not isinstance(full_extent, (list, tuple)) and len(full_extent) != 4: raise TypeError('full_extent must be tuple(4) or str wkid') full_xrange = (full_extent[0], full_extent[2]) full_yrange = (full_extent[1], full_extent[3]) x_range_scaled = (_scale(canvas.x_range[0], full_xrange, (0.0, 1.0)), _scale(canvas.x_range[1], full_xrange, (0.0, 1.0))) y_range_scaled = (_scale(canvas.y_range[0], full_yrange, (0.0, 1.0)), _scale(canvas.y_range[1], full_yrange, (0.0, 1.0))) data = _gen_terrain(canvas.plot_width, canvas.plot_height, seed, x_range=x_range_scaled, y_range=y_range_scaled) data = (data - np.min(data))/np.ptp(data) data[data < 0.3] = 0 # create water data *= zfactor # DataArray coords were coming back different from cvs.points... hack_agg = canvas.points(pd.DataFrame({'x': [], 'y': []}), 'x', 'y') agg = DataArray(data, name='terrain', coords=hack_agg.coords, dims=hack_agg.dims, attrs={'res': 1}) return agg