def algorithm(self, inputs, coordinates): cs = [Coordinates.from_xarray(x) for x in inputs.values()] if any(c != cs[0] for c in cs): raise NodeException("Cannot combine inputs with different coordinates") data = np.stack([inputs[key] for key in self.inputs], axis=-1) return self.create_output_array(cs[0], data=data)
def coordinates(self): if self.data is None: _log.warning("No coordinates found in EGI source") return Coordinates([], dims=[]) return Coordinates.from_xarray(self.data.coords, crs=self.data.attrs["crs"])
def open(cls, *args, **kwargs): """ Open an :class:`podpac.UnitsDataArray` from a file or file-like object containing a single data variable. This is a wrapper around :func:`xarray.open_datarray`. The inputs to this function are passed directly to :func:`xarray.open_datarray`. See http://xarray.pydata.org/en/stable/generated/xarray.open_dataarray.html#xarray.open_dataarray. The DataArray passed back from :func:`xarray.open_datarray` is used to create a units data array using :func:`creare_dataarray`. Returns ------- :class:`podpac.UnitsDataArray` """ da = xr.open_dataarray(*args, **kwargs) coords = Coordinates.from_xarray(da) # pass in kwargs to constructor uda_kwargs = {"attrs": da.attrs} if "output" in da.dims: uda_kwargs.update({"outputs": da.coords["output"]}) return cls.create(coords, data=da.data, **uda_kwargs)
def to_geotiff(fp, data, geotransform=None, crs=None, **kwargs): """Export a UnitsDataArray to a Geotiff Params ------- fp: str, file object or pathlib.Path object A filename or URL, a file object opened in binary ('rb') mode, or a Path object. If not supplied, the results will be written to a memfile object data: UnitsDataArray, xr.DataArray, np.ndarray The data to be saved. If there is more than 1 band, this should be the last dimension of the array. If given a np.ndarray, ensure that the 'lat' dimension is aligned with the rows of the data, with an appropriate geotransform. geotransform: tuple, optional The geotransform that describes the input data. If not given, will look for data.attrs['geotransform'] crs: str, optional The coordinate reference system for the data kwargs: **dict Additional key-word arguments that overwrite defaults used in the `rasterio.open` function. This function populates the following defaults: drive="GTiff" height=data.shape[0] width=data.shape[1] count=data.shape[2] dtype=data.dtype mode="w" Returns -------- MemoryFile, list If fp is given, results a list of the results for writing to each band r.append(dst.write(data[..., i], i + 1)) If fp is None, returns the MemoryFile object """ # This only works for data that essentially has lat/lon only dims = list(data.coords.keys()) if "lat" not in dims or "lon" not in dims: raise NotImplementedError("Cannot export GeoTIFF for dataset with lat/lon coordinates.") if "time" in dims and len(data.coords["time"]) > 1: raise NotImplemented("Cannot export GeoTIFF for dataset with multiple times,") if "alt" in dims and len(data.coords["alt"]) > 1: raise NotImplemented("Cannot export GeoTIFF for dataset with multiple altitudes.") # TODO: add proper checks, etc. to make sure we handle edge cases and throw errors when we cannot support # i.e. do work to remove this warning. _logger.warning("GeoTIFF export assumes data is in a uniform, non-rotated coordinate system.") # Get the crs and geotransform that describes the coordinates if crs is None: crs = data.attrs.get("crs") if crs is None: raise ValueError( "The `crs` of the data needs to be provided to save as GeoTIFF. If supplying a UnitsDataArray, created " " through a PODPAC Node, the crs should be automatically populated. If not, please file an issue." ) if geotransform is None: geotransform = data.attrs.get("geotransform") # Geotransform should ALWAYS be defined as (lon_origin, lon_dj, lon_di, lat_origin, lat_dj, lat_di) # if isinstance(data, xr.DataArray) and data.dims.index('lat') > data.dims.index('lon'): # geotransform = geotransform[3:] + geotransform[:3] if geotransform is None: try: geotransform = Coordinates.from_xarray(data).geotransform except (TypeError, AttributeError): raise ValueError( "The `geotransform` of the data needs to be provided to save as GeoTIFF. If the geotransform attribute " "wasn't automatically populated as part of the dataset, it means that the data is in a non-uniform " "coordinate system. This can sometimes happen when the data is transformed to a different CRS than the " "native CRS, which can cause the coordinates to seems non-uniform due to floating point precision. " ) # Make all types into a numpy array if isinstance(data, xr.DataArray): data = data.data # Get the data dtype = kwargs.get("dtype", np.float32) data = data.astype(dtype).squeeze() if len(data.shape) == 2: data = data[:, :, None] geotransform = affine.Affine.from_gdal(*geotransform) # Update the kwargs that rasterio will use. Anything added by the user will take priority. kwargs2 = dict( driver="GTiff", height=data.shape[0], width=data.shape[1], count=data.shape[2], dtype=data.dtype, crs=crs, transform=geotransform, ) kwargs2.update(kwargs) # Write the file if fp is None: # Write to memory file r = rasterio.io.MemoryFile() with r.open(**kwargs2) as dst: for i in range(data.shape[2]): dst.write(data[..., i], i + 1) else: r = [] kwargs2["mode"] = "w" with rasterio.open(fp, **kwargs2) as dst: for i in range(data.shape[2]): r.append(dst.write(data[..., i], i + 1)) return r