Пример #1
0
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)
Пример #2
0
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
Пример #3
0
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