From 0e89b7f3bbfa185841c4c1995b9ee8755cb1a721 Mon Sep 17 00:00:00 2001 From: Wei Ji Date: Thu, 28 May 2020 20:27:09 +1200 Subject: [PATCH] :truck: Rename geo to spatiotemporal, and BBox to Region Found a better name than geo.py - spatiotemporal.py! Because time matters. Also renaming the BBox class to Region as the double capital letters in a row didn't look Pythonic. The Region.subset function has been revamped to be a lot more user friendly, giving the actual subsetted xr.Dataset instead of just the boolean array. --- atl11_play.ipynb | 14 +++++------ atl11_play.py | 16 +++++++------ deepicedrain/__init__.py | 2 +- deepicedrain/{geo.py => spatiotemporal.py} | 17 ++++++++----- tests/{test_bbox.py => test_region.py} | 28 +++++++++++----------- 5 files changed, 42 insertions(+), 35 deletions(-) rename deepicedrain/{geo.py => spatiotemporal.py} (74%) rename tests/{test_bbox.py => test_region.py} (60%) diff --git a/atl11_play.ipynb b/atl11_play.ipynb index 3d0b110..329e62d 100644 --- a/atl11_play.ipynb +++ b/atl11_play.ipynb @@ -277,19 +277,19 @@ "source": [ "# Dictionary of Antarctic bounding box locations with EPSG:3031 coordinates\n", "regions = {\n", - " \"kamb\": deepicedrain.BBox(\n", + " \"kamb\": deepicedrain.Region(\n", " name=\"Kamb Ice Stream\",\n", " xmin=-739741.7702261859,\n", " xmax=-411054.19240523444,\n", " ymin=-699564.516934089,\n", " ymax=-365489.6822096751,\n", " ),\n", - " \"antarctica\": deepicedrain.BBox(\"Antarctica\", -2700000, 2800000, -2200000, 2300000),\n", - " \"siple_coast\": deepicedrain.BBox(\n", + " \"antarctica\": deepicedrain.Region(\"Antarctica\", -2700000, 2800000, -2200000, 2300000),\n", + " \"siple_coast\": deepicedrain.Region(\n", " \"Siple Coast\", -1000000, 250000, -1000000, -100000\n", " ),\n", - " \"kamb2\": deepicedrain.BBox(\"Kamb Ice Stream\", -500000, -400000, -600000, -500000),\n", - " \"whillans\": deepicedrain.BBox(\n", + " \"kamb2\": deepicedrain.Region(\"Kamb Ice Stream\", -500000, -400000, -600000, -500000),\n", + " \"whillans\": deepicedrain.Region(\n", " \"Whillans Ice Stream\", -350000, -100000, -700000, -450000\n", " ),\n", "}" @@ -303,7 +303,7 @@ "source": [ "# Do the actual computation to find data points within region of interest\n", "region = regions[\"kamb\"] # Select Kamb Ice Stream region\n", - "ds_subset = ds.where(cond=region.subset(ds=ds), drop=True)\n", + "ds_subset = region.subset(ds=ds)\n", "ds_subset = ds_subset.unify_chunks()\n", "ds_subset = ds_subset.compute()" ] @@ -671,7 +671,7 @@ "source": [ "# Select region here, see dictionary of regions at top\n", "placename: str = \"antarctica\"\n", - "region: deepicedrain.BBox = regions[placename]" + "region: deepicedrain.Region = regions[placename]" ] }, { diff --git a/atl11_play.py b/atl11_play.py index 944f314..13717c5 100644 --- a/atl11_play.py +++ b/atl11_play.py @@ -148,19 +148,21 @@ # %% # Dictionary of Antarctic bounding box locations with EPSG:3031 coordinates regions = { - "kamb": deepicedrain.BBox( + "kamb": deepicedrain.Region( name="Kamb Ice Stream", xmin=-739741.7702261859, xmax=-411054.19240523444, ymin=-699564.516934089, ymax=-365489.6822096751, ), - "antarctica": deepicedrain.BBox("Antarctica", -2700000, 2800000, -2200000, 2300000), - "siple_coast": deepicedrain.BBox( + "antarctica": deepicedrain.Region( + "Antarctica", -2700000, 2800000, -2200000, 2300000 + ), + "siple_coast": deepicedrain.Region( "Siple Coast", -1000000, 250000, -1000000, -100000 ), - "kamb2": deepicedrain.BBox("Kamb Ice Stream", -500000, -400000, -600000, -500000), - "whillans": deepicedrain.BBox( + "kamb2": deepicedrain.Region("Kamb Ice Stream", -500000, -400000, -600000, -500000), + "whillans": deepicedrain.Region( "Whillans Ice Stream", -350000, -100000, -700000, -450000 ), } @@ -168,7 +170,7 @@ # %% # Do the actual computation to find data points within region of interest region = regions["kamb"] # Select Kamb Ice Stream region -ds_subset = ds.where(cond=region.subset(ds=ds), drop=True) +ds_subset = region.subset(ds=ds) ds_subset = ds_subset.unify_chunks() ds_subset = ds_subset.compute() @@ -317,7 +319,7 @@ # %% # Select region here, see dictionary of regions at top placename: str = "antarctica" -region: deepicedrain.BBox = regions[placename] +region: deepicedrain.Region = regions[placename] # %% # Find subglacial lakes (Smith et al., 2009) within region of interest diff --git a/deepicedrain/__init__.py b/deepicedrain/__init__.py index bd39aaf..ae5350b 100644 --- a/deepicedrain/__init__.py +++ b/deepicedrain/__init__.py @@ -1,4 +1,4 @@ __version__ = "0.1.0" -from deepicedrain.geo import BBox from deepicedrain.deltamath import calculate_delta +from deepicedrain.spatiotemporal import Region diff --git a/deepicedrain/geo.py b/deepicedrain/spatiotemporal.py similarity index 74% rename from deepicedrain/geo.py rename to deepicedrain/spatiotemporal.py index 93696ce..2aa0fe9 100644 --- a/deepicedrain/geo.py +++ b/deepicedrain/spatiotemporal.py @@ -1,5 +1,6 @@ """ -Geographic class that implements some handy geographic tools. +Geospatial and Temporal class that implements some handy tools. +Does bounding box region subsets, coordinate/time conversions, and more! """ import dataclasses @@ -8,10 +9,10 @@ @dataclasses.dataclass(frozen=True) -class BBox: +class Region: """ - A BoundingBox structure that outputs nice tuples of coordinates, - includes xarray subsetting capabilities and has a map scale property. + A nice region data structure that outputs a tuple of bounding box + coordinates, has xarray subsetting capabilities and a map scale property. """ name: str # name of region @@ -41,12 +42,16 @@ def bounds(self, style="lrbt") -> tuple: else: raise NotImplementedError(f"Unknown style type {style}") - def subset(self, ds: xr.Dataset, x_dim: str = "x", y_dim: str = "y") -> xr.Dataset: + def subset( + self, ds: xr.Dataset, x_dim: str = "x", y_dim: str = "y", drop: bool = True + ) -> xr.Dataset: """ Convenience function to find datapoints in an xarray.Dataset that fit within the bounding boxes of this region """ - return np.logical_and( + cond = np.logical_and( np.logical_and(ds[x_dim] > self.xmin, ds[x_dim] < self.xmax), np.logical_and(ds[y_dim] > self.ymin, ds[y_dim] < self.ymax), ) + + return ds.where(cond=cond, drop=drop) diff --git a/tests/test_bbox.py b/tests/test_region.py similarity index 60% rename from tests/test_bbox.py rename to tests/test_region.py index a2e3176..440f135 100644 --- a/tests/test_bbox.py +++ b/tests/test_region.py @@ -1,51 +1,51 @@ """ -Tests behaviour of the BBox class +Tests behaviour of the Region class """ import numpy as np import pytest import xarray as xr -from deepicedrain import BBox +from deepicedrain import Region -def test_bbox_scale(): +def test_region_scale(): """ - Tests that a map scale is output based on the BBox region. + Tests that a map scale is output based on the region. """ - region = BBox("Antarctica", -2700000, 2800000, -2200000, 2300000) + region = Region("Antarctica", -2700000, 2800000, -2200000, 2300000) assert region.scale == 27500000 -def test_bbox_bounds_lrbt(): +def test_region_bounds_lrbt(): """ Tests that PyGMT style bounds are given (by default). """ - region = BBox("Siple Coast", -1000000, 250000, -1000000, -100000) + region = Region("Siple Coast", -1000000, 250000, -1000000, -100000) assert region.bounds() == (-1000000, 250000, -1000000, -100000) -def test_bbox_bounds_lbrt(): +def test_region_bounds_lbrt(): """ Tests that Shapely style bounds are given """ - region = BBox("Whillans Ice Stream", -350000, -100000, -700000, -450000) + region = Region("Whillans Ice Stream", -350000, -100000, -700000, -450000) assert region.bounds(style="lbrt") == (-350000, -700000, -100000, -450000) -def test_bbox_bounds_ltrb(): +def test_region_bounds_ltrb(): """ Tests that error is raised when passing in a style that is not implemented. """ - region = BBox("Kamb Ice Stream", -500000, -400000, -600000, -500000) + region = Region("Kamb Ice Stream", -500000, -400000, -600000, -500000) with pytest.raises(NotImplementedError): print(region.bounds(style="ltrb")) -def test_bbox_subset(): +def test_region_subset(): """ Test that we can subset an xarray.Dataset based on the region's bounds """ - region = BBox("South Pole", -100, 100, -100, 100) + region = Region("South Pole", -100, 100, -100, 100) dataset = xr.Dataset( data_vars={"h_corr": (["x", "y"], np.random.rand(50, 50))}, coords={ @@ -53,6 +53,6 @@ def test_bbox_subset(): "y": np.linspace(start=-160, stop=160, num=50), }, ) - ds_subset = dataset.where(cond=region.subset(ds=dataset), drop=True) + ds_subset = region.subset(ds=dataset) assert isinstance(ds_subset, xr.Dataset) assert ds_subset.h_corr.shape == (24, 30)