Skip to content

Commit 6dc20ab

Browse files
authored
Merge pull request #1026 from CLIMADA-project/feature/improve_ee_import
Better handling of optional dependency import for earth-engine
2 parents eda7e40 + 2c34d49 commit 6dc20ab

File tree

1 file changed

+153
-142
lines changed

1 file changed

+153
-142
lines changed

climada/util/earth_engine.py

Lines changed: 153 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -26,148 +26,159 @@
2626
# That's why `earthengine-api` is not in the CLIMADA requirements.
2727
# See tutorial: climada_util_earth_engine.ipynb
2828
# pylint: disable=import-error
29-
import ee
30-
3129
LOGGER = logging.getLogger(__name__)
32-
ee.Initialize()
33-
34-
35-
def obtain_image_landsat_composite(landsat_collection, time_range, area):
36-
"""Selection of Landsat cloud-free composites in the Earth Engine library
37-
See also: https://developers.google.com/earth-engine/landsat
38-
39-
Parameters
40-
----------
41-
collection :
42-
name of the collection
43-
time_range : ['YYYY-MT-DY','YYYY-MT-DY']
44-
must be inside the available data
45-
area : ee.geometry.Geometry
46-
area of interest
47-
48-
Returns
49-
-------
50-
image_composite : ee.image.Image
51-
"""
52-
collection = ee.ImageCollection(landsat_collection)
53-
54-
# Filter by time range and location
55-
collection_time = collection.filterDate(time_range[0], time_range[1])
56-
image_area = collection_time.filterBounds(area)
57-
image_composite = ee.Algorithms.Landsat.simpleComposite(image_area, 75, 3)
58-
return image_composite
59-
60-
61-
def obtain_image_median(collection, time_range, area):
62-
"""Selection of median from a collection of images in the Earth Engine library
63-
See also: https://developers.google.com/earth-engine/reducers_image_collection
64-
65-
Parameters
66-
----------
67-
collection :
68-
name of the collection
69-
time_range : ['YYYY-MT-DY','YYYY-MT-DY']
70-
must be inside the available data
71-
area : ee.geometry.Geometry
72-
area of interest
73-
74-
Returns
75-
-------
76-
image_median : ee.image.Image
77-
"""
78-
collection = ee.ImageCollection(collection)
79-
80-
# Filter by time range and location
81-
collection_time = collection.filterDate(time_range[0], time_range[1])
82-
image_area = collection_time.filterBounds(area)
83-
image_median = image_area.median()
84-
return image_median
85-
86-
87-
def obtain_image_sentinel(sentinel_collection, time_range, area):
88-
"""Selection of median, cloud-free image from a collection of images in the Sentinel 2 dataset
89-
See also: https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2
90-
91-
Parameters
92-
----------
93-
collection :
94-
name of the collection
95-
time_range : ['YYYY-MT-DY','YYYY-MT-DY']
96-
must be inside the available data
97-
area : ee.geometry.Geometry
98-
area of interest
99-
100-
Returns
101-
-------
102-
sentinel_median : ee.image.Image
103-
"""
104-
105-
# First, method to remove cloud from the image
106-
def maskclouds(image):
107-
band_qa = image.select("QA60")
108-
cloud_mask = ee.Number(2).pow(10).int()
109-
cirrus_mask = ee.Number(2).pow(11).int()
110-
mask = band_qa.bitwiseAnd(cloud_mask).eq(0) and (
111-
band_qa.bitwiseAnd(cirrus_mask).eq(0)
112-
)
113-
return image.updateMask(mask).divide(10000)
114-
115-
sentinel_filtered = (
116-
ee.ImageCollection(sentinel_collection)
117-
.filterBounds(area)
118-
.filterDate(time_range[0], time_range[1])
119-
.filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE", 20))
120-
.map(maskclouds)
30+
31+
try:
32+
import ee
33+
34+
LOGGER.info("Google Earth Engine API successfully imported.")
35+
EE_AVAILABLE = True
36+
except ImportError:
37+
LOGGER.error(
38+
"Google Earth Engine API not found. Please install it using 'pip install earthengine-api'."
39+
)
40+
EE_AVAILABLE = False
41+
42+
if not EE_AVAILABLE:
43+
LOGGER.error(
44+
"Google Earth Engine API not found. Skipping the init of `earth_engine.py`."
12145
)
46+
else:
47+
ee.Initialize()
48+
49+
def obtain_image_landsat_composite(landsat_collection, time_range, area):
50+
"""Selection of Landsat cloud-free composites in the Earth Engine library
51+
See also: https://developers.google.com/earth-engine/landsat
52+
53+
Parameters
54+
----------
55+
collection :
56+
name of the collection
57+
time_range : ['YYYY-MT-DY','YYYY-MT-DY']
58+
must be inside the available data
59+
area : ee.geometry.Geometry
60+
area of interest
61+
62+
Returns
63+
-------
64+
image_composite : ee.image.Image
65+
"""
66+
collection = ee.ImageCollection(landsat_collection)
67+
68+
# Filter by time range and location
69+
collection_time = collection.filterDate(time_range[0], time_range[1])
70+
image_area = collection_time.filterBounds(area)
71+
image_composite = ee.Algorithms.Landsat.simpleComposite(image_area, 75, 3)
72+
return image_composite
73+
74+
def obtain_image_median(collection, time_range, area):
75+
"""Selection of median from a collection of images in the Earth Engine library
76+
See also: https://developers.google.com/earth-engine/reducers_image_collection
77+
78+
Parameters
79+
----------
80+
collection :
81+
name of the collection
82+
time_range : ['YYYY-MT-DY','YYYY-MT-DY']
83+
must be inside the available data
84+
area : ee.geometry.Geometry
85+
area of interest
86+
87+
Returns
88+
-------
89+
image_median : ee.image.Image
90+
"""
91+
collection = ee.ImageCollection(collection)
92+
93+
# Filter by time range and location
94+
collection_time = collection.filterDate(time_range[0], time_range[1])
95+
image_area = collection_time.filterBounds(area)
96+
image_median = image_area.median()
97+
return image_median
98+
99+
def obtain_image_sentinel(sentinel_collection, time_range, area):
100+
"""Selection of median, cloud-free image from a collection of images in the Sentinel 2
101+
dataset.
102+
See also: https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2
103+
104+
Parameters
105+
----------
106+
collection :
107+
name of the collection
108+
time_range : ['YYYY-MT-DY','YYYY-MT-DY']
109+
must be inside the available data
110+
area : ee.geometry.Geometry
111+
area of interest
112+
113+
Returns
114+
-------
115+
sentinel_median : ee.image.Image
116+
"""
117+
118+
# First, method to remove cloud from the image
119+
def maskclouds(image):
120+
band_qa = image.select("QA60")
121+
cloud_mask = ee.Number(2).pow(10).int()
122+
cirrus_mask = ee.Number(2).pow(11).int()
123+
mask = band_qa.bitwiseAnd(cloud_mask).eq(0) and (
124+
band_qa.bitwiseAnd(cirrus_mask).eq(0)
125+
)
126+
return image.updateMask(mask).divide(10000)
127+
128+
sentinel_filtered = (
129+
ee.ImageCollection(sentinel_collection)
130+
.filterBounds(area)
131+
.filterDate(time_range[0], time_range[1])
132+
.filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE", 20))
133+
.map(maskclouds)
134+
)
135+
136+
sentinel_median = sentinel_filtered.median()
137+
return sentinel_median
138+
139+
def get_region(geom):
140+
"""Get the region of a given geometry, needed for exporting tasks.
141+
142+
Parameters
143+
----------
144+
geom : ee.Geometry, ee.Feature, ee.Image
145+
region of interest
146+
147+
Returns
148+
-------
149+
region : list
150+
"""
151+
if isinstance(geom, ee.Geometry):
152+
return geom.getInfo()["coordinates"]
153+
if isinstance(geom, (ee.Feature, ee.Image)):
154+
return geom.geometry().getInfo()["coordinates"]
155+
raise ValueError(
156+
"parameter must be one of `ee.Geometry`, `ee.Feature`, `ee.Image`"
157+
)
158+
159+
def get_url(name, image, scale, region):
160+
"""It will open and download automatically a zip folder containing Geotiff data of 'image'.
161+
If additional parameters are needed, see also:
162+
https://github.com/google/earthengine-api/blob/master/python/ee/image.py
163+
164+
Parameters
165+
----------
166+
name : str
167+
name of the created folder
168+
image : ee.image.Image
169+
image to export
170+
scale : int
171+
resolution of export in meters (e.g: 30 for Landsat)
172+
region : list
173+
region of interest
174+
175+
Returns
176+
-------
177+
path : str
178+
"""
179+
path = image.getDownloadURL(
180+
{"name": (name), "scale": scale, "region": (region)}
181+
)
122182

123-
sentinel_median = sentinel_filtered.median()
124-
return sentinel_median
125-
126-
127-
def get_region(geom):
128-
"""Get the region of a given geometry, needed for exporting tasks.
129-
130-
Parameters
131-
----------
132-
geom : ee.Geometry, ee.Feature, ee.Image
133-
region of interest
134-
135-
Returns
136-
-------
137-
region : list
138-
"""
139-
if isinstance(geom, ee.Geometry):
140-
region = geom.getInfo()["coordinates"]
141-
elif isinstance(geom, ee.Feature, ee.Image):
142-
region = geom.geometry().getInfo()["coordinates"]
143-
elif isinstance(geom, list):
144-
condition = all([isinstance(item) == list for item in geom])
145-
if condition:
146-
region = geom
147-
return region
148-
149-
150-
def get_url(name, image, scale, region):
151-
"""It will open and download automatically a zip folder containing Geotiff data of 'image'.
152-
If additional parameters are needed, see also:
153-
https://github.com/google/earthengine-api/blob/master/python/ee/image.py
154-
155-
Parameters
156-
----------
157-
name : str
158-
name of the created folder
159-
image : ee.image.Image
160-
image to export
161-
scale : int
162-
resolution of export in meters (e.g: 30 for Landsat)
163-
region : list
164-
region of interest
165-
166-
Returns
167-
-------
168-
path : str
169-
"""
170-
path = image.getDownloadURL({"name": (name), "scale": scale, "region": (region)})
171-
172-
webbrowser.open_new_tab(path)
173-
return path
183+
webbrowser.open_new_tab(path)
184+
return path

0 commit comments

Comments
 (0)