Skip to content

Commit 040a714

Browse files
authored
Merge pull request #29 from codeuniversity/feature/msavi-endpoint
Add MSAVI index to backend
2 parents 1ca0be7 + f9bc700 commit 040a714

File tree

17 files changed

+851
-71
lines changed

17 files changed

+851
-71
lines changed

backend/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ earthengine-api
22
python-dotenv
33
pandas
44
plotly
5-
fastapi
5+
fastapi[standard]
66
uvicorn

backend/src/cache/msavi_cache.py

Lines changed: 544 additions & 0 deletions
Large diffs are not rendered by default.

backend/src/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Unit(str, Enum):
2929
MM = "mm"
3030
PERCENT = "%"
3131
M3 = "m³/m³"
32+
DIMENSIONLESS = "Dimensionless"
3233

3334

3435
class LocationPolygon(Enum):

backend/src/routes/ndvi_router.py renamed to backend/src/controller/sat_index_controller.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
from datetime import datetime, timezone
22

3-
from fastapi import APIRouter, Query
3+
from fastapi import Query
44
from fastapi.responses import JSONResponse
55
from src.constants import (
6+
IndexType,
67
AggregationMethod,
78
LocationName,
89
TemporalResolution,
910
Unit,
1011
)
11-
from src.service import ndvi_service
12+
from src.service import sat_index_service
1213
from src.utils.temporal import get_optimistic_rounding
13-
from src.validation.models import NDVIResponse
1414
from src.validation.utils import (
1515
validate_timestamp_in_range_of_S2_imagery,
1616
validate_timestamp_start_date_before_end_date,
1717
)
1818

19-
ndvi_router = APIRouter()
2019

21-
22-
@ndvi_router.get("/ndvi", response_model=NDVIResponse)
23-
async def get_temperature_data(
20+
async def sat_index_controller(
21+
sat_index_type: IndexType,
2422
startDate: int = Query(...,
23+
2524
description="Start date as UNIX timestamp in seconds"),
2625
endDate: int = Query(...,
26+
2727
description="End date as UNIX timestamp in seconds"),
2828
location: LocationName = Query(..., description="Location name"),
2929
temporalResolution: TemporalResolution = Query(
3030
..., description="Temporal resolution"
3131
),
3232
aggregation: AggregationMethod = Query(...,
33+
3334
description="Aggregation method"),
3435
):
3536

@@ -42,7 +43,7 @@ async def get_temperature_data(
4243
start_date_dt, end_date_dt, temporalResolution
4344
)
4445

45-
data = ndvi_service(
46+
data = sat_index_service(
4647
location=location,
4748
temporal_resolution=temporalResolution,
4849
aggregation_method=aggregation,
@@ -62,4 +63,4 @@ async def get_temperature_data(
6263
"data": data,
6364
}
6465

65-
return JSONResponse(content=response)
66+
return JSONResponse(content=response)

backend/src/gee/caching_script.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import json
2+
3+
content = [
4+
{"timestamp": 1493251200, "value": 0.6265267304234295},
5+
{"timestamp": 1494720000, "value": 0.68603163673333},
6+
{"timestamp": 1494979200, "value": 0.755257128311451},
7+
]
8+
var_name = "msavi_daily_cache"
9+
file_name = "../cache/temp_cache.py"
10+
INDENT = " "
11+
12+
def combine_chache_with_update():
13+
# update existing cache
14+
return
15+
16+
def write_year(file, year, results):
17+
file.write(f"{INDENT}# Year {year}\n")
18+
19+
def write_results_to_cache(results: list, var_name: str, file_name: str):
20+
with open(file_name, "w") as file:
21+
file.write(f"{var_name} = [\n")
22+
for day in results:
23+
file.write(f"{INDENT}{json.dumps(day)},\n")
24+
file.write("]\n")
25+
file.close()
26+
27+
return
28+
29+
30+
# write_results_to_cache(content, var_name, file_name)
Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
import ee
2+
from ..constants import IndexType
23

34
INDEX_FEATURE_LABEL = "indexing_value"
45
TIMESTAMP_FEATURE_LABEL = "start_of_day_timestamp"
56
INDEX_NULL_STRING = "NULL"
67

78

8-
def calculate_mean_ndvi_GEE_SERVER(image: ee.Image, aoi: ee.Geometry.Polygon):
9-
ndvi = image.normalizedDifference(["B8", "B4"]).rename("NDVI")
10-
mean_ndvi = ndvi.reduceRegion(
9+
def get_index_image_by_index_type(index_type: IndexType, image: ee.Image):
10+
match index_type:
11+
case IndexType.NDVI:
12+
return image.normalizedDifference(["B8", "B4"]).rename("NDVI")
13+
case IndexType.MSAVI:
14+
return image.expression(
15+
expression="((2 * NIR + 1) - ((2 * NIR + 1)**2 - 8 * (NIR - RED))**0.5) / 2",
16+
opt_map={
17+
"NIR": image.select("B4"),
18+
"RED": image.select("B8"),
19+
},
20+
).rename("MSAVI")
21+
case _:
22+
return None
23+
24+
25+
def calculate_mean_index_GEE_SERVER(image: ee.Image, aoi: ee.Geometry.Polygon, index_type: IndexType):
26+
index_image = get_index_image_by_index_type(index_type, image)
27+
mean_index = index_image.reduceRegion(
1128
reducer=ee.Reducer.mean(), geometry=aoi, scale=10, maxPixels=1e8
12-
).get("NDVI")
13-
mean_ndvi = ee.Algorithms.If(
14-
ee.Algorithms.IsEqual(mean_ndvi, None), INDEX_NULL_STRING, mean_ndvi
29+
).get(index_type.value)
30+
31+
mean_index = ee.Algorithms.If(
32+
ee.Algorithms.IsEqual(mean_index, None), INDEX_NULL_STRING, mean_index
1533
)
16-
return image.set(INDEX_FEATURE_LABEL, mean_ndvi)
34+
return image.set(INDEX_FEATURE_LABEL, mean_index)
35+
1736

1837

1938
def calculate_start_of_day_timestamp_GEE_SERVER(image: ee.Image):
@@ -27,28 +46,28 @@ def calculate_start_of_day_timestamp_GEE_SERVER(image: ee.Image):
2746
return image.set(TIMESTAMP_FEATURE_LABEL, start_of_day)
2847

2948

30-
def get_ndvi_info(
31-
image_collection: ee.ImageCollection, coordinates: ee.Geometry.Polygon
49+
def get_sat_index_info(
50+
image_collection: ee.ImageCollection, coordinates: ee.Geometry.Polygon, index_type: IndexType
3251
):
3352
aoi = ee.Geometry.Polygon(coordinates)
3453

3554
# Setting indexing values Server side
36-
image_collection_with_ndvi = image_collection.map(
37-
lambda img: calculate_mean_ndvi_GEE_SERVER(img, aoi)
55+
image_collection_with_index = image_collection.map(
56+
lambda img: calculate_mean_index_GEE_SERVER(img, aoi, index_type)
3857
)
3958

4059
# Setting timestamps Server side
41-
image_collection_with_timestamp_and_ndvi = image_collection_with_ndvi.map(
60+
image_collection_with_timestamp_and_index = image_collection_with_index.map(
4261
lambda img: calculate_start_of_day_timestamp_GEE_SERVER(img)
4362
)
4463

4564
# Getting indexing values to the client side
46-
index_value_list = image_collection_with_timestamp_and_ndvi.aggregate_array(
65+
index_value_list = image_collection_with_timestamp_and_index.aggregate_array(
4766
INDEX_FEATURE_LABEL
4867
).getInfo()
4968

5069
# Getting timestamps to the client
51-
timestamp_list = image_collection_with_timestamp_and_ndvi.aggregate_array(
70+
timestamp_list = image_collection_with_timestamp_and_index.aggregate_array(
5271
TIMESTAMP_FEATURE_LABEL
5372
).getInfo()
5473

backend/src/main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from fastapi import FastAPI
22
from fastapi.middleware.cors import CORSMiddleware
33

4-
from src.routes.ndvi_router import ndvi_router
4+
from src.routes.sat_index_router import sat_index_router
55

66
from .weather.router import router as weather_router
77

@@ -17,10 +17,11 @@
1717
allow_headers=["*"],
1818
)
1919

20+
2021
@app.get("/")
2122
def read_root():
2223
return {"Hello": "World"}
2324

2425

2526
app.include_router(weather_router, prefix="/weather", tags=["Weather Data"])
26-
app.include_router(ndvi_router, prefix="/index", tags=["NDVI Data"])
27+
app.include_router(sat_index_router, prefix="/index", tags=["Vegetation Indices"])

0 commit comments

Comments
 (0)