def write_fc_band_tile(fc, key, filename): slim_dataset = fc[[key]] # create a one band dataset attrs = slim_dataset[key].attrs.copy() # To get nodata in del attrs['crs'] # It's format is poor del attrs['units'] # It's format is poor slim_dataset[key] = fc.data_vars[key].astype('int16', copy=True) output_filename = filename + key + '_' + str(tile_no) + '_TEMP' + '.tif' write_geotiff(output_filename, slim_dataset, profile_override=attrs) return output_filename
def _save(ds, name): """ saves xarray as a local file :param xarray ds: An xarray :param str name: the file path including filename """ logging.debug(ds) logging.info('Writing file: %s', name) helpers.write_geotiff(name, ds)
def test_write_geotiff(tmpdir, odc_style_xr_dataset): """Ensure the geotiff helper writer works, and supports datasets smaller than 256x256.""" filename = tmpdir + '/test.tif' assert len(odc_style_xr_dataset.latitude) < 256 write_geotiff(filename, odc_style_xr_dataset) assert filename.exists() with rasterio.open(str(filename)) as src: written_data = src.read(1) assert (written_data == odc_style_xr_dataset['B10']).all()
def test_write_geotiff_str_crs(tmpdir, odc_style_xr_dataset): """Ensure the geotiff helper writer works, and supports crs as a string.""" filename = tmpdir + '/test.tif' original_crs = odc_style_xr_dataset.crs odc_style_xr_dataset.attrs['crs'] = str(original_crs) write_geotiff(filename, odc_style_xr_dataset) assert filename.exists() with rasterio.open(str(filename)) as src: written_data = src.read(1) assert (written_data == odc_style_xr_dataset['B10']).all() del odc_style_xr_dataset.attrs['crs'] with pytest.raises(ValueError): write_geotiff(filename, odc_style_xr_dataset)
def convert_to_tiff(filename, var=None, outputdir='geotiff'): if var is None: ds = xr.open_dataset(filename) varnames = list(ds.data_vars) if None in varnames: raise ValueError(varnames) else: ds = xr.open_dataset(filename) varnames = [var] for var in varnames: outputname = '%s/%s' % (outputdir, filename.split('/')[-1].replace( '.nc', '_%s.tif' % var.lower())) if os.path.exists(outputname): continue #print(outputname) try: ds_output = ds[var].to_dataset(name=var) except: print(ds.data_vars) #ds_output = ds_output.sortby('y', ascending=False) #ds = ds.astype('float64') ds_output.attrs['crs'] = geometry.CRS('EPSG:3577') #print(ds) helpers.write_geotiff(outputname, ds_output) return varnames
def dataset_to_geotif_yaml(dataset: xarray.Dataset, odc_dataset: Dataset, filename: Union[Path, str], variable_params=None): """ Write the dataset out as a set of geotifs with metadata in a yaml file. There will be one geotiff file per band. The band name is added into the file name. i.e ls8_fc.tif -> ls8_fc_BS.tif :param dataset: :param filename: Output filename :param variable_params: dict of variable_name: {param_name: param_value, [...]} Used to get band names. """ bands = variable_params.keys() abs_paths, _, yml = tif_filenames(filename, bands) Path(filename).parent.mkdir(parents=True, exist_ok=True) # Write out the yaml file with fileutils.atomic_save(str(yml)) as stream: yaml.safe_dump(odc_dataset.metadata_doc, stream, encoding='utf8') # Iterate over the bands for key, bandfile in abs_paths.items(): slim_dataset = dataset[[key]] # create a one band dataset attrs = slim_dataset[key].attrs.copy() # To get nodata in del attrs['crs'] # It's format is poor del attrs['units'] # It's format is poor slim_dataset[key] = dataset.data_vars[key].astype('int16', copy=True) write_geotiff(bandfile, slim_dataset.isel(time=0), profile_override=attrs)
query_2 = { "x": (central_lon - buffer, central_lon + buffer), "y": (central_lat - buffer, central_lat + buffer), "time": (postfire_start, postfire_end), "output_crs": "EPSG:32755", "resolution": (-10, 10) } postfire_data = load_ard( dc=dc, products=['s2a_ard_granule', 's2b_ard_granule'], measurements=['nbart_nir_1', 'nbart_swir_3'], min_gooddata=0, # dask_chunks={'x': 'auto', 'y': 'auto'}, group_by='solar_day', **query_2) postfire_image = postfire_data.median(dim='time') postfire_image = calculate_indices(postfire_image, index='NBR', collection='ga_s2_1', drop=False) postfire_burnratio = postfire_image.NBR postfire_burnratio.data delta_NBR = prefire_burnratio - postfire_burnratio # delta_NBR.compute() dnbr_dataset = delta_NBR.to_dataset(name='delta_NBR') write_geotiff(f'./scratch/wj97/ab4513/tumbarumba_dNBR_full.tif', dnbr_dataset)
def xr_rasterize(gdf, da, attribute_col=False, crs=None, transform=None, name=None, x_dim='x', y_dim='y', export_tiff=None, **rasterio_kwargs): """ Rasterizes a geopandas.GeoDataFrame into an xarray.DataArray. Parameters ---------- gdf : geopandas.GeoDataFrame A geopandas.GeoDataFrame object containing the vector/shapefile data you want to rasterise. da : xarray.DataArray or xarray.Dataset The shape, coordinates, dimensions, and transform of this object are used to build the rasterized shapefile. It effectively provides a template. The attributes of this object are also appended to the output xarray.DataArray. attribute_col : string, optional Name of the attribute column in the geodataframe that the pixels in the raster will contain. If set to False, output will be a boolean array of 1's and 0's. crs : str, optional CRS metadata to add to the output xarray. e.g. 'epsg:3577'. The function will attempt get this info from the input GeoDataFrame first. transform : affine.Affine object, optional An affine.Affine object (e.g. `from affine import Affine; Affine(30.0, 0.0, 548040.0, 0.0, -30.0, "6886890.0) giving the affine transformation used to convert raster coordinates (e.g. [0, 0]) to geographic coordinates. If none is provided, the function will attempt to obtain an affine transformation from the xarray object (e.g. either at `da.transform` or `da.geobox.transform`). x_dim : str, optional An optional string allowing you to override the xarray dimension used for x coordinates. Defaults to 'x'. Useful, for example, if x and y dims instead called 'lat' and 'lon'. y_dim : str, optional An optional string allowing you to override the xarray dimension used for y coordinates. Defaults to 'y'. Useful, for example, if x and y dims instead called 'lat' and 'lon'. export_tiff: str, optional If a filepath is provided (e.g 'output/output.tif'), will export a geotiff file. A named array is required for this operation, if one is not supplied by the user a default name, 'data', is used **rasterio_kwargs : A set of keyword arguments to rasterio.features.rasterize Can include: 'all_touched', 'merge_alg', 'dtype'. Returns ------- xarr : xarray.DataArray """ # Check for a crs object try: crs = da.geobox.crs except: try: crs = da.crs except: if crs is None: raise Exception( "Please add a `crs` attribute to the " "xarray.DataArray, or provide a CRS using the " "function's `crs` parameter (e.g. crs='EPSG:3577')") # Check if transform is provided as a xarray.DataArray method. # If not, require supplied Affine if transform is None: try: # First, try to take transform info from geobox transform = da.geobox.transform # If no geobox except: try: # Try getting transform from 'transform' attribute transform = da.transform except: # If neither of those options work, raise an exception telling the # user to provide a transform raise Exception( "Please provide an Affine transform object using the " "`transform` parameter (e.g. `from affine import " "Affine; Affine(30.0, 0.0, 548040.0, 0.0, -30.0, " "6886890.0)`") # Grab the 2D dims (not time) try: dims = da.geobox.dims except: dims = y_dim, x_dim # Coords xy_coords = [da[dims[0]], da[dims[1]]] # Shape try: y, x = da.geobox.shape except: y, x = len(xy_coords[0]), len(xy_coords[1]) # Reproject shapefile to match CRS of raster print(f'Rasterizing to match xarray.DataArray dimensions ({y}, {x}) ' f'and projection system/CRS (e.g. {crs})') try: gdf_reproj = gdf.to_crs(crs=crs) except: # Sometimes the crs can be a datacube utils CRS object # so convert to string before reprojecting gdf_reproj = gdf.to_crs(crs={'init': str(crs)}) # If an attribute column is specified, rasterise using vector # attribute values. Otherwise, rasterise into a boolean array if attribute_col: # Use the geometry and attributes from `gdf` to create an iterable shapes = zip(gdf_reproj.geometry, gdf_reproj[attribute_col]) else: # Use geometry directly (will produce a boolean numpy array) shapes = gdf_reproj.geometry # Rasterise shapes into an array arr = rasterio.features.rasterize(shapes=shapes, out_shape=(y, x), transform=transform, **rasterio_kwargs) # Convert result to a xarray.DataArray xarr = xr.DataArray(arr, coords=xy_coords, dims=dims, attrs=da.attrs, name=name if name else None) # Add back crs if xarr.attrs doesn't have it if 'crs' not in xarr.attrs: xarr.attrs['crs'] = str(crs) if export_tiff: print(f"Exporting GeoTIFF to {export_tiff}") ds = xarr.to_dataset(name=name if name else 'data') ds.attrs = xarr.attrs # xarray bug removes metadata, add it back write_geotiff(export_tiff, ds) return xarr
def test_write_geotiff_time_index_deprecated(): """The `time_index` parameter to `write_geotiff()` was a poorly thought out addition and is now deprecated.""" with pytest.raises(ValueError): write_geotiff("", None, time_index=1)
def _save(ds, name): helpers.write_geotiff(name, ds)
tv = tv_mask.where(data['PV'] > 0) # Calculate the proportion of time where total vegetation is greater than the bare soil fraction of a pixel # for the input year tv_summary = tv.mean(dim='time', skipna=True) # Create a boolean layer where vegetation is assigned if greater than .167 # tv_summary_filt = tv_summary > .167 # Convert booleans to binary # tv_summary_filt = tv_summary_filt * 1 # Change data type to float # tv_summary_filt = tv_summary_filt.data.astype(float) meta_d = data.isel(time=0).drop('time') out = xr.Dataset({'fc_summary': (meta_d.dims, tv_summary)}, coords=meta_d.coords, attrs=meta_d.attrs) helpers.write_geotiff('testarea_pvfcsummary.tif', out) tv_mask = data['BS'] < data['NPV'] tv = tv_mask.where(data['NPV'] > 0) # Calculate the proportion of time where total vegetation is greater than the bare soil fraction of a pixel # for the input year tv_summary = tv.mean(dim='time') # Create a boolean layer where vegetation is assigned if greater than .167 # tv_summary_filt = tv_summary > .167 # Convert booleans to binary # tv_summary_filt = tv_summary_filt * 1 # Change data type to float # tv_summary_filt = tv_summary_filt.data.astype(float) meta_d = data.isel(time=0).drop('time') out = xr.Dataset({'fc_summary': (meta_d.dims, tv_summary)},
dc = datacube.Datacube(config='/g/data/u46/users/sc0554/datacube.conf') # x = (1500000, 1600000) # y = (-4000000, -3900000) x = (1199685, 1299651) y = (-3800197, -3700025) product = 'fc' query = {'time': ('2015-01-01', '2015-12-31')} query['x'] = (x[0], x[1]) query['y'] = (y[0], y[1]) query['crs'] = 'EPSG:3577' mask_dict = { 'cloud_acca': 'no_cloud', 'cloud_fmask': 'no_cloud', 'contiguous': True } data = DEADataHandling.load_clearlandsat(dc=dc, query=query, product=product, masked_prop=0.1, mask_dict=mask_dict, satellite_metadata=True) meta_d = data.isel(time=0).drop('time') out = xr.Dataset({'fc': (meta_d.dims, data)}, coords=meta_d.coords, attrs=meta_d.attrs) helpers.write_geotiff('testarea.tif', out)
def dNBR_processing(coordinates): # Load all data in baseline period available from s2a/b_ard_granule datasets prefire_ard = load_ard( dc=dc, products=['s2a_ard_granule', 's2b_ard_granule'], x=(coordinates.x - 0.1, coordinates.x + 0.1), y=(coordinates.y - 0.1, coordinates.y + 0.1), time=(prefire_start, prefire_end), measurements=['nbart_nir_1', 'nbart_swir_3'], min_gooddata=0.1, output_crs='EPSG:32755', # UTM Zone 55S resolution=(-10, 10), group_by='solar_day') prefire_ard = calculate_indices(prefire_ard, index='NBR', collection='ga_s2_1', drop=False) # Compute median using all observations in the dataset along the time axis prefire_image = prefire_ard.median(dim='time') # Delete baseline_combined del prefire_ard # Select NBR prefire_NBR = prefire_image.NBR del prefire_image # Load all data in post-fire period available from s2a/b_ard_granule datasets postfire_ard = load_ard( dc=dc, products=['s2a_ard_granule', 's2b_ard_granule'], x=(coordinates.x - 0.1, coordinates.x + 0.1), y=(coordinates.y - 0.1, coordinates.y + 0.1), time=(postfire_start, postfire_end), measurements=['nbart_nir_1', 'nbart_swir_3'], min_gooddata=0.1, output_crs='EPSG:32755', # UTM Zone 55S resolution=(-10, 10), group_by='solar_day') # Calculate NBR on all post-fire images postfire_ard = calculate_indices(postfire_ard, index='NBR', collection='ga_s2_1', drop=False) # Calculate the median post-fire image postfire_image = postfire_ard.median(dim='time') del postfire_ard # Select NBR postfire_NBR = postfire_image.NBR del postfire_image # Calculate delta delta_NBR = prefire_NBR - postfire_NBR del prefire_NBR del postfire_NBR x = np.round_(coordinates.x, decimals=4) y = np.round_(coordinates.y, decimals=4) # Turn dNBR into a x-array dataset for export to GeoTIFF dnbr_dataset = delta_NBR.to_dataset(name='delta_NBR') # cog.write_cog(dnbr_dataset, './NBR_geotiffs/{x}_{y}_dNBR.tif') write_geotiff(f'/scratch/wj97/ab4513/dNBR_geotiffs/{x}_{y}_dNBR.tif', dnbr_dataset) del delta_NBR del dnbr_dataset