Esempio n. 1
0
def test_from_string():
    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert wgs84_crs.to_dict() == {'init': 'epsg:4326'}

    # Make sure this doesn't get handled using the from_epsg() even though 'epsg' is in the string
    epsg_init_crs = CRS.from_string('+init=epsg:26911')
    assert epsg_init_crs.to_dict() == {'init': 'epsg:26911'}
Esempio n. 2
0
def test_from_epsg_string():
    crs_dict = CRS.from_string('epsg:4326')
    assert crs_dict['init'].lower() == 'epsg:4326'

    # Test with invalid EPSG code
    with pytest.raises(ValueError):
        assert CRS.from_string('epsg:xyz')
Esempio n. 3
0
def test_from_string():
    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert wgs84_crs.to_dict() == {'no_defs': True, 'ellps': 'WGS84', 'datum': 'WGS84', 'proj': 'longlat'}

    # Make sure this doesn't get handled using the from_epsg() even though 'epsg' is in the string
    epsg_init_crs = CRS.from_string('+units=m +init=epsg:26911 +no_defs=True')
    assert epsg_init_crs.to_dict() == {'units': 'm', 'init': 'epsg:26911', 'no_defs': True}
Esempio n. 4
0
def test_is_projected():
    assert CRS({'init': 'EPSG:3857'}).is_projected is True

    lcc_crs = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert CRS(lcc_crs).is_projected is True

    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert CRS(wgs84_crs).is_projected is False
Esempio n. 5
0
def test_from_proj4_json():
    json_str = '{"proj": "longlat", "ellps": "WGS84", "datum": "WGS84"}'
    crs_dict = CRS.from_string(json_str)
    assert crs_dict == json.loads(json_str)

    # Test with invalid JSON code
    with pytest.raises(ValueError):
        assert CRS.from_string('{foo: bar}')
Esempio n. 6
0
def test_is_geographic_from_string():
    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert wgs84_crs.is_geographic is True

    nad27_crs = CRS.from_string('+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs')
    assert nad27_crs.is_geographic is True

    lcc_crs = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert lcc_crs.is_geographic is False
Esempio n. 7
0
def test_bare_parameters():
    """ Make sure that bare parameters (e.g., no_defs) are handled properly,
    even if they come in with key=True.  This covers interaction with pyproj,
    which makes presents bare parameters as key=<bool>."""

    # Example produced by pyproj
    crs_dict = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert crs_dict.get('no_defs', False) is True

    crs_dict = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=False +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert crs_dict.get('no_defs', True) is False
Esempio n. 8
0
def test_symmetric_proj4(tmpdir):
    """ Test writing and reading proj4 string as attribute of variable """

    ds = Dataset(str(tmpdir.join('test.nc')), 'w')
    proj4 = '+proj=stere +units=m +datum=WGS84 +lat_ts=60 +lat_0=90 +lon_0=263 +lat_1=60 +x_0=3475000 +y_0=7475000'
    ds.createVariable('data', 'S1')
    set_crs(ds, 'data', Proj(proj4), set_proj4_att=True)
    out_proj4 = get_crs(ds, 'data')

    out_data = CRS.from_string(out_proj4).to_dict()

    assert len(out_data) == 9  # There should be 9 parameters
    assert CRS.from_string(proj4).to_dict() == out_data
Esempio n. 9
0
def test_is_same_crs():
    crs1 = CRS({'init': 'EPSG:4326'})
    crs2 = CRS({'init': 'EPSG:3857'})

    assert crs1 == crs1
    assert crs1 != crs2

    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert crs1 == wgs84_crs

    # Make sure that same projection with different parameter are not equal
    lcc_crs1 = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    lcc_crs2 = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=45 +lat_0=0')
    assert lcc_crs1 != lcc_crs2
Esempio n. 10
0
def test_get_crs(tmpdir):
    """ Test reading proj4 string from CF convention parameters """

    ds = Dataset(str(tmpdir.join('test.nc')), 'w')
    data_var = ds.createVariable('data', 'S1')
    data_var.setncattr('grid_mapping', 'crs_Lambert')
    crs_var = ds.createVariable('crs_Lambert', 'S1')

    in_proj4 = '+proj=lcc +units=m +lat_1=30 +lat_2=60 +lat_0=47.5 +lon_0=-97 +x_0=3825000 +y_0=3200000'

    # These parameters match the above proj4 string
    ncatts = dict()
    ncatts['grid_mapping_name'] = 'lambert_conformal_conic'
    ncatts['latitude_of_projection_origin'] = 47.5
    ncatts['longitude_of_central_meridian'] = -97
    ncatts['standard_parallel'] = [30, 60]
    ncatts['false_northing'] = 3200000
    ncatts['false_easting'] = 3825000
    set_ncattrs(crs_var, ncatts)

    out_proj4 = get_crs(ds, 'data')
    assert out_proj4 is not None

    out_data = CRS.from_string(out_proj4).to_dict()

    assert len(out_data) == 8  # There should be 8 parameters
    assert CRS.from_string(in_proj4).to_dict() == out_data

    # Test WGS84 lat/long
    data_var = ds.createVariable('data2', 'S1')
    data_var.setncattr('grid_mapping', 'crs_latlong')
    crs_var = ds.createVariable('crs_latlong', 'S1')

    in_proj4 = '+proj=latlong +a={0} +rf={1}'.format(pj_ellps['WGS84']['a'], pj_ellps['WGS84']['rf'])

    # These parameters match the above proj4 string
    ncatts = dict()
    ncatts['grid_mapping_name'] = 'latitude_longitude'
    ncatts['semi_major_axis'] = 6378137.0
    ncatts['inverse_flattening'] = 298.257223563
    set_ncattrs(crs_var, ncatts)

    out_proj4 = get_crs(ds, 'data2')
    assert out_proj4 is not None

    out_data = CRS.from_string(out_proj4).to_dict()

    assert len(out_data) == 4  # There should be 4 parameters
    # Note: pyproj adds units=m even for latlong, which is incorrect but not our problem
    assert CRS.from_string(in_proj4 + ' +units=m').to_dict() == out_data
Esempio n. 11
0
    def index(self, *args, **kwargs):
        target_srs = self.crs
        # Annotations are always in WGS84
        source_srs = CRS.from_string("EPSG:4326")

        args = transform_coordinates(source_srs, target_srs,
                                     [args[0]], [args[1]])
        return self.dataset.index(*args, **kwargs)
Esempio n. 12
0
def test_warped_vrt(path_rgb_byte_tif):
    """A VirtualVRT has the expected VRT properties."""
    with rasterio.open(path_rgb_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS)
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata == 0.0
        assert vrt.dst_nodata == 0.0
        assert vrt.tolerance == 0.125
        assert vrt.resampling == Resampling.nearest
        assert vrt.warp_extras == {"init_dest": "NO_DATA"}
        assert vrt.mask_flag_enums == ([MaskFlags.nodata],) * 3
Esempio n. 13
0
    def get_band_ix(self, indexes, x, y):
        # Reproject to native data coordinates
        target_srs = self.crs
        # Annotations are always in WGS84
        source_srs = CRS.from_string("EPSG:4326")

        transformed_x, transformed_y = transform_coordinates(source_srs,
                                                             target_srs,
                                                             [x], [y])
        return list(self.dataset.sample([(transformed_x, transformed_y)],
                                        indexes=indexes))[0]
Esempio n. 14
0
def test_empty_json():
    with pytest.raises(CRSError):
        CRS.from_string('{}')
    with pytest.raises(CRSError):
        CRS.from_string('[]')
    with pytest.raises(CRSError):
        CRS.from_string('')
Esempio n. 15
0
def retrieve_tilespecs():
    """ Retrieve default tile specifications packaged within ``tilezilla``

    Returns:
        dict: default tilespecs packaged within ``tilezilla`` as TileSpec
            objects
    """
    tilespecs = json.loads(pkgutil.get_data('tilezilla',
                                            'data/tile_specs.json').decode())
    for key in tilespecs:
        tilespecs[key]['crs'] = CRS.from_string(tilespecs[key]['crs'])
        tilespecs[key] = TileSpec(desc=key, **tilespecs[key])
    return tilespecs
Esempio n. 16
0
def test_wrap_file(path_rgb_byte_tif):
    """A VirtualVRT has the expected dataset properties."""
    with rasterio.open(path_rgb_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS)
        assert vrt.crs == CRS.from_string(DST_CRS)
        assert tuple(round(x, 1) for x in vrt.bounds) == (
            -8789636.7, 2700460.0, -8524406.4, 2943560.2
        )
        assert vrt.name.startswith("WarpedVRT(")
        assert vrt.name.endswith("tests/data/RGB.byte.tif)")
        assert vrt.indexes == (1, 2, 3)
        assert vrt.nodatavals == (0, 0, 0)
        assert vrt.dtypes == ("uint8", "uint8", "uint8")
        assert vrt.read().shape == (3, 736, 803)
Esempio n. 17
0
def test_warped_vrt_add_alpha(path_rgb_byte_tif):
    """A VirtualVRT has the expected VRT properties."""
    with rasterio.open(path_rgb_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS, add_alpha=True)
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata == 0.0
        assert vrt.dst_nodata is None
        assert vrt.tolerance == 0.125
        assert vrt.resampling == Resampling.nearest
        assert vrt.warp_extras == {"init_dest": "NO_DATA"}
        assert vrt.count == 4
        assert vrt.mask_flag_enums == (
            [MaskFlags.per_dataset, MaskFlags.alpha],
        ) * 3 + (
            [MaskFlags.all_valid],
        )
Esempio n. 18
0
def test_warped_vrt_msk_nodata(path_rgb_msk_byte_tif, caplog):
    """Specifying dst nodata also works for source with .msk"""
    with rasterio.open(path_rgb_msk_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS, nodata=0.0)
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata is None
        assert vrt.dst_nodata == 0.0
        assert vrt.count == 3
        assert vrt.mask_flag_enums == ([MaskFlags.nodata],) * 3

        caplog.set_level(logging.DEBUG)
        with rasterio.Env(CPL_DEBUG=True):
            masks = vrt.read_masks()
            assert masks[0, 0, 0] == 0
            assert masks[0].mean() > 0

        assert "RGB2.byte.tif.msk" in caplog.text
Esempio n. 19
0
def crs_handler(ctx, param, value):
    """Get crs value from a template file or command line."""
    retval = options.from_like_context(ctx, param, value)
    if retval is None and value:
        try:
            retval = json.loads(value)
        except ValueError:
            retval = value
        try:
            if isinstance(retval, dict):
                retval = CRS(retval)
            else:
                retval = CRS.from_string(retval)
        except CRSError:
            raise click.BadParameter(
                "'%s' is not a recognized CRS." % retval,
                param=param, param_hint='crs')
    return retval
Esempio n. 20
0
    def __init__(self, ul, crs, res, size, desc=None):
        self.ul = ul
        if isinstance(crs, six.string_types):
            self.crs = CRS.from_string(crs)
        elif isinstance(crs, int):
            self.crs = CRS.from_epsg(crs)
        else:
            self.crs = crs

        if not self.crs.is_valid:
            raise ValueError('Could not parse coordinate reference system '
                             'string to a valid projection ({})'.format(crs))

        self.crs_str = self.crs.to_string()
        self.res = res
        self.size = size
        self.desc = desc or 'unnamed'
        self._tiles = {}
Esempio n. 21
0
def test_utm(tmpdir):
    ds = Dataset(str(tmpdir.join('test.nc')), 'w')
    proj4 = '+init=epsg:3157'  # UTM Zone 10
    ds.createVariable('data', 'S1')
    set_crs(ds, 'data', Proj(proj4), set_proj4_att=True)
    out_proj4 = get_crs(ds, 'data')

    out_data = CRS.from_string(out_proj4).to_dict()

    # ESPG will have been converted to long form
    assert len(out_data) == 6

    expected = {
        u'zone': 10,
        u'ellps': u'GRS80',
        u'no_defs': True,
        u'proj': u'utm',
        u'units': u'm',
        u'towgs84': u'0,0,0,0,0,0,0'
    }
    assert expected == out_data
Esempio n. 22
0
def test_warped_vrt_dimensions(path_rgb_byte_tif):
    """
    A WarpedVRT with target dimensions has the expected dataset
    properties.
    """
    with rasterio.open(path_rgb_byte_tif) as src:
        extent = (-20037508.34, 20037508.34)
        size = (2 ** 16) * 256
        resolution = (extent[1] - extent[0]) / size
        dst_transform = affine.Affine(
            resolution, 0.0, extent[0], 0.0, -resolution, extent[1]
        )
        vrt = WarpedVRT(
            src, crs=DST_CRS, width=size, height=size, transform=dst_transform
        )
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata == 0.0
        assert vrt.dst_nodata == 0.0
        assert vrt.resampling == Resampling.nearest
        assert vrt.width == size
        assert vrt.height == size
        assert vrt.transform == dst_transform
        assert vrt.warp_extras == {"init_dest": "NO_DATA"}
Esempio n. 23
0
def warp(ctx, files, output, driver, like, dst_crs, dimensions, src_bounds,
         dst_bounds, res, resampling, src_nodata, dst_nodata, threads,
         check_invert_proj, overwrite, creation_options,
         target_aligned_pixels):
    """
    Warp a raster dataset.

    If a template raster is provided using the --like option, the
    coordinate reference system, affine transform, and dimensions of
    that raster will be used for the output.  In this case --dst-crs,
    --bounds, --res, and --dimensions options are not applicable and
    an exception will be raised.

    \b
        $ rio warp input.tif output.tif --like template.tif

    The output coordinate reference system may be either a PROJ.4 or
    EPSG:nnnn string,

    \b
        --dst-crs EPSG:4326
        --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84'

    or a JSON text-encoded PROJ.4 object.

    \b
        --dst-crs '{"proj": "utm", "zone": 18, ...}'

    If --dimensions are provided, --res and --bounds are not applicable and an
    exception will be raised.
    Resolution is calculated based on the relationship between the
    raster bounds in the target coordinate system and the dimensions,
    and may produce rectangular rather than square pixels.

    \b
        $ rio warp input.tif output.tif --dimensions 100 200 \\
        > --dst-crs EPSG:4326

    If --bounds are provided, --res is required if --dst-crs is provided
    (defaults to source raster resolution otherwise).

    \b
        $ rio warp input.tif output.tif \\
        > --bounds -78 22 -76 24 --res 0.1 --dst-crs EPSG:4326

    """
    output, files = resolve_inout(
        files=files, output=output, overwrite=overwrite)

    resampling = Resampling[resampling]  # get integer code for method

    if not len(res):
        # Click sets this as an empty tuple if not provided
        res = None
    else:
        # Expand one value to two if needed
        res = (res[0], res[0]) if len(res) == 1 else res

    if target_aligned_pixels:
        if not res:
            raise click.BadParameter(
                '--target-aligned-pixels requires a specified resolution')
        if src_bounds or dst_bounds:
            raise click.BadParameter(
                '--target-aligned-pixels cannot be used with '
                '--src-bounds or --dst-bounds')

    # Check invalid parameter combinations
    if like:
        invalid_combos = (dimensions, dst_bounds, dst_crs, res)
        if any(p for p in invalid_combos if p is not None):
            raise click.BadParameter(
                "--like cannot be used with any of --dimensions, --bounds, "
                "--dst-crs, or --res")

    elif dimensions:
        invalid_combos = (dst_bounds, res)
        if any(p for p in invalid_combos if p is not None):
            raise click.BadParameter(
                "--dimensions cannot be used with --bounds or --res")

    with ctx.obj['env']:
        setenv(CHECK_WITH_INVERT_PROJ=check_invert_proj)

        with rasterio.open(files[0]) as src:
            l, b, r, t = src.bounds
            out_kwargs = src.profile.copy()
            out_kwargs['driver'] = driver

            # Sort out the bounds options.
            if src_bounds and dst_bounds:
                raise click.BadParameter(
                    "--src-bounds and destination --bounds may not be "
                    "specified simultaneously.")

            if like:
                with rasterio.open(like) as template_ds:
                    dst_crs = template_ds.crs
                    dst_transform = template_ds.transform
                    dst_height = template_ds.height
                    dst_width = template_ds.width

            elif dst_crs is not None:
                try:
                    dst_crs = CRS.from_string(dst_crs)
                except ValueError as err:
                    raise click.BadParameter(
                        str(err), param='dst_crs', param_hint='dst_crs')

                if dimensions:
                    # Calculate resolution appropriate for dimensions
                    # in target.
                    dst_width, dst_height = dimensions
                    try:
                        xmin, ymin, xmax, ymax = transform_bounds(
                            src.crs, dst_crs, *src.bounds)
                    except CRSError as err:
                        raise click.BadParameter(
                            str(err), param='dst_crs', param_hint='dst_crs')
                    dst_transform = Affine(
                        (xmax - xmin) / float(dst_width),
                        0, xmin, 0,
                        (ymin - ymax) / float(dst_height),
                        ymax
                    )

                elif src_bounds or dst_bounds:
                    if not res:
                        raise click.BadParameter(
                            "Required when using --bounds.",
                            param='res', param_hint='res')

                    if src_bounds:
                        try:
                            xmin, ymin, xmax, ymax = transform_bounds(
                                src.crs, dst_crs, *src_bounds)
                        except CRSError as err:
                            raise click.BadParameter(
                                str(err), param='dst_crs',
                                param_hint='dst_crs')
                    else:
                        xmin, ymin, xmax, ymax = dst_bounds

                    dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax)
                    dst_width = max(int(ceil((xmax - xmin) / res[0])), 1)
                    dst_height = max(int(ceil((ymax - ymin) / res[1])), 1)

                else:
                    try:
                        if src.transform.is_identity and src.gcps:
                            src_crs = src.gcps[1]
                            kwargs = {'gcps': src.gcps[0]}
                        else:
                            src_crs = src.crs
                            kwargs = src.bounds._asdict()
                        dst_transform, dst_width, dst_height = calcdt(
                            src_crs, dst_crs, src.width, src.height,
                            resolution=res, **kwargs)
                    except CRSError as err:
                        raise click.BadParameter(
                            str(err), param='dst_crs', param_hint='dst_crs')

            elif dimensions:
                # Same projection, different dimensions, calculate resolution.
                dst_crs = src.crs
                dst_width, dst_height = dimensions
                dst_transform = Affine(
                    (r - l) / float(dst_width),
                    0, l, 0,
                    (b - t) / float(dst_height),
                    t
                )

            elif src_bounds or dst_bounds:
                # Same projection, different dimensions and possibly
                # different resolution.
                if not res:
                    res = (src.transform.a, -src.transform.e)

                dst_crs = src.crs
                xmin, ymin, xmax, ymax = (src_bounds or dst_bounds)
                dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax)
                dst_width = max(int(ceil((xmax - xmin) / res[0])), 1)
                dst_height = max(int(ceil((ymax - ymin) / res[1])), 1)

            elif res:
                # Same projection, different resolution.
                dst_crs = src.crs
                dst_transform = Affine(res[0], 0, l, 0, -res[1], t)
                dst_width = max(int(ceil((r - l) / res[0])), 1)
                dst_height = max(int(ceil((t - b) / res[1])), 1)

            else:
                dst_crs = src.crs
                dst_transform = src.transform
                dst_width = src.width
                dst_height = src.height

            if target_aligned_pixels:
                dst_transform, dst_width, dst_height = aligned_target(dst_transform, dst_width, dst_height, res)

            # If src_nodata is not None, update the dst metadata NODATA
            # value to src_nodata (will be overridden by dst_nodata if it is not None
            if src_nodata is not None:
                # Update the dst nodata value
                out_kwargs.update({
                    'nodata': src_nodata
                })

            # Validate a manually set destination NODATA value
            # against the input datatype.
            if dst_nodata is not None:
                if src_nodata is None and src.meta['nodata'] is None:
                    raise click.BadParameter(
                        "--src-nodata must be provided because dst-nodata is not None")
                else:
                    # Update the dst nodata value
                    out_kwargs.update({'nodata': dst_nodata})

            # When the bounds option is misused, extreme values of
            # destination width and height may result.
            if (dst_width < 0 or dst_height < 0 or
                    dst_width > MAX_OUTPUT_WIDTH or
                    dst_height > MAX_OUTPUT_HEIGHT):
                raise click.BadParameter(
                    "Invalid output dimensions: {0}.".format(
                        (dst_width, dst_height)))

            out_kwargs.update({
                'crs': dst_crs,
                'transform': dst_transform,
                'width': dst_width,
                'height': dst_height
            })

            # Adjust block size if necessary.
            if ('blockxsize' in out_kwargs and
                    dst_width < out_kwargs['blockxsize']):
                del out_kwargs['blockxsize']
            if ('blockysize' in out_kwargs and
                    dst_height < out_kwargs['blockysize']):
                del out_kwargs['blockysize']

            out_kwargs.update(**creation_options)

            with rasterio.open(output, 'w', **out_kwargs) as dst:
                reproject(
                    source=rasterio.band(src, list(range(1, src.count + 1))),
                    destination=rasterio.band(
                        dst, list(range(1, src.count + 1))),
                    src_transform=src.transform,
                    src_crs=src.crs,
                    src_nodata=src_nodata,
                    dst_transform=out_kwargs['transform'],
                    dst_crs=out_kwargs['crs'],
                    dst_nodata=dst_nodata,
                    resampling=resampling,
                    num_threads=threads)
Esempio n. 24
0
def test_epsg__no_code_available():
    lcc_crs = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc '
                              '+x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert lcc_crs.to_epsg() is None
Esempio n. 25
0
def test_crs_OSR_no_equivalence():
    crs1 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
    crs2 = CRS.from_string('+proj=longlat +datum=NAD27 +no_defs')
    assert crs1 != crs2
Esempio n. 26
0
def test_convert_crs(string):
    test = CRS.from_string(string)
    assert convert.GIS_TO_STR['crs'](test) == string
    assert convert.STR_TO_GIS['crs'](string) == test
Esempio n. 27
0
def test_empty_json(arg):
    with Env(), pytest.raises(CRSError):
        CRS.from_string(arg)
Esempio n. 28
0
    def __init__(self, tile_id: str, grid: Grid, layer: Layer) -> None:

        self.grid: Grid = grid
        self.layer: Layer = layer

        self.local_dst: Dict[str, RasterSource] = dict()

        self.tile_id: str = tile_id
        self.bounds: BoundingBox = grid.get_tile_bounds(tile_id)

        gdal_profile = {
            "driver":
            "GTiff",
            "width":
            grid.cols,
            "height":
            grid.rows,
            "count":
            self.layer.band_count,
            "transform":
            rasterio.transform.from_origin(self.bounds.left, self.bounds.top,
                                           grid.xres, grid.yres),
            "crs":
            CRS.from_string(grid.crs.to_string(
            )),  # Need to convert from ProjPy CRS to RasterIO CRS
            "sparse_ok":
            "TRUE",
            "interleave":
            "BAND",
        }
        if layer.photometric:
            gdal_profile[
                "photometric"] = layer.photometric.value  # need value, not just Enum!

        gdal_profile.update(self.layer.dst_profile)

        LOGGER.debug(f"GDAL Profile for tile {self.tile_id}: {gdal_profile}")

        # Drop GDAL specific optimizations which might not be readable by other applications
        geotiff_profile = copy.deepcopy(gdal_profile)
        geotiff_profile.pop("nbits", None)
        geotiff_profile.pop("sparse_ok", None)
        geotiff_profile.pop("interleave", None)
        geotiff_profile["compress"] = "DEFLATE"

        LOGGER.debug(
            f"GEOTIFF Profile for tile {self.tile_id}: {geotiff_profile}")

        self.dst: Dict[str, Destination] = {
            DstFormat.gdal_geotiff:
            Destination(
                uri=os.path.join(layer.prefix, DstFormat.gdal_geotiff,
                                 f"{self.tile_id}.tif"),
                profile=gdal_profile,
                bounds=self.bounds,
            ),
            DstFormat.geotiff:
            Destination(
                uri=os.path.join(layer.prefix, DstFormat.geotiff,
                                 f"{self.tile_id}.tif"),
                profile=geotiff_profile,
                bounds=self.bounds,
            ),
        }

        self.work_dir = create_dir(os.path.join(os.getcwd(), tile_id))
        self.tmp_dir = create_dir(os.path.join(self.work_dir, "tmp"))

        self.default_format = GLOBALS.default_dst_format
        self.status = "pending"
        self.metadata: Dict[str, Dict] = dict()
Esempio n. 29
0
def mask(
    input,
    output,
    variable,
    like,
    netcdf3,
    all_touched,
    invert,
    zip):

    """
    Create a NetCDF mask from a shapefile.

    Values are equivalent to a numpy mask: 0 for unmasked areas, and 1 for masked areas.

    Template NetCDF dataset must have a valid projection defined or be inferred from dimensions (e.g., lat / long)
    """

    with Dataset(like) as template_ds:
        template_varname = data_variables(template_ds).keys()[0]
        template_variable = template_ds.variables[template_varname]
        template_crs = get_crs(template_ds, template_varname)

        if template_crs:
            template_crs = CRS.from_string(template_crs)
        elif is_geographic(template_ds, template_varname):
            template_crs = CRS({'init': 'EPSG:4326'})
        else:
            raise click.UsageError('template dataset must have a valid projection defined')

        spatial_dimensions = template_variable.dimensions[-2:]
        mask_shape = template_variable.shape[-2:]

        template_y_name, template_x_name = spatial_dimensions
        coords = SpatialCoordinateVariables.from_dataset(
            template_ds,
            x_name=template_x_name,
            y_name=template_y_name,
            projection=Proj(**template_crs.to_dict())
        )


    with fiona.open(input, 'r') as shp:
        transform_required = CRS(shp.crs) != template_crs

        # Project bbox for filtering
        bbox = coords.bbox
        if transform_required:
            bbox = bbox.project(Proj(**shp.crs), edge_points=21)

        geometries = []
        for f in shp.filter(bbox=bbox.as_list()):
            geom = f['geometry']
            if transform_required:
                geom = transform_geom(shp.crs, template_crs, geom)

            geometries.append(geom)

    click.echo('Converting {0} features to mask'.format(len(geometries)))

    if invert:
        fill_value = 0
        default_value = 1
    else:
        fill_value = 1
        default_value = 0

    with rasterio.drivers():
        # Rasterize features to 0, leaving background as 1
        mask = rasterize(
            geometries,
            out_shape=mask_shape,
            transform=coords.affine,
            all_touched=all_touched,
            fill=fill_value,
            default_value=default_value,
            dtype=numpy.uint8
        )

    format = 'NETCDF3_CLASSIC' if netcdf3 else 'NETCDF4'
    dtype = 'int8' if netcdf3 else 'uint8'

    with Dataset(output, 'w', format=format) as out:
        coords.add_to_dataset(out, template_x_name, template_y_name)
        out_var = out.createVariable(variable, dtype, dimensions=spatial_dimensions, zlib=zip,
                                     fill_value=get_fill_value(dtype))
        out_var[:] = mask
Esempio n. 30
0
def test_crs_OSR_no_equivalence():
    crs1 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
    crs2 = CRS.from_string('+proj=longlat +datum=NAD27 +no_defs')
    assert crs1 != crs2
Esempio n. 31
0
    def __init__(
        self,
        array,
        bands,
        crs,
        transform,
        nodataval,
        driver="GTiff",
        rio_ds=None,
    ):
        if rasterio is None:
            msg = ("Raster(): error " +
                   'importing rasterio - try "pip install rasterio"')
            raise ImportError(msg)
        else:
            from rasterio.crs import CRS

        if affine is None:
            msg = ("Raster(): error " +
                   'importing affine - try "pip install affine"')
            raise ImportError(msg)

        self._array = array
        self._bands = bands

        meta = {"driver": driver, "nodata": nodataval}

        # create metadata dictionary
        if array.dtype in Raster.FLOAT32:
            dtype = "float32"
        elif array.dtype in Raster.FLOAT64:
            dtype = "float64"
        elif array.dtype in Raster.INT8:
            dtype = "int8"
        elif array.dtype in Raster.INT16:
            dtype = "int16"
        elif array.dtype in Raster.INT32:
            dtype = "int32"
        elif array.dtype in Raster.INT64:
            dtype = "int64"
        else:
            raise TypeError("dtype cannot be determined from Raster")

        meta["dtype"] = dtype

        if isinstance(crs, CRS):
            pass
        elif isinstance(crs, int):
            crs = CRS.from_epsg(crs)
        elif isinstance(crs, str):
            crs = CRS.from_string(crs)
        else:
            TypeError("crs type not understood, provide an epsg or proj4")

        meta["crs"] = crs

        count, height, width = array.shape
        meta["count"] = count
        meta["height"] = height
        meta["width"] = width

        if not isinstance(transform, affine.Affine):
            raise TypeError("Transform must be defined by an Affine object")

        meta["transform"] = transform

        self._meta = meta
        self._dataset = None
        self.__arr_dict = {
            self._bands[b]: arr
            for b, arr in enumerate(self._array)
        }

        self.__xcenters = None
        self.__ycenters = None

        if isinstance(rio_ds, rasterio.io.DatasetReader):
            self._dataset = rio_ds
Esempio n. 32
0
def test_epsg__no_code_available():
    lcc_crs = CRS.from_string(
        '+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc '
        '+x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert lcc_crs.to_epsg() is None
Esempio n. 33
0
def test_crs_OSR_equivalence():
    crs1 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
    crs2 = CRS.from_string('+proj=latlong +datum=WGS84 +no_defs')
    crs3 = CRS({'init': 'EPSG:4326'})
    assert crs1 == crs2
    assert crs1 == crs3
Esempio n. 34
0
def test_epsg():
    assert CRS({'init': 'EPSG:4326'}).to_epsg() == 4326
    assert CRS.from_string(
        '+proj=longlat +datum=WGS84 +no_defs').to_epsg() == 4326
Esempio n. 35
0
def read_data_grid(file_name, output_format='data_array', output_dtype='float32'):

    try:
        dset = rasterio.open(file_name)
        bounds = dset.bounds
        res = dset.res
        transform = dset.transform
        data = dset.read()

        if dset.crs is None:
            crs = CRS.from_string(proj_epsg_default)
        else:
            crs = dset.crs

        values = data[0, :, :]

        decimal_round = 7

        center_right = bounds.right - (res[0] / 2)
        center_left = bounds.left + (res[0] / 2)
        center_top = bounds.top - (res[1] / 2)
        center_bottom = bounds.bottom + (res[1] / 2)

        lon = np.arange(center_left, center_right + np.abs(res[0] / 2), np.abs(res[0]), float)
        lat = np.arange(center_bottom, center_top + np.abs(res[0] / 2), np.abs(res[1]), float)
        lons, lats = np.meshgrid(lon, lat)

        min_lon_round = round(np.min(lons), decimal_round)
        max_lon_round = round(np.max(lons), decimal_round)
        min_lat_round = round(np.min(lats), decimal_round)
        max_lat_round = round(np.max(lats), decimal_round)

        center_right_round = round(center_right, decimal_round)
        center_left_round = round(center_left, decimal_round)
        center_bottom_round = round(center_bottom, decimal_round)
        center_top_round = round(center_top, decimal_round)

        assert min_lon_round == center_left_round
        assert max_lon_round == center_right_round
        assert min_lat_round == center_bottom_round
        assert max_lat_round == center_top_round

        lats = np.flipud(lats)

        if output_format == 'data_array':

            data_obj = create_darray_2d(values, lons[0, :], lats[:, 0],
                                        coord_name_x='west_east', coord_name_y='south_north',
                                        dim_name_x='west_east', dim_name_y='south_north')

        elif output_format == 'dictionary':

            data_obj = {'values': values, 'longitude': lons[0, :], 'latitude': lats[:, 0],
                        'transform': transform, 'crs': crs,
                        'bbox': [bounds.left, bounds.bottom, bounds.right, bounds.top],
                        'bb_left': bounds.left, 'bb_right': bounds.right,
                        'bb_top': bounds.top, 'bb_bottom': bounds.bottom,
                        'res_lon': res[0], 'res_lat': res[1]}
        else:
            log_stream.error(' ===> File static "' + file_name + '" output format not allowed')
            raise NotImplementedError('Case not implemented yet')

    except IOError as io_error:

        data_obj = None
        log_stream.warning(' ===> File static in ascii grid was not correctly open with error "' + str(io_error) + '"')
        log_stream.warning(' ===> Filename "' + os.path.split(file_name)[1] + '"')

    return data_obj
Esempio n. 36
0
def warp(ctx, files, output, driver, like, dst_crs, dimensions, src_bounds,
         dst_bounds, res, resampling, src_nodata, dst_nodata, threads,
         check_invert_proj, force_overwrite, creation_options):
    """
    Warp a raster dataset.

    If a template raster is provided using the --like option, the
    coordinate reference system, affine transform, and dimensions of
    that raster will be used for the output.  In this case --dst-crs,
    --bounds, --res, and --dimensions options are not applicable and
    an exception will be raised.

    \b
        $ rio warp input.tif output.tif --like template.tif

    The output coordinate reference system may be either a PROJ.4 or
    EPSG:nnnn string,

    \b
        --dst-crs EPSG:4326
        --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84'

    or a JSON text-encoded PROJ.4 object.

    \b
        --dst-crs '{"proj": "utm", "zone": 18, ...}'

    If --dimensions are provided, --res and --bounds are not applicable and an
    exception will be raised.
    Resolution is calculated based on the relationship between the
    raster bounds in the target coordinate system and the dimensions,
    and may produce rectangular rather than square pixels.

    \b
        $ rio warp input.tif output.tif --dimensions 100 200 \\
        > --dst-crs EPSG:4326

    If --bounds are provided, --res is required if --dst-crs is provided
    (defaults to source raster resolution otherwise).

    \b
        $ rio warp input.tif output.tif \\
        > --bounds -78 22 -76 24 --res 0.1 --dst-crs EPSG:4326

    """
    output, files = resolve_inout(files=files,
                                  output=output,
                                  force_overwrite=force_overwrite)

    resampling = Resampling[resampling]  # get integer code for method

    if not len(res):
        # Click sets this as an empty tuple if not provided
        res = None
    else:
        # Expand one value to two if needed
        res = (res[0], res[0]) if len(res) == 1 else res

    # Check invalid parameter combinations
    if like:
        invalid_combos = (dimensions, dst_bounds, dst_crs, res)
        if any(p for p in invalid_combos if p is not None):
            raise click.BadParameter(
                "--like cannot be used with any of --dimensions, --bounds, "
                "--dst-crs, or --res")

    elif dimensions:
        invalid_combos = (dst_bounds, res)
        if any(p for p in invalid_combos if p is not None):
            raise click.BadParameter(
                "--dimensions cannot be used with --bounds or --res")

    with ctx.obj['env']:
        setenv(CHECK_WITH_INVERT_PROJ=check_invert_proj)

        with rasterio.open(files[0]) as src:
            l, b, r, t = src.bounds
            out_kwargs = src.profile.copy()
            out_kwargs['driver'] = driver

            # Sort out the bounds options.
            if src_bounds and dst_bounds:
                raise click.BadParameter(
                    "--src-bounds and destination --bounds may not be "
                    "specified simultaneously.")

            if like:
                with rasterio.open(like) as template_ds:
                    dst_crs = template_ds.crs
                    dst_transform = template_ds.transform
                    dst_height = template_ds.height
                    dst_width = template_ds.width

            elif dst_crs is not None:
                try:
                    dst_crs = CRS.from_string(dst_crs)
                except ValueError as err:
                    raise click.BadParameter(str(err),
                                             param='dst_crs',
                                             param_hint='dst_crs')

                if dimensions:
                    # Calculate resolution appropriate for dimensions
                    # in target.
                    dst_width, dst_height = dimensions
                    try:
                        xmin, ymin, xmax, ymax = transform_bounds(
                            src.crs, dst_crs, *src.bounds)
                    except CRSError as err:
                        raise click.BadParameter(str(err),
                                                 param='dst_crs',
                                                 param_hint='dst_crs')
                    dst_transform = Affine(
                        (xmax - xmin) / float(dst_width), 0, xmin, 0,
                        (ymin - ymax) / float(dst_height), ymax)

                elif src_bounds or dst_bounds:
                    if not res:
                        raise click.BadParameter(
                            "Required when using --bounds.",
                            param='res',
                            param_hint='res')

                    if src_bounds:
                        try:
                            xmin, ymin, xmax, ymax = transform_bounds(
                                src.crs, dst_crs, *src_bounds)
                        except CRSError as err:
                            raise click.BadParameter(str(err),
                                                     param='dst_crs',
                                                     param_hint='dst_crs')
                    else:
                        xmin, ymin, xmax, ymax = dst_bounds

                    dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax)
                    dst_width = max(int(ceil((xmax - xmin) / res[0])), 1)
                    dst_height = max(int(ceil((ymax - ymin) / res[1])), 1)

                else:
                    try:
                        if src.transform.is_identity and src.gcps:
                            src_crs = src.gcps[1]
                            kwargs = {'gcps': src.gcps[0]}
                        else:
                            src_crs = src.crs
                            kwargs = src.bounds._asdict()
                        dst_transform, dst_width, dst_height = calcdt(
                            src_crs,
                            dst_crs,
                            src.width,
                            src.height,
                            resolution=res,
                            **kwargs)
                    except CRSError as err:
                        raise click.BadParameter(str(err),
                                                 param='dst_crs',
                                                 param_hint='dst_crs')

            elif dimensions:
                # Same projection, different dimensions, calculate resolution.
                dst_crs = src.crs
                dst_width, dst_height = dimensions
                dst_transform = Affine((r - l) / float(dst_width), 0, l, 0,
                                       (b - t) / float(dst_height), t)

            elif src_bounds or dst_bounds:
                # Same projection, different dimensions and possibly
                # different resolution.
                if not res:
                    res = (src.transform.a, -src.transform.e)

                dst_crs = src.crs
                xmin, ymin, xmax, ymax = (src_bounds or dst_bounds)
                dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax)
                dst_width = max(int(ceil((xmax - xmin) / res[0])), 1)
                dst_height = max(int(ceil((ymax - ymin) / res[1])), 1)

            elif res:
                # Same projection, different resolution.
                dst_crs = src.crs
                dst_transform = Affine(res[0], 0, l, 0, -res[1], t)
                dst_width = max(int(ceil((r - l) / res[0])), 1)
                dst_height = max(int(ceil((t - b) / res[1])), 1)

            else:
                dst_crs = src.crs
                dst_transform = src.transform
                dst_width = src.width
                dst_height = src.height

            # If src_nodata is not None, update the dst metadata NODATA
            # value to src_nodata (will be overridden by dst_nodata if it is not None
            if src_nodata is not None:
                # Update the dst nodata value
                out_kwargs.update({'nodata': src_nodata})

            # Validate a manually set destination NODATA value
            # against the input datatype.
            if dst_nodata is not None:
                if src_nodata is None and src.meta['nodata'] is None:
                    raise click.BadParameter(
                        "--src-nodata must be provided because dst-nodata is not None"
                    )
                else:
                    # Update the dst nodata value
                    out_kwargs.update({'nodata': dst_nodata})

            # When the bounds option is misused, extreme values of
            # destination width and height may result.
            if (dst_width < 0 or dst_height < 0 or dst_width > MAX_OUTPUT_WIDTH
                    or dst_height > MAX_OUTPUT_HEIGHT):
                raise click.BadParameter(
                    "Invalid output dimensions: {0}.".format(
                        (dst_width, dst_height)))

            out_kwargs.update({
                'crs': dst_crs,
                'transform': dst_transform,
                'width': dst_width,
                'height': dst_height
            })

            # Adjust block size if necessary.
            if ('blockxsize' in out_kwargs
                    and dst_width < out_kwargs['blockxsize']):
                del out_kwargs['blockxsize']
            if ('blockysize' in out_kwargs
                    and dst_height < out_kwargs['blockysize']):
                del out_kwargs['blockysize']

            out_kwargs.update(**creation_options)

            with rasterio.open(output, 'w', **out_kwargs) as dst:
                reproject(source=rasterio.band(src,
                                               list(range(1, src.count + 1))),
                          destination=rasterio.band(
                              dst, list(range(1, src.count + 1))),
                          src_transform=src.transform,
                          src_crs=src.crs,
                          src_nodata=src_nodata,
                          dst_transform=out_kwargs['transform'],
                          dst_crs=out_kwargs['crs'],
                          dst_nodata=dst_nodata,
                          resampling=resampling,
                          num_threads=threads)
Esempio n. 37
0
    def get(self, request, pk=None, project_pk=None, tile_type=""):
        """
        Get the metadata for this tasks's asset type
        """
        task = self.get_and_check_task(request, pk)
        formula = self.request.query_params.get('formula')
        bands = self.request.query_params.get('bands')
        defined_range = self.request.query_params.get('range')
        boundaries_feature = self.request.query_params.get('boundaries')
        if formula == '': formula = None
        if bands == '': bands = None
        if defined_range == '': defined_range = None
        if boundaries_feature == '': boundaries_feature = None
        if boundaries_feature is not None:
            boundaries_feature = json.loads(boundaries_feature)
        try:
            expr, hrange = lookup_formula(formula, bands)
            if defined_range is not None:
                new_range = tuple(map(float, defined_range.split(",")[:2]))
                #Validate rescaling range
                if hrange is not None and (new_range[0] < hrange[0] or new_range[1] > hrange[1]):
                    pass
                else:
                    hrange = new_range

        except ValueError as e:
            raise exceptions.ValidationError(str(e))
        pmin, pmax = 2.0, 98.0
        raster_path = get_raster_path(task, tile_type)
        if not os.path.isfile(raster_path):
            raise exceptions.NotFound()
        try:
            with COGReader(raster_path) as src:
                band_count = src.metadata()['count']
                if boundaries_feature is not None:
                    boundaries_cutline = create_cutline(src.dataset, boundaries_feature, CRS.from_string('EPSG:4326'))
                    boundaries_bbox = featureBounds(boundaries_feature)
                else:
                    boundaries_cutline = None
                    boundaries_bbox = None
                if has_alpha_band(src.dataset):
                    band_count -= 1
                nodata = None
                # Workaround for https://github.com/OpenDroneMap/WebODM/issues/894
                if tile_type == 'orthophoto':
                    nodata = 0
                histogram_options = {"bins": 255, "range": hrange}
                if expr is not None:
                    if boundaries_cutline is not None:
                        data, mask = src.preview(expression=expr, vrt_options={'cutline': boundaries_cutline})
                    else:
                        data, mask = src.preview(expression=expr)
                    data = numpy.ma.array(data)
                    data.mask = mask == 0
                    stats = {
                        str(b + 1): raster_stats(data[b], percentiles=(pmin, pmax), bins=255, range=hrange)
                        for b in range(data.shape[0])
                    }
                    stats = {b: ImageStatistics(**s) for b, s in stats.items()}
                    metadata = RioMetadata(statistics=stats, **src.info().dict())
                else:
                    if (boundaries_cutline is not None) and (boundaries_bbox is not None):
                        metadata = src.metadata(pmin=pmin, pmax=pmax, hist_options=histogram_options, nodata=nodata
                                                , bounds=boundaries_bbox, vrt_options={'cutline': boundaries_cutline})
                    else:
                        metadata = src.metadata(pmin=pmin, pmax=pmax, hist_options=histogram_options, nodata=nodata)
                info = json.loads(metadata.json())
        except IndexError as e:
            # Caught when trying to get an invalid raster metadata
            raise exceptions.ValidationError("Cannot retrieve raster metadata: %s" % str(e))
        # Override min/max
        if hrange:
            for b in info['statistics']:
                info['statistics'][b]['min'] = hrange[0]
                info['statistics'][b]['max'] = hrange[1]

        cmap_labels = {
            "viridis": "Viridis",
            "jet": "Jet",
            "terrain": "Terrain",
            "gist_earth": "Earth",
            "rdylgn": "RdYlGn",
            "rdylgn_r": "RdYlGn (Reverse)",
            "spectral": "Spectral",
            "spectral_r": "Spectral (Reverse)",
            "discrete_ndvi": "Contrast NDVI",
            "better_discrete_ndvi": "Custom NDVI Index",
            "rplumbo": "Rplumbo (Better NDVI)",
            "pastel1": "Pastel",
        }

        colormaps = []
        algorithms = []
        if tile_type in ['dsm', 'dtm']:
            colormaps = ['viridis', 'jet', 'terrain', 'gist_earth', 'pastel1']
        elif formula and bands:
            colormaps = ['rdylgn', 'spectral', 'rdylgn_r', 'spectral_r', 'rplumbo', 'discrete_ndvi',
                         'better_discrete_ndvi']
            algorithms = *get_algorithm_list(band_count),

        info['color_maps'] = []
        info['algorithms'] = algorithms
        if colormaps:
            for cmap in colormaps:
                try:
                    info['color_maps'].append({
                        'key': cmap,
                        'color_map': colormap.get(cmap).values(),
                        'label': cmap_labels.get(cmap, cmap)
                    })
                except FileNotFoundError:
                    raise exceptions.ValidationError("Not a valid color_map value: %s" % cmap)

        info['name'] = task.name
        info['scheme'] = 'xyz'
        info['tiles'] = [get_tile_url(task, tile_type, self.request.query_params)]

        if info['maxzoom'] < info['minzoom']:
            info['maxzoom'] = info['minzoom']
        info['maxzoom'] += ZOOM_EXTRA_LEVELS
        info['minzoom'] -= ZOOM_EXTRA_LEVELS
        info['bounds'] = {'value': src.bounds, 'crs': src.dataset.crs}
        return Response(info)
Esempio n. 38
0
def set_crs(dataset, variable_name, projection, set_proj4_att=False):
    """
    Set the projection information into a grid_mapping variable and reference it
    from the data variable.

    :param dataset: dataset open in write or append mode
    :param variable_name: name of data variable to attach projection to
    :param projection: pyproj.Proj projection object
    :param set_proj4_att: if True, set the 'proj4' attribute on the variable
    """

    if not isinstance(projection, Proj):
        raise ValueError('Projection must be instance of pyproj.Proj')

    variable = dataset.variables[variable_name]

    if 'epsg:' in projection.srs:
        proj_string = epsg_to_proj4(re.search('(?<=epsg:)\d+', projection.srs).group())
    else:
        proj_string = projection.srs

    if set_proj4_att:
        variable.setncattr(PROJ4_KEY, proj_string)

    proj = CRS.from_string(proj_string)
    proj_data = proj.to_dict()
    proj_key = 'latlong' if not proj.is_projected else proj_data['proj']
    if not proj_key in PROJ4_CF_PARAM_MAP.keys():
        raise ValueError('CF Convention mapping is not yet available for projection {0}'.format(proj_key))

    crs_variable_name = 'crs_{0}'.format(pj_list[proj_key].replace(' ', '_').replace('/', ''))
    if not crs_variable_name in dataset.variables:
        crs_variable = dataset.createVariable(crs_variable_name, 'S1')

        ncatts = {'grid_mapping_name': PROJ4_CF_NAMES[proj_key]}

        out_proj_params = PROJ4_CF_PARAM_MAP[proj_key]
        for param in out_proj_params:
            if param.count('{'):
                # Special case - standard parallel
                keys = [param.format(i) for i in (1, 2)]
                values = [proj_data[key] for key in keys if key in proj_data]
                if values:
                    if len(values) == 1:
                        values = values[0]
                    ncatts[out_proj_params[param]] = values

            elif param in proj_data:
                ncatts[out_proj_params[param]] = proj_data[param]

        if 'datum' in proj_data and not 'ellps' in proj_data:
            # Not all datums link to available pj_ellps keys, some had to be added manually here
            if proj_data['datum'] in pj_ellps:
                proj_data['ellps'] = proj_data['datum']
            elif proj_data['datum'] == 'NAD83':
                proj_data['ellps'] = 'GRS80'
            elif proj_data['datum'] == 'NAD27':
                proj_data['ellps'] = 'clrk66'
            else:
                raise ValueError('projection ellipsoid must be specified, datum {0}'
                                 'does not match a known ellipsoid'.format(proj_data['datum']))

        # Extract out parameters of known ellipsoids
        if 'ellps' in proj_data:
            if not proj_data['ellps'] in pj_ellps:
                raise ValueError('projection ellipsoid does not match a known ellipsoid')

            ellipsoid_params = pj_ellps[proj_data['ellps']]
            for param in set(PROJ4_CF_ELLIPSOID_MAP.keys()).intersection(ellipsoid_params):
                proj_data[param] = ellipsoid_params[param]

        for param in set(PROJ4_CF_ELLIPSOID_MAP.keys()).intersection(proj_data):
            ncatts[PROJ4_CF_ELLIPSOID_MAP[param]] = proj_data[param]

        set_ncattrs(crs_variable, ncatts)

    variable.setncattr('grid_mapping', crs_variable_name)
Esempio n. 39
0
def write_geotiff_from_xr(tif_path,
                          dataset,
                          bands=[],
                          no_data=-9999,
                          crs="EPSG:4326"):
    """Write a geotiff from an xarray dataset.

    Args:
        tif_path: path for the tif to be written to.
        dataset: xarray dataset
        bands: list of strings representing the bands in the order they should be written
        no_data: nodata value for the dataset
        crs: requested crs.
        Affine(a,b,c,d,e,f)
        a = width of a pixel
        b = row rotation (typically zero)
        c = x-coordinate of the upper-left corner of the upper-left pixel
        d = column rotation (typically zero)
        e = height of a pixel (typically negative)
        f = y-coordinate of the of the upper-left corner of the upper-left pixel

    """
    from rasterio.crs import CRS as CRS_rasterio
    bands = list(dataset.data_vars.keys())
    assert isinstance(bands, list), "Bands must a list of strings"
    assert len(bands) > 0 and isinstance(
        bands[0], str), "You must supply at least one band."

    logging.info('write_geotiff_from_xr: dataset {} - {}'.format(
        type(dataset), dataset))

    #print(dataset.crs)
    #if dataset.crs is not None:
    #    if isinstance(dataset.crs, xr.DataArray):
    #        print(type(dataset.crs))
    #        crs_dict = dataset.crs.to_dict()
    #        crs = CRS_rasterio.from_wkt(crs_dict['attrs']['crs_wkt'])
    #        print(crs_dict['attrs'])
    #        geobox = calculate_bounds_geotransform(dataset)
    #        bounds = BoundingBox(left=geobox['left'], bottom=geobox['bottom'], right=geobox['right'], top=geobox['top'])
    #    else:
    #        crs = dataset.crs.crs_str
    #else:
    #    print("no entra")
    #    transform = _get_transform_from_xr(dataset)

    #transform = _get_transform_from_xr(dataset)

    if isinstance(dataset.crs, xr.DataArray):
        crs_dict = dataset.crs.to_dict()
        crs = CRS_rasterio.from_wkt(crs_dict['attrs']['crs_wkt'])

    elif isinstance(dataset.crs, datacube.utils.geometry._base.CRS):
        crs = CRS_rasterio.from_string(dataset.crs.crs_str)
    else:
        raise Exception(
            'dataset.crs datatype not know (please check calculate_bounds_geotransform)'
        )

    geobox = calculate_bounds_geotransform(dataset)
    bounds = BoundingBox(left=geobox['left'],
                         bottom=geobox['bottom'],
                         right=geobox['right'],
                         top=geobox['top'])

    transform = _get_transform_from_xr(dataset)

    with rasterio.open(
            tif_path,
            'w',
            driver='GTiff',
            height=dataset.dims['latitude'],
            width=dataset.dims['longitude'],
            count=len(bands),
            dtype=dataset[bands[0]].dtype,  #str(dataset[bands[0]].dtype),
            crs=crs,
            transform=transform,
            bounds=bounds,
            nodata=no_data) as dst:
        for index, band in enumerate(bands):
            print(dataset[band].dtype)
            dst.write_band(
                index + 1,
                dataset[band].values.astype(dataset[bands[0]].dtype),
            )
            tag = {'Band_' + str(index + 1): bands[index]}
            dst.update_tags(**tag)
            dst.set_band_description(index + 1, band)
        dst.close()
Esempio n. 40
0
def test_crs_proj_json__from_string():
    aeqd_crs = CRS(proj="aeqd", lon_0=-80, lat_0=40.5)
    assert CRS.from_string(json.dumps(
        aeqd_crs.to_dict(projjson=True))) == aeqd_crs
Esempio n. 41
0
def extract_chips_from_raster(
    raster,
    rescale_mode=None,
    rescale_range=None,
    bands=None,
    type="tif",
    write_geojson=True,
    labels=None,
    label_property="class",
    mask_type="class",
    classes=None,
    crs=None,
    skip_existing=True,
    within=False,
    aoi_poly=None,
    polys_dict=None,
    dry_run=False,
    *,
    size,
    step_size,
    output_dir,
):

    basename, _ = os.path.splitext(os.path.basename(raster))

    masks_folder = os.path.join(output_dir, "masks")
    image_folder = os.path.join(output_dir, "images")

    with rasterio.open(raster) as ds:
        _logger.info("Raster size: %s", (ds.width, ds.height))

        if any(b > ds.count for b in bands):
            raise RuntimeError(
                f"Raster has {ds.count} bands, but you asked to use {bands} band indexes"
            )

        if bands is None:
            bands = list(range(1, min(ds.count, 3) + 1))

        _logger.info("Building windows")
        win_size = (size, size)
        win_step_size = (step_size, step_size)
        windows = list(
            sliding_windows(win_size,
                            win_step_size,
                            ds.width,
                            ds.height,
                            whole=True))
        _logger.info("Total windows: %d", len(windows))

        _logger.info("Building window shapes")
        window_shapes = [
            box(*rasterio.windows.bounds(w, ds.transform)) for w, _ in windows
        ]
        window_and_shapes = zip(windows, window_shapes)

        # Filter windows by AOI shape
        if aoi_poly:
            _logger.info("Filtering windows by AOI")
            _logger.info("Using \"%s\" function",
                         'within' if within else 'intersects')
            filter_fn = lambda w, aoi: w.within(
                aoi) if within else w.intersects(aoi)
            window_and_shapes = [(w, s) for w, s in window_and_shapes
                                 if filter_fn(s, aoi_poly)]
            _logger.info("Total windows after filtering: %d",
                         len(window_and_shapes))

        meta = ds.meta.copy()
        if crs:
            meta["crs"] = CRS.from_string(crs)

        chips = []
        for c, ((window, (i, j)),
                win_shape) in tqdm(list(enumerate(window_and_shapes))):
            _logger.debug("%s %s", window, (i, j))

            img_path = os.path.join(image_folder, f"{basename}_{i}_{j}.{type}")
            mask_path = os.path.join(masks_folder,
                                     f"{basename}_{i}_{j}.{type}")

            # Store chip window for generating GeoJSON later
            chip = (win_shape, (c, i, j))
            chips.append(chip)

            if dry_run:
                continue

            if (skip_existing and os.path.exists(img_path)
                    and (not labels or os.path.exists(mask_path))):
                continue

            # Extract chip image from original image
            img = ds.read(window=window)
            img = np.nan_to_num(img)
            img = np.array([img[b - 1, :, :] for b in bands])

            # Rescale intensity (if needed)
            if rescale_mode:
                img = rescale_intensity(img, rescale_mode, rescale_range)

            # Write chip image
            if type == "tif":
                image_was_saved = write_tif(
                    img,
                    img_path,
                    window=window,
                    meta=meta.copy(),
                    transform=ds.transform,
                    bands=bands,
                )
            else:
                image_was_saved = write_image(img, img_path)

            # If there are labels, and chip was extracted succesfully, generate a mask
            if image_was_saved and labels:
                if mask_type == "class":
                    keys = classes if classes is not None else polys_dict.keys(
                    )
                    multiband_chip_mask_by_classes(
                        classes=keys,
                        transform=ds.transform,
                        window=window,
                        window_shape=win_shape,
                        polys_dict=polys_dict,
                        metadata=meta,
                        mask_path=mask_path,
                        label_property=label_property,
                    )

        if write_geojson:
            geojson_path = os.path.join(output_dir,
                                        "{}.geojson".format(basename))
            write_chips_geojson(geojson_path,
                                chips,
                                type=type,
                                crs=str(meta["crs"]),
                                basename=basename)
Esempio n. 42
0
def test_tmerc_no_match():
    """Should not match an authority, see issue #2293."""
    s = "+proj=tmerc +lat_0=0 +lon_0=10.7584 +k=0.9996 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
    crs = CRS.from_string(s)
    assert crs.to_epsg() is None
Esempio n. 43
0
def set_crs(dataset, variable_name, projection, set_proj4_att=False):
    """
    Set the projection information into a grid_mapping variable and reference it
    from the data variable.

    :param dataset: dataset open in write or append mode
    :param variable_name: name of data variable to attach projection to
    :param projection: pyproj.Proj projection object
    :param set_proj4_att: if True, set the 'proj4' attribute on the variable
    """

    if not isinstance(projection, Proj):
        raise ValueError('Projection must be instance of pyproj.Proj')

    variable = dataset.variables[variable_name]

    if 'epsg:' in projection.srs:
        proj_string = epsg_to_proj4(re.search('(?<=epsg:)\d+', projection.srs).group())
    else:
        proj_string = projection.srs

    if set_proj4_att:
        variable.setncattr(PROJ4_KEY, proj_string)

    proj_data = CRS.from_string(proj_string).to_dict()
    proj_key = proj_data['proj']
    if not proj_key in PROJ4_CF_PARAM_MAP.keys():
        raise ValueError('CF Convention mapping is not yet available for projection {0}'.format(proj_key))

    crs_variable_name = 'crs_{0}'.format(pj_list[proj_key].replace(' ', '_').replace('/', ''))
    if not crs_variable_name in dataset.variables:
        crs_variable = dataset.createVariable(crs_variable_name, 'S1')

        ncatts = {'grid_mapping_name': PROJ4_CF_NAMES[proj_key]}

        out_proj_params = PROJ4_CF_PARAM_MAP[proj_key]
        for param in out_proj_params:
            if param.count('{'):
                # Special case - standard parallel
                keys = [param.format(i) for i in (1, 2)]
                values = [proj_data[key] for key in keys if key in proj_data]
                if values:
                    if len(values) == 1:
                        values = values[0]
                    ncatts[out_proj_params[param]] = values

            elif param in proj_data:
                ncatts[out_proj_params[param]] = proj_data[param]

        if 'datum' in proj_data and not 'ellps' in proj_data:
            # Not all datums link to available pj_ellps keys, some had to be added manually here
            if proj_data['datum'] in pj_ellps:
                proj_data['ellps'] = proj_data['datum']
            elif proj_data['datum'] == 'NAD83':
                proj_data['ellps'] = 'GRS80'
            elif proj_data['datum'] == 'NAD27':
                proj_data['ellps'] = 'clrk66'
            else:
                raise ValueError('projection ellipsoid must be specified, datum {0}'
                                 'does not match a known ellipsoid'.format(proj_data['datum']))

        # Extract out parameters of known ellipsoids
        if 'ellps' in proj_data:
            if not proj_data['ellps'] in pj_ellps:
                raise ValueError('projection ellipsoid does not match a known ellipsoid')

            ellipsoid_params = pj_ellps[proj_data['ellps']]
            for param in set(PROJ4_CF_ELLIPSOID_MAP.keys()).intersection(ellipsoid_params):
                proj_data[param] = ellipsoid_params[param]

        for param in set(PROJ4_CF_ELLIPSOID_MAP.keys()).intersection(proj_data):
            ncatts[PROJ4_CF_ELLIPSOID_MAP[param]] = proj_data[param]

        set_ncattrs(crs_variable, ncatts)

    variable.setncattr('grid_mapping', crs_variable_name)
Esempio n. 44
0
def write_data_grid(file_name, file_data, file_ancillary=None):

    if 'bb_left' in list(file_ancillary.keys()):
        bb_left = file_ancillary['bb_left']
    else:
        log_stream.error(
            ' ===> Geographical info "bb_left" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'bb_bottom' in list(file_ancillary.keys()):
        bb_bottom = file_ancillary['bb_bottom']
    else:
        log_stream.error(
            ' ===> Geographical info "bb_bottom" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'res_lon' in list(file_ancillary.keys()):
        res_lon = file_ancillary['res_lon']
    else:
        log_stream.error(
            ' ===> Geographical info "res_lon" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'res_lat' in list(file_ancillary.keys()):
        res_lat = file_ancillary['res_lat']
    else:
        log_stream.error(
            ' ===> Geographical info "res_lat" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'transform' in list(file_ancillary.keys()):
        transform = file_ancillary['transform']
    else:
        log_stream.error(
            ' ===> Geographical info "transform" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'no_data' in list(file_ancillary.keys()):
        no_data = file_ancillary['no_data']
    else:
        no_data = -9999
    if 'espg' in list(file_ancillary.keys()):
        epsg = file_ancillary['epsg']
    else:
        epsg = proj_epsg_default
    if 'decimal_precision' in list(file_ancillary.keys()):
        decimal_precision = int(file_ancillary['decimal_precision'])
    else:
        decimal_num = Decimal(str(file_data[0][0]))
        decimal_precision = abs(decimal_num.as_tuple().exponent)

    if isinstance(epsg, int):
        crs = CRS.from_epsg(epsg)
    elif isinstance(epsg, str):
        crs = CRS.from_string(epsg)
    else:
        log_stream.error(
            ' ===> Geographical info "epsg" defined by using an unsupported format.'
        )
        raise IOError(
            'Geographical EPSG must be in string format "EPSG:4326" or integer format "4326".'
        )

    dset_meta = dict(driver='AAIGrid',
                     height=file_data.shape[0],
                     width=file_data.shape[1],
                     crs=crs,
                     count=1,
                     dtype=str(file_data.dtype),
                     transform=transform,
                     nodata=no_data,
                     decimal_precision=decimal_precision)

    with rasterio.open(file_name, 'w', **dset_meta) as dset_handle:
        dset_handle.write(file_data, 1)
Esempio n. 45
0
def render_netcdf(filename_pattern, variable, output_directory, renderer_file,
                  save_file, renderer_type, colormap, fill, colorspace,
                  palette, palette_stretch, scale, id_variable, lh,
                  legend_breaks, legend_ticks, legend_precision, format,
                  src_crs, dst_crs, res, resampling, anchors, interactive_map,
                  mask_path):
    """
    Render netcdf files to images.

    colormap is ignored if renderer_file is provided

    --dst-crs is ignored if using --map option (always uses EPSG:3857

    If no colormap or palette is provided, a default palette may be chosen based on the name of the variable.

    If provided, mask must be 1 for areas to be masked out, and 0 otherwise.  It
    must be in the same CRS as the input datasets, and have the same spatial
    dimensions.

    """

    # Parameter overrides
    if interactive_map:
        dst_crs = 'EPSG:3857'

    filenames = glob.glob(filename_pattern)
    if not filenames:
        raise click.BadParameter('No files found matching that pattern',
                                 param='filename_pattern',
                                 param_hint='FILENAME_PATTERN')

    if not os.path.exists(output_directory):
        os.makedirs(output_directory)

    mask = get_mask(mask_path) if mask_path is not None else None

    if renderer_file is not None and not save_file:
        if not os.path.exists(renderer_file):
            raise click.BadParameter('does not exist',
                                     param='renderer_file',
                                     param_hint='renderer_file')

        # see https://bitbucket.org/databasin/ncdjango/wiki/Home for format
        renderer_dict = json.loads(open(renderer_file).read())

        if variable in renderer_dict and not 'colors' in renderer_dict:
            renderer_dict = renderer_dict[variable]

        renderer_type = renderer_dict['type']
        if renderer_type == 'stretched':
            colors = ','.join([str(c[0]) for c in renderer_dict['colors']])
            if 'min' in colors or 'max' in colors or 'mean' in colors:
                statistics = collect_statistics(filenames, (variable, ),
                                                mask=mask)[variable]
                for entry in renderer_dict['colors']:
                    if isinstance(entry[0], basestring):
                        if entry[0] in ('min', 'max', 'mean'):
                            entry[0] = statistics[entry[0]]
                        elif '*' in entry[0]:
                            rel_value, statistic = entry[0].split('*')
                            entry[0] = float(rel_value) * statistics[statistic]

        renderer = renderer_from_dict(renderer_dict)

    else:

        if renderer_type == 'stretched':
            if palette is not None:
                renderer = palette_to_stretched_renderer(palette,
                                                         palette_stretch,
                                                         filenames,
                                                         variable,
                                                         fill_value=fill,
                                                         mask=mask)

            elif colormap is None and variable in DEFAULT_PALETTES:
                palette, palette_stretch = DEFAULT_PALETTES[variable]
                renderer = palette_to_stretched_renderer(palette,
                                                         palette_stretch,
                                                         filenames,
                                                         variable,
                                                         fill_value=fill,
                                                         mask=mask)

            else:
                if colormap is None:
                    colormap = 'min:#000000,max:#FFFFFF'
                renderer = colormap_to_stretched_renderer(colormap,
                                                          colorspace,
                                                          filenames,
                                                          variable,
                                                          fill_value=fill,
                                                          mask=mask)

        elif renderer_type == 'classified':
            if not palette:
                raise click.BadParameter(
                    'palette required for classified (for now)',
                    param='--palette',
                    param_hint='--palette')

            renderer = palette_to_classified_renderer(
                palette,
                filenames,
                variable,
                method='equal',
                fill_value=fill,
                mask=mask)  # TODO: other methods

    if save_file:

        if os.path.exists(save_file):
            with open(save_file, 'r+') as output_file:
                data = json.loads(output_file.read())
                output_file.seek(0)
                output_file.truncate()
                data[variable] = renderer.serialize()
                output_file.write(json.dumps(data, indent=4))
        else:
            with open(save_file, 'w') as output_file:
                output_file.write(json.dumps({variable: renderer.serialize()}))

    if renderer_type == 'stretched':
        if legend_ticks is not None and not legend_breaks:
            legend_ticks = [float(v) for v in legend_ticks.split(',')]

        legend = renderer.get_legend(
            image_height=lh,
            breaks=legend_breaks,
            ticks=legend_ticks,
            max_precision=legend_precision)[0].to_image()

    elif renderer_type == 'classified':
        legend = composite_elements(renderer.get_legend())

    legend.save(
        os.path.join(output_directory, '{0}_legend.png'.format(variable)))

    with Dataset(filenames[0]) as ds:
        var_obj = ds.variables[variable]
        dimensions = var_obj.dimensions
        shape = var_obj.shape
        num_dimensions = len(shape)

        if num_dimensions == 3:
            if id_variable:
                if shape[0] != ds.variables[id_variable][:].shape[0]:
                    raise click.BadParameter(
                        'must be same dimensionality as 3rd dimension of {0}'.
                        format(variable),
                        param='--id_variable',
                        param_hint='--id_variable')
            else:
                # Guess from the 3rd dimension
                guess = dimensions[0]
                if guess in ds.variables and ds.variables[guess][:].shape[
                        0] == shape[0]:
                    id_variable = guess

        ds_crs = get_crs(ds, variable)
        if not ds_crs and is_geographic(ds, variable):
            ds_crs = 'EPSG:4326'  # Assume all geographic data is WGS84

        src_crs = CRS.from_string(ds_crs) if ds_crs else CRS(
            {'init': src_crs}) if src_crs else None

        # get transforms, assume last 2 dimensions on variable are spatial in row, col order
        y_dim, x_dim = dimensions[-2:]
        coords = SpatialCoordinateVariables.from_dataset(
            ds,
            x_dim,
            y_dim,
            projection=Proj(src_crs.to_dict()) if src_crs else None)

        if mask is not None and not mask.shape == shape[-2:]:
            # Will likely break before this if collecting statistics
            raise click.BadParameter(
                'mask variable shape does not match shape of input spatial dimensions',
                param='--mask',
                param_hint='--mask')

        flip_y = False
        reproject_kwargs = None
        if dst_crs is not None:
            if not src_crs:
                raise click.BadParameter('must provide src_crs to reproject',
                                         param='--src-crs',
                                         param_hint='--src-crs')

            dst_crs = CRS.from_string(dst_crs)

            src_height, src_width = coords.shape
            dst_transform, dst_width, dst_height = calculate_default_transform(
                src_crs,
                dst_crs,
                src_width,
                src_height,
                *coords.bbox.as_list(),
                resolution=res)

            reproject_kwargs = {
                'src_crs': src_crs,
                'src_transform': coords.affine,
                'dst_crs': dst_crs,
                'dst_transform': dst_transform,
                'resampling': getattr(Resampling, resampling),
                'dst_shape': (dst_height, dst_width)
            }

        else:
            dst_transform = coords.affine
            dst_height, dst_width = coords.shape
            dst_crs = src_crs

            if coords.y.is_ascending_order():
                # Only needed if we are not already reprojecting the data, since that will flip it automatically
                flip_y = True

        if anchors or interactive_map:
            if not (dst_crs or src_crs):
                raise click.BadParameter(
                    'must provide at least src_crs to get Leaflet anchors or interactive map',
                    param='--src-crs',
                    param_hint='--src-crs')

            leaflet_anchors = get_leaflet_anchors(
                BBox.from_affine(
                    dst_transform,
                    dst_width,
                    dst_height,
                    projection=Proj(dst_crs) if dst_crs else None))

            if anchors:
                click.echo('Anchors: {0}'.format(leaflet_anchors))

    layers = {}
    for filename in filenames:
        with Dataset(filename) as ds:
            click.echo('Processing {0}'.format(filename))

            filename_root = os.path.split(filename)[1].replace('.nc', '')

            if not variable in ds.variables:
                raise click.BadParameter(
                    'variable {0} was not found in file: {1}'.format(
                        variable, filename),
                    param='variable',
                    param_hint='VARIABLE')

            var_obj = ds.variables[variable]
            if not var_obj.dimensions == dimensions:
                raise click.ClickException(
                    'All datasets must have the same dimensions for {0}'.
                    format(variable))

            if num_dimensions == 2:
                data = var_obj[:]
                if mask is not None:
                    data = numpy.ma.masked_array(data, mask=mask)
                image_filename = os.path.join(
                    output_directory,
                    '{0}_{1}.{2}'.format(filename_root, variable, format))
                if reproject_kwargs:
                    data = warp_array(data, **reproject_kwargs)
                render_image(renderer,
                             data,
                             image_filename,
                             scale,
                             flip_y=flip_y,
                             format=format)

                local_filename = os.path.split(image_filename)[1]
                layers[os.path.splitext(local_filename)[0]] = local_filename

            elif num_dimensions == 3:
                for index in range(shape[0]):
                    id = ds.variables[id_variable][
                        index] if id_variable is not None else index
                    image_filename = os.path.join(
                        output_directory,
                        '{0}_{1}__{2}.{3}'.format(filename_root, variable, id,
                                                  format))
                    data = var_obj[index]
                    if mask is not None:
                        data = numpy.ma.masked_array(data, mask=mask)
                    if reproject_kwargs:
                        data = warp_array(data, **reproject_kwargs)
                    render_image(renderer,
                                 data,
                                 image_filename,
                                 scale,
                                 flip_y=flip_y,
                                 format=format)

                    local_filename = os.path.split(image_filename)[1]
                    layers[os.path.splitext(local_filename)
                           [0]] = local_filename

            # TODO: not tested recently.  Make sure still correct
            # else:
            #     # Assume last 2 components of shape are lat & lon, rest are iterated over
            #     id_variables = None
            #     if id_variable is not None:
            #         id_variables = id_variable.split(',')
            #         for index, name in enumerate(id_variables):
            #             if name:
            #                 assert data.shape[index] == ds.variables[name][:].shape[0]
            #
            #     ranges = []
            #     for dim in data.shape[:-2]:
            #         ranges.append(range(0, dim))
            #     for combined_index in product(*ranges):
            #         id_parts = []
            #         for index, dim_index in enumerate(combined_index):
            #             if id_variables is not None and index < len(id_variables) and id_variables[index]:
            #                 id = ds.variables[id_variables[index]][dim_index]
            #
            #                 if not isinstance(id, basestring):
            #                     if isinstance(id, Iterable):
            #                         id = '_'.join((str(i) for i in id))
            #                     else:
            #                         id = str(id)
            #
            #                 id_parts.append(id)
            #
            #             else:
            #                 id_parts.append(str(dim_index))
            #
            #         combined_id = '_'.join(id_parts)
            #         image_filename = os.path.join(output_directory, '{0}__{1}.{2}'.format(filename_root, combined_id, format))
            #         if reproject_kwargs:
            #             data = warp_array(data, **reproject_kwargs)  # NOTE: lack of index will break this
            #         render_image(renderer, data[combined_index], image_filename, scale, flip_y=flip_y, format=format)
            #
            #         local_filename = os.path.split(image_filename)[1]
            #         layers[os.path.splitext(local_filename)[0]] = local_filename

    if interactive_map:
        index_html = os.path.join(output_directory, 'index.html')
        with open(index_html, 'w') as out:
            template = Environment(
                loader=PackageLoader('trefoil.cli')).get_template('map.html')
            out.write(
                template.render(layers=json.dumps(layers),
                                bounds=str(leaflet_anchors),
                                variable=variable))

        webbrowser.open(index_html)
Esempio n. 46
0
def test_esri_auth__from_string():
    assert CRS.from_string('ESRI:54009').to_string() == 'ESRI:54009'
Esempio n. 47
0
def test_epsg():
    assert CRS({'init': 'epsg:4326'}).to_epsg() == 4326
    assert CRS.from_string('+proj=longlat +datum=WGS84 +no_defs').to_epsg() == 4326
Esempio n. 48
0
def map_eems(
        eems_file,
        # output_directory,
        scale,
        format,
        src_crs,
        resampling):
    """
    Render a NetCDF EEMS model to a web map.
    """

    from EEMSBasePackage import EEMSCmd, EEMSProgram

    model = EEMSProgram(eems_file)

    # For each data producing command, store the netcdf file that contains it
    file_vars = dict()
    raw_variables = set()
    for cmd in model.orderedCmds:  # This is bottom up, may want to invert
        filename = None
        variable = None
        if cmd.HasResultName():
            filename = cmd.GetParam('OutFileName')
            variable = cmd.GetResultName()
        elif cmd.IsReadCmd():
            filename = cmd.GetParam('OutFileName')
            variable = cmd.GetParam('NewFieldName')
            raw_variables.add(variable)

        if filename and variable:
            if not filename in file_vars:
                file_vars[filename] = []
            file_vars[filename].append(variable)

    filenames = file_vars.keys()
    for filename in filenames:
        if not os.path.exists(filename):
            raise click.ClickException(
                'Could not find data file from EEMS model: {0}'.format(
                    filename))

    dst_crs = 'EPSG:3857'

    output_directory = tempfile.mkdtemp()
    click.echo('Using temp directory: {0}'.format(output_directory))
    # if not os.path.exists(output_directory):
    #     os.makedirs(output_directory)

    # Since fuzzy renderer is hardcoded, we can output it now
    fuzzy_renderer = palette_to_stretched_renderer(DEFAULT_PALETTES['fuzzy'],
                                                   '1,-1')
    fuzzy_renderer.get_legend(image_height=150)[0].to_image().save(
        os.path.join(output_directory, 'fuzzy_legend.png'))

    template_filename = filenames[0]
    template_var = file_vars[template_filename][0]
    with Dataset(template_filename) as ds:
        var_obj = ds.variables[template_var]
        dimensions = var_obj.dimensions
        shape = var_obj.shape
        num_dimensions = len(shape)
        if num_dimensions != 2:
            raise click.ClickException(
                'Only 2 dimensions are allowed on data variables for now')

        ds_crs = get_crs(ds, template_var)
        if not ds_crs and is_geographic(ds, template_var):
            ds_crs = 'EPSG:4326'  # Assume all geographic data is WGS84

        src_crs = CRS.from_string(ds_crs) if ds_crs else CRS(
            {'init': src_crs}) if src_crs else None

        # get transforms, assume last 2 dimensions on variable are spatial in row, col order
        y_dim, x_dim = dimensions[-2:]
        coords = SpatialCoordinateVariables.from_dataset(
            ds, x_dim, y_dim, projection=Proj(src_crs) if src_crs else None)
        #
        #     if mask is not None and not mask.shape == shape[-2:]:
        #         # Will likely break before this if collecting statistics
        #         raise click.BadParameter(
        #             'mask variable shape does not match shape of input spatial dimensions',
        #             param='--mask', param_hint='--mask'
        #         )
        #
        if not src_crs:
            raise click.BadParameter('must provide src_crs to reproject',
                                     param='--src-crs',
                                     param_hint='--src-crs')

        dst_crs = CRS.from_string(dst_crs)

        src_height, src_width = coords.shape
        dst_transform, dst_width, dst_height = calculate_default_transform(
            src_crs, dst_crs, src_width, src_height, *coords.bbox.as_list())

        reproject_kwargs = {
            'src_crs': src_crs,
            'src_transform': coords.affine,
            'dst_crs': dst_crs,
            'dst_transform': dst_transform,
            'resampling': getattr(Resampling, resampling),
            'dst_shape': (dst_height, dst_width)
        }

        if not (dst_crs or src_crs):
            raise click.BadParameter(
                'must provide valid src_crs to get interactive map',
                param='--src-crs',
                param_hint='--src-crs')

        leaflet_anchors = get_leaflet_anchors(
            BBox.from_affine(dst_transform,
                             dst_width,
                             dst_height,
                             projection=Proj(dst_crs) if dst_crs else None))

    layers = {}
    for filename in filenames:
        with Dataset(filename) as ds:
            click.echo('Processing dataset {0}'.format(filename))

            for variable in file_vars[filename]:
                click.echo('Processing variable {0}'.format(variable))

                if not variable in ds.variables:
                    raise click.ClickException(
                        'variable {0} was not found in file: {1}'.format(
                            variable, filename))

                var_obj = ds.variables[variable]
                if not var_obj.dimensions == dimensions:
                    raise click.ClickException(
                        'All datasets must have the same dimensions for {0}'.
                        format(variable))

                data = var_obj[:]
                # if mask is not None:
                #     data = numpy.ma.masked_array(data, mask=mask)

                if variable in raw_variables:
                    palette = DEFAULT_PALETTES['raw']
                    palette_stretch = '{0},{1}'.format(data.max(), data.min())

                    renderer = palette_to_stretched_renderer(
                        palette, palette_stretch)
                    renderer.get_legend(
                        image_height=150, max_precision=2)[0].to_image().save(
                            os.path.join(output_directory,
                                         '{0}_legend.png'.format(variable)))
                else:
                    renderer = fuzzy_renderer

                image_filename = os.path.join(
                    output_directory, '{0}.{1}'.format(variable, format))
                data = warp_array(data, **reproject_kwargs)
                render_image(renderer,
                             data,
                             image_filename,
                             scale=scale,
                             format=format)

                local_filename = os.path.split(image_filename)[1]
                layers[variable] = local_filename

    index_html = os.path.join(output_directory, 'index.html')
    with open(index_html, 'w') as out:
        template = Environment(
            loader=PackageLoader('trefoil.cli')).get_template('eems_map.html')
        out.write(
            template.render(layers=json.dumps(layers),
                            bounds=str(leaflet_anchors),
                            tree=[[cmd, depth]
                                  for (cmd, depth) in model.GetCmdTree()],
                            raw_variables=list(raw_variables)))

    webbrowser.open(index_html)
Esempio n. 49
0
def test_crs_OSR_equivalence():
    crs1 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
    crs2 = CRS.from_string('+proj=latlong +datum=WGS84 +no_defs')
    crs3 = CRS({'init': 'epsg:4326'})
    assert crs1 == crs2
    assert crs1 == crs3
Esempio n. 50
0
    def __init__(self, array, bands, crs, transform,
                 nodataval, driver="GTiff", rio_ds=None):
        import rasterio
        import affine
        from rasterio.crs import CRS

        self._array = array
        self._bands = bands

        meta = {"driver": driver,
                "nodata": nodataval}

        # create metadata dictionary
        if array.dtype in Raster.FLOAT32:
            dtype = "float32"
        elif array.dtype in Raster.FLOAT64:
            dtype = "float64"
        elif array.dtype in Raster.INT8:
            dtype = "int8"
        elif array.dtype in Raster.INT16:
            dtype = "int16"
        elif array.dtype in Raster.INT32:
            dtype = "int32"
        elif array.dtype in Raster.INT64:
            dtype = "int64"
        else:
            raise TypeError("dtype cannot be determined from Raster")

        meta['dtype'] = dtype

        if isinstance(crs, CRS):
            pass
        elif isinstance(crs, int):
            crs = CRS.from_epsg(crs)
        elif isinstance(crs, str):
            crs = CRS.from_string(crs)
        else:
            TypeError("crs type not understood, provide an epsg or proj4")

        meta['crs'] = crs

        count, height, width = array.shape
        meta['count'] = count
        meta['height'] = height
        meta['width'] = width

        if not isinstance(transform, affine.Affine):
            raise TypeError("Transform must be defined by an Affine object")

        meta['transform'] = transform

        self._meta = meta
        self._dataset = None
        self.__arr_dict = {self._bands[b]: arr for
                           b, arr in enumerate(self._array)}

        self.__xcenters = None
        self.__ycenters = None

        if isinstance(rio_ds, rasterio.io.DatasetReader):
            self._dataset = rio_ds
Esempio n. 51
0
def test_from_wkt():
    wgs84 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
    from_wkt = CRS.from_wkt(wgs84.wkt)
    assert wgs84.wkt == from_wkt.wkt
Esempio n. 52
0
    def subset(self, raster_data, **kwargs):
        # It is possible our user has drawn a polygon where part of the
        # shape is outside the dataset,  intersect with the rasterdata
        # shape to make sure we don't try to select/mask data that is
        # outside the bounds of our dataset.

        # Convert the image corner coordinates to WGS84
        trgt_srs = CRS.from_string("EPSG:4326")
        src_srs = raster_data.crs
        transformed = [transform_coordinates(src_srs, trgt_srs, [i[0]], [i[1]])
                       for i in raster_data.shape.exterior.coords]
        reprojected_data_extent = sPolygon(transformed)
        clipped = self.intersection(reprojected_data_extent)

        # Polygon is completely outside the dataset, return whatever
        # would have been returned by get_data()
        if not bool(clipped):
            ul = raster_data.index(self.bounds[0], self.bounds[1])
            lr = raster_data.index(self.bounds[2], self.bounds[3])
            window = self.get_data_window(ul[0], ul[1], lr[0], lr[1])

            return raster_data.get_data(window=window, **kwargs)

        ul = raster_data.index(clipped.bounds[0], clipped.bounds[1])
        lr = raster_data.index(clipped.bounds[2], clipped.bounds[3])
        window = self.get_data_window(ul[0], ul[1], lr[0], lr[1])

        data = raster_data.get_data(window=window, **kwargs)

        # out_shape must be determined from data's shape,  get_data
        # may have returned a bounding box of data that is smaller than
        # the implicit shape of the window we passed.  e.g. if the window
        # is partially outside the extent of the raster data. Note that
        # we index with negative numbers here because we may or may not
        # have a time dimension.
        num_bands = len(raster_data.band_indexes)

        if num_bands > 1:
            out_shape = data.shape[-3], data.shape[-2]
        else:
            out_shape = data.shape[-2], data.shape[-1]

        coordinates = []
        for lat, lon in clipped.exterior.coords:
            x, y = raster_data.index(lat, lon)
            coordinates.append((y - window[0][1], x - window[0][0]))

        # Mask the final polygon
        mask = rasterize(
            [({'type': 'Polygon',
               'coordinates': [coordinates]}, 0)],
            out_shape=out_shape, fill=1, all_touched=True, dtype=np.uint8)

        # If we have more than one band,  expand the mask so it includes
        # A "channel" dimension (e.g.  shape is now (lat, lon, channel))
        if num_bands > 1:
            mask = mask[..., np.newaxis] * np.ones(num_bands)

        # Finally broadcast mask to data because data may be from a
        # Raster data collection and include a time component
        # (e.g.  shape could be (time, lat, lon),  or even
        #  (time, lat, lon, channels))
        _, mask = np.broadcast_arrays(data, mask)
        data[mask.astype(bool)] = raster_data.nodata

        return np.ma.masked_equal(data, raster_data.nodata)
Esempio n. 53
0
    def get(self, request, pk=None, project_pk=None, tile_type="", z="", x="", y="", scale=1):
        """
        Get a tile image
        """
        task = self.get_and_check_task(request, pk)

        z = int(z)
        x = int(x)
        y = int(y)

        scale = int(scale)
        ext = "png"
        driver = "jpeg" if ext == "jpg" else ext

        indexes = None
        nodata = None
        rgb_tile = None

        formula = self.request.query_params.get('formula')
        bands = self.request.query_params.get('bands')
        rescale = self.request.query_params.get('rescale')
        color_map = self.request.query_params.get('color_map')
        hillshade = self.request.query_params.get('hillshade')
        boundaries_feature = self.request.query_params.get('boundaries')
        if boundaries_feature == '':
            boundaries_feature = None
        if boundaries_feature is not None:
            try:
                boundaries_feature = json.loads(boundaries_feature)
            except json.JSONDecodeError:
                raise exceptions.ValidationError("Invalid boundaries parameter")

        if formula == '': formula = None
        if bands == '': bands = None
        if rescale == '': rescale = None
        if color_map == '': color_map = None
        if hillshade == '' or hillshade == '0': hillshade = None

        try:
            expr, _ = lookup_formula(formula, bands)
        except ValueError as e:
            raise exceptions.ValidationError(str(e))

        if tile_type in ['dsm', 'dtm'] and rescale is None:
            rescale = "0,1000"
        if tile_type == 'orthophoto' and rescale is None:
            rescale = "0,255"

        if tile_type in ['dsm', 'dtm'] and color_map is None:
            color_map = "gray"

        if tile_type == 'orthophoto' and formula is not None:
            if color_map is None:
                color_map = "gray"
            if rescale is None:
                rescale = "-1,1"

        if nodata is not None:
            nodata = np.nan if nodata == "nan" else float(nodata)
        tilesize = scale * 256
        url = get_raster_path(task, tile_type)
        if not os.path.isfile(url):
            raise exceptions.NotFound()

        with COGReader(url) as src:
            if not src.tile_exists(z, x, y):
                raise exceptions.NotFound("Outside of bounds")

        with COGReader(url) as src:
            minzoom, maxzoom = get_zoom_safe(src)
            has_alpha = has_alpha_band(src.dataset)
            if z < minzoom - ZOOM_EXTRA_LEVELS or z > maxzoom + ZOOM_EXTRA_LEVELS:
                raise exceptions.NotFound()
            if boundaries_feature is not None:
                try:
                    boundaries_cutline = create_cutline(src.dataset, boundaries_feature, CRS.from_string('EPSG:4326'))
                except:
                    raise exceptions.ValidationError("Invalid boundaries")
            else:
                boundaries_cutline = None
            # Handle N-bands datasets for orthophotos (not plant health)
            if tile_type == 'orthophoto' and expr is None:
                ci = src.dataset.colorinterp
                # More than 4 bands?
                if len(ci) > 4:
                    # Try to find RGBA band order
                    if ColorInterp.red in ci and \
                            ColorInterp.green in ci and \
                            ColorInterp.blue in ci:
                        indexes = (ci.index(ColorInterp.red) + 1,
                                   ci.index(ColorInterp.green) + 1,
                                   ci.index(ColorInterp.blue) + 1,)
                    else:
                        # Fallback to first three
                        indexes = (1, 2, 3,)
                elif has_alpha:
                    indexes = non_alpha_indexes(src.dataset)

            # Workaround for https://github.com/OpenDroneMap/WebODM/issues/894
            if nodata is None and tile_type == 'orthophoto':
                nodata = 0

        resampling = "nearest"
        padding = 0
        if tile_type in ["dsm", "dtm"]:
            resampling = "bilinear"
            padding = 16

        try:
            with COGReader(url) as src:
                if expr is not None:
                    if boundaries_cutline is not None:
                        tile = src.tile(x, y, z, expression=expr, tilesize=tilesize, nodata=nodata,
                                        padding=padding,
                                        resampling_method=resampling, vrt_options={'cutline': boundaries_cutline})
                    else:
                        tile = src.tile(x, y, z, expression=expr, tilesize=tilesize, nodata=nodata,
                                        padding=padding,
                                        resampling_method=resampling)
                else:
                    if boundaries_cutline is not None:
                        tile = src.tile(x, y, z, tilesize=tilesize, nodata=nodata,
                                        padding=padding,
                                        resampling_method=resampling, vrt_options={'cutline': boundaries_cutline})
                    else:
                        tile = src.tile(x, y, z, indexes=indexes, tilesize=tilesize, nodata=nodata,
                                        padding=padding, resampling_method=resampling)

        except TileOutsideBounds:
            raise exceptions.NotFound("Outside of bounds")

        if color_map:
            try:
                colormap.get(color_map)
            except InvalidColorMapName:
                raise exceptions.ValidationError("Not a valid color_map value")
        
        intensity = None
        try:
            rescale_arr = list(map(float, rescale.split(",")))
        except ValueError:
            raise exceptions.ValidationError("Invalid rescale value")

        options = img_profiles.get(driver, {})
        if hillshade is not None:
            try:
                hillshade = float(hillshade)
                if hillshade <= 0:
                    hillshade = 1.0
            except ValueError:
                raise exceptions.ValidationError("Invalid hillshade value")
            if tile.data.shape[0] != 1:
                raise exceptions.ValidationError(
                    "Cannot compute hillshade of non-elevation raster (multiple bands found)")
            delta_scale = (maxzoom + ZOOM_EXTRA_LEVELS + 1 - z) * 4
            dx = src.dataset.meta["transform"][0] * delta_scale
            dy = -src.dataset.meta["transform"][4] * delta_scale
            ls = LightSource(azdeg=315, altdeg=45)
            # Hillshading is not a local tile operation and
            # requires neighbor tiles to be rendered seamlessly
            elevation = get_elevation_tiles(tile.data[0], url, x, y, z, tilesize, nodata, resampling, padding)
            intensity = ls.hillshade(elevation, dx=dx, dy=dy, vert_exag=hillshade)
            intensity = intensity[tilesize:tilesize * 2, tilesize:tilesize * 2]

        if intensity is not None:
            rgb = tile.post_process(in_range=(rescale_arr,))
            if colormap:
                rgb, _ = apply_cmap(rgb.data, colormap.get(color_map))
            if rgb.data.shape[0] != 3:
                raise exceptions.ValidationError(
                    "Cannot process tile: intensity image provided, but no RGB data was computed.")
            intensity = intensity * 255.0
            rgb = hsv_blend(rgb, intensity)
            if rgb is not None:
                return HttpResponse(
                    render(rgb, tile.mask, img_format=driver, **options),
                    content_type="image/{}".format(ext)
                )

        if color_map is not None:
            return HttpResponse(
                tile.post_process(in_range=(rescale_arr,)).render(img_format=driver, colormap=colormap.get(color_map),
                                                                  **options),
                content_type="image/{}".format(ext)
            )
        return HttpResponse(
            tile.post_process(in_range=(rescale_arr,)).render(img_format=driver, **options),
            content_type="image/{}".format(ext)
        )
Esempio n. 54
0
def test_from_wkt():
    wgs84 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
    from_wkt = CRS.from_wkt(wgs84.wkt)
    assert wgs84.wkt == from_wkt.wkt
Esempio n. 55
0
def rasterize(ctx, files, output, driver, like, bounds, dimensions, res,
              src_crs, all_touched, default_value, fill, prop, overwrite,
              nodata, creation_options):
    """Rasterize GeoJSON into a new or existing raster.

    If the output raster exists, rio-rasterize will rasterize feature
    values into all bands of that raster.  The GeoJSON is assumed to be
    in the same coordinate reference system as the output unless
    --src-crs is provided.

    --default_value or property values when using --property must be
    using a data type valid for the data type of that raster.

    If a template raster is provided using the --like option, the affine
    transform and data type from that raster will be used to create the
    output.  Only a single band will be output.

    The GeoJSON is assumed to be in the same coordinate reference system
    unless --src-crs is provided.

    --default_value or property values when using --property must be
    using a data type valid for the data type of that raster.

    --driver, --bounds, --dimensions, --res, --nodata are ignored when
    output exists or --like raster is provided

    If the output does not exist and --like raster is not provided, the
    input GeoJSON will be used to determine the bounds of the output
    unless provided using --bounds.

    --dimensions or --res are required in this case.

    If --res is provided, the bottom and right coordinates of bounds are
    ignored.

    Note
    ----

    The GeoJSON is not projected to match the coordinate reference
    system of the output or --like rasters at this time.  This
    functionality may be added in the future.

    """

    from rasterio.crs import CRS
    from rasterio.features import rasterize
    from rasterio.features import bounds as calculate_bounds

    output, files = resolve_inout(files=files,
                                  output=output,
                                  overwrite=overwrite)

    bad_param = click.BadParameter('invalid CRS.  Must be an EPSG code.',
                                   ctx,
                                   param=src_crs,
                                   param_hint='--src_crs')
    has_src_crs = src_crs is not None
    try:
        src_crs = CRS.from_string(src_crs) if has_src_crs else CRS.from_string(
            'EPSG:4326')
    except CRSError:
        raise bad_param

    # If values are actually meant to be integers, we need to cast them
    # as such or rasterize creates floating point outputs
    if default_value == int(default_value):
        default_value = int(default_value)
    if fill == int(fill):
        fill = int(fill)

    with ctx.obj['env']:

        def feature_value(feature):
            if prop and 'properties' in feature:
                return feature['properties'].get(prop, default_value)
            return default_value

        with click.open_file(files.pop(0) if files else '-') as gj_f:
            geojson = json.loads(gj_f.read())
        if 'features' in geojson:
            geometries = []
            for f in geojson['features']:
                geometries.append((f['geometry'], feature_value(f)))
        elif 'geometry' in geojson:
            geometries = ((geojson['geometry'], feature_value(geojson)), )
        else:
            raise click.BadParameter('Invalid GeoJSON',
                                     param=input,
                                     param_hint='input')

        geojson_bounds = geojson.get('bbox', calculate_bounds(geojson))

        if rasterio.shutil.exists(output):
            with rasterio.open(output, 'r+') as out:
                if has_src_crs and src_crs != out.crs:
                    raise click.BadParameter(
                        'GeoJSON does not match crs of '
                        'existing output raster',
                        param='input',
                        param_hint='input')

                if disjoint_bounds(geojson_bounds, out.bounds):
                    click.echo(
                        "GeoJSON outside bounds of existing output "
                        "raster. Are they in different coordinate "
                        "reference systems?",
                        err=True)

                meta = out.meta

                result = rasterize(geometries,
                                   out_shape=(meta['height'], meta['width']),
                                   transform=meta.get('affine',
                                                      meta['transform']),
                                   all_touched=all_touched,
                                   dtype=meta.get('dtype', None),
                                   default_value=default_value,
                                   fill=fill)

                for bidx in range(1, meta['count'] + 1):
                    data = out.read(bidx, masked=True)
                    # Burn in any non-fill pixels, and update mask accordingly
                    ne = result != fill
                    data[ne] = result[ne]
                    if data.mask.any():
                        data.mask[ne] = False
                    out.write(data, indexes=bidx)

        else:
            if like is not None:
                template_ds = rasterio.open(like)

                if has_src_crs and src_crs != template_ds.crs:
                    raise click.BadParameter(
                        'GeoJSON does not match crs of '
                        '--like raster',
                        param='input',
                        param_hint='input')

                if disjoint_bounds(geojson_bounds, template_ds.bounds):
                    click.echo(
                        "GeoJSON outside bounds of --like raster. "
                        "Are they in different coordinate reference "
                        "systems?",
                        err=True)

                kwargs = template_ds.profile
                kwargs['count'] = 1
                kwargs['transform'] = template_ds.transform

                template_ds.close()

            else:
                bounds = bounds or geojson_bounds

                if src_crs.is_geographic:
                    if (bounds[0] < -180 or bounds[2] > 180 or bounds[1] < -80
                            or bounds[3] > 80):
                        raise click.BadParameter(
                            "Bounds are beyond the valid extent for "
                            "EPSG:4326.",
                            ctx,
                            param=bounds,
                            param_hint='--bounds')

                if dimensions:
                    width, height = dimensions
                    res = ((bounds[2] - bounds[0]) / float(width),
                           (bounds[3] - bounds[1]) / float(height))

                else:
                    if not res:
                        raise click.BadParameter(
                            'pixel dimensions are required',
                            ctx,
                            param=res,
                            param_hint='--res')

                    elif len(res) == 1:
                        res = (res[0], res[0])

                    width = max(
                        int(ceil((bounds[2] - bounds[0]) / float(res[0]))), 1)
                    height = max(
                        int(ceil((bounds[3] - bounds[1]) / float(res[1]))), 1)

                kwargs = {
                    'count':
                    1,
                    'crs':
                    src_crs,
                    'width':
                    width,
                    'height':
                    height,
                    'transform':
                    Affine(res[0], 0, bounds[0], 0, -res[1], bounds[3]),
                    'driver':
                    driver
                }
                if driver:
                    kwargs["driver"] = driver

            kwargs.update(**creation_options)

            if nodata is not None:
                kwargs['nodata'] = nodata

            result = rasterize(geometries,
                               out_shape=(kwargs['height'], kwargs['width']),
                               transform=kwargs['transform'],
                               all_touched=all_touched,
                               dtype=kwargs.get('dtype', None),
                               default_value=default_value,
                               fill=fill)

            if 'dtype' not in kwargs:
                kwargs['dtype'] = result.dtype

            with rasterio.open(output, 'w', **kwargs) as out:
                out.write(result, indexes=1)
Esempio n. 56
0
def test_empty_json(arg):
    with Env(), pytest.raises(CRSError):
        CRS.from_string(arg)
Esempio n. 57
0
    def __init__(
        self,
        data,
        index_column=None,
        x_column=None,
        y_column=None,
        crs=None,
        res=None,
        **df_init_kws,
    ):
        """
        Initialize the land data frame instance.

        The default parameters are defined to work with SFSO data out-of-the-box, but
        they can be modified through the following keyword arguments:

        Parameters
        ----------
        data : ndarray (structured or homogeneous), Iterable, dict or DataFrame
            Data that will be passed to the initialization method of `pd.DataFrame`.
        index_column : str, optional
            Label of the index column. If `None` is provided, the value set in
            `settings.DEFAULT_INDEX_COLUMN` will be taken.
        x_column : str, optional
            Label of the x-coordinates column. If `None` is provided, the value set in
            `settings.DEFAULT_X_COLUMN` will be taken.
        y_column : str, optional
            Label of the y-coordinates column. If `None` is provided, the value set in
            `settings.DEFAULT_Y_COLUMN` will be taken.
        crs : str or rasterio CRS, optional
            Coordinate reference system, as string or as rasterio CRS object. If a
            string is provided, it will be passed to `rasterio.crs.CRS.from_string` to
            instantiatie a rasterio CRS object. If `None` is provided, the value set in
            `settings.DEFAULT_CRS` will be taken.
        res : tuple, optional
            The (x, y) resolution of the dataset. If `None` is provided, the value set
            in `settings.DEFAULT_RES` will be taken.
        """
        # init the pandas dataframe
        super(LandDataFrame, self).__init__(data, **df_init_kws)

        # set the index
        if index_column is None:
            index_column = settings.DEFAULT_INDEX_COLUMN
        if self.index.name != index_column:
            self.set_index(index_column, inplace=True)

        # set the rest of attributes
        if x_column is None:
            x_column = settings.DEFAULT_X_COLUMN
        if y_column is None:
            y_column = settings.DEFAULT_Y_COLUMN
        if crs is None:
            crs = CRS.from_string(settings.DEFAULT_CRS)
        elif isinstance(crs, str):
            crs = CRS.from_string(crs)
        if res is None:
            res = settings.DEFAULT_RES

        self.x_column = x_column
        self.y_column = y_column
        self.crs = crs
        self.res = res
Esempio n. 58
0
def test_deprecated_param(path_rgb_byte_tif):
    """dst_crs is deprecated"""
    with rasterio.open(path_rgb_byte_tif) as src:
        with pytest.warns(RasterioDeprecationWarning):
            vrt = WarpedVRT(src, dst_crs=DST_CRS)
            assert vrt.dst_crs == CRS.from_string(DST_CRS)
def quicklook_rgb_xr(
    xarr: xr.Dataset,
    rgb_varlist: List[str],
    scale_factor: Union[float, int],
    dwnscale_factor: float = 3,
    mask_nodata: bool = False,
) -> Tuple[np.ndarray, dict]:
    """
    Generate a quicklook RGB from an xarray object

    Parameters
    ----------
    xarr : xr.Dataset
        xarray dataset at a given instance, e.g.
        xarr = parent_xarr.isel(time=XX)
        where XX is the user specified time index

    rgb_varlist : list
        A list of variable names used to generate the RGB, e.g.
        rgb_varlist = ["lmbskyg_red", "lmbskyg_green", "lmbskyg_blue"]

    scale_factor : float or int
        scale factor to convert integer values to reflectances

    dwnscale_factor : float >= 1
        The downscaling factor.
        If dwnscale_factor = 3 then the spatial resolution
        of the quicklook RGB will be reduced by a factor
        of three from the native resolution of the sensors'
        RGB bands.

        If dwnscale_factor = 1 then no downscaling is
        performed, thus the native resolution of the RGB
        bands are used.

    mask_nodata : bool
        Whether to set nodata pixels [< 0 or > scale_factor] to grey
        in the quicklook RGB

    Returns
    -------
    rgb_im : numpy.ndarray
        RGB image with the following dimensions
        [nrows, ncols, 3] for the three channels

    rgb_meta : dict
        Metadata dictionary taken from rasterio

    Raises
    ------
    ValueError
        * if len(rgb_varlist) != 3
        * if dwnscale_factor < 1
    """
    if len(rgb_varlist) != 3:
        raise ValueError("rgb_bandlist must have three elements")

    src_trans = xarr.affine
    src_crs = CRS.from_string(xarr.attrs["crs"])

    # compute the downsample transform matrix
    dst_trans = src_trans * src_trans.scale(dwnscale_factor, dwnscale_factor)
    dst_nrows = int(xarr.dims["y"] / dwnscale_factor)
    dst_ncols = int(xarr.dims["x"] / dwnscale_factor)

    # create a rasterio-style metadata dict for destination
    # image. This will be needed in creating a shapefile
    # from the matplotlib polygon

    var_dtype = xarr.variables[rgb_varlist[0]].dtype
    nodata = xarr.variables[rgb_varlist[0]].attrs["nodata"]

    dst_meta = {
        "transform": dst_trans,
        "crs": src_crs,
        "height": dst_nrows,
        "width": dst_ncols,
        "dtype": var_dtype.name,
        "nodata": nodata,
        "count": 3,
        "driver": "GTiff",  # dummy
    }

    if dwnscale_factor > 1:

        refl_im = np.zeros([3, dst_nrows, dst_ncols], order="C", dtype=var_dtype)

        for z, varname in enumerate(rgb_varlist):
            var_ds = xarr.variables[varname]

            # resample
            reproject(
                source=var_ds.values,
                destination=refl_im[z, :, :],
                src_transform=src_trans,
                src_crs=src_crs,
                src_nodata=nodata,
                dst_transform=dst_trans,
                dst_crs=src_crs,  # keep the same projection
                dst_nodata=nodata,
                resampling=Resampling.nearest,
            )

    else:
        # dwnscale_factor = 1. This is likely to be memory intensive
        refl_im = np.array(
            [
                xarr.variables[rgb_varlist[0]].values,
                xarr.variables[rgb_varlist[1]].values,
                xarr.variables[rgb_varlist[2]].values,
            ],
            order="C",
        )

    # use NASA-OBPG SeaDAS's transformation to create a very pretty RGB
    rgb_im = seadas_style_rgb(
        refl_img=refl_im,
        rgb_ix=[0, 1, 2],
        scale_factor=scale_factor,
        mask_nodata=mask_nodata,
    )

    return rgb_im, dst_meta
Esempio n. 60
0
def test_crs_compound_epsg():
    assert CRS.from_string("EPSG:4326+3855").to_wkt().startswith("COMPD")