forked from cabustillo13/earth_engine_backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstructure.json
More file actions
3 lines (3 loc) · 8.67 KB
/
structure.json
File metadata and controls
3 lines (3 loc) · 8.67 KB
1
2
3
{
"main.py": "import os\r\nfrom dotenv import load_dotenv\r\n\r\nimport ee\r\nimport folium\r\nimport matplotlib.pyplot as plt\r\n\r\nfrom fastapi import FastAPI, Request\r\nfrom fastapi.responses import HTMLResponse\r\nfrom fastapi.staticfiles import StaticFiles\r\nfrom starlette.templating import Jinja2Templates\r\n\r\nimport uvicorn\r\nfrom pydantic import BaseModel\r\nfrom starlette.responses import FileResponse\r\nfrom typing import Optional\r\n\r\n\r\n# Load environment variables from the .env file\r\nload_dotenv()\r\n\r\n# Retrieve the Earth Engine project name from the environment variables\r\nee_project = os.getenv('EE_PROJECT')\r\n\r\n# Initialize Earth Engine with the project name\r\nee.Initialize(project=ee_project)\r\n\r\n# FastAPI app\r\napp = FastAPI()\r\n\r\n# Get the absolute path to the static directory\r\nstatic_dir = os.path.abspath(\"static\")\r\n\r\n# Mount the static files\r\napp.mount(\"/static\", StaticFiles(directory=static_dir), name=\"static\")\r\n\r\n# Template directory for HTML rendering\r\ntemplates = Jinja2Templates(directory=\"templates\")\r\n\r\n# Define a model for the area of interest and date range\r\nclass AoiRequest(BaseModel):\r\n lat: Optional[float] = -32.88\r\n lon: Optional[float] = -68.84\r\n start_date: Optional[str] = '2024-01-01'\r\n end_date: Optional[str] = '2025-12-30'\r\n\r\n\r\n# Endpoint 0: Root\r\n@app.get(\"/\")\r\nasync def root():\r\n return {\"message\": \"Welcome to LESSAT 2024!\"}\r\n\r\n\r\n# Endpoint 1: Generate scatter plot of Red vs NIR\r\n@app.post(\"/generate-scatter-plot/\")\r\nasync def generate_scatter_plot(request: AoiRequest):\r\n aoi = ee.Geometry.Point([request.lon, request.lat])\r\n\r\n # Fetch Landsat 8 TOA images and filter by date and region\r\n landsat_collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\r\n .filterDate(request.start_date, request.end_date) \\\r\n .filterBounds(aoi)\r\n\r\n # Define a function to sample Red and NIR bands from each image\r\n def sample_image(image):\r\n return image.select(['B4', 'B5']).sample(region=aoi, scale=30, numPixels=500)\r\n\r\n # Map the sampling function over the collection\r\n sampled_images = landsat_collection.map(sample_image)\r\n\r\n # Flatten the sampled points into a single FeatureCollection\r\n all_samples = sampled_images.flatten()\r\n\r\n # Arrange the samples as a list of lists\r\n samp_dict = all_samples.reduceColumns(ee.Reducer.toList().repeat(2), ['B4', 'B5'])\r\n samp_list = ee.List(samp_dict.get('list'))\r\n\r\n # Save server-side ee.List as a client-side Python list\r\n samp_data = samp_list.getInfo()\r\n\r\n # Generate the scatter plot using matplotlib\r\n plt.scatter(samp_data[0], samp_data[1], alpha=0.2)\r\n plt.xlabel('Red (B4)', fontsize=12)\r\n plt.ylabel('NIR (B5)', fontsize=12)\r\n plt.title('Red vs. NIR Scatter Plot for Landsat Images')\r\n\r\n # Save the plot\r\n plot_filename = 'static/scatter_plot.png'\r\n plt.savefig(plot_filename)\r\n\r\n # Return the image as a response\r\n return FileResponse(plot_filename, media_type='image/png')\r\n\r\n@app.post(\"/generate-map/\")\r\nasync def generate_map(request: AoiRequest):\r\n aoi = ee.Geometry.Point([request.lon, request.lat])\r\n\r\n # Fetch Landsat 8 TOA images and filter by date and region\r\n landsat_collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\r\n .filterDate(request.start_date, request.end_date) \\\r\n .filterBounds(aoi)\r\n\r\n # Get the first image in the collection for visualization\r\n img = landsat_collection.first()\r\n\r\n # Get metadata from the first image\r\n img_info = img.getInfo()\r\n properties = img_info.get('properties', {})\r\n\r\n # Extract 5 key metadata items relevant to scientific analysis\r\n relevant_metadata = {\r\n 'Cloud Coverage': properties.get('CLOUD_COVER', 'N/A'),\r\n 'Sun Azimuth': properties.get('SUN_AZIMUTH', 'N/A'),\r\n 'Sun Elevation': properties.get('SUN_ELEVATION', 'N/A'),\r\n 'Earth-Sun Distance': properties.get('EARTH_SUN_DISTANCE', 'N/A'),\r\n 'Sensor Angle': properties.get('SENSOR_AZIMUTH', 'N/A')\r\n }\r\n\r\n # Create a Folium map centered on the AOI\r\n map_center = [request.lat, request.lon]\r\n m = folium.Map(location=map_center, zoom_start=8)\r\n\r\n # Function to add Earth Engine image to folium map\r\n def add_ee_layer(image, vis_params, name):\r\n map_id_dict = ee.Image(image).getMapId(vis_params)\r\n folium.TileLayer(\r\n tiles=map_id_dict['tile_fetcher'].url_format,\r\n attr='Google Earth Engine',\r\n name=name,\r\n overlay=True,\r\n control=True\r\n ).add_to(m)\r\n\r\n # Experimenting with auto-scaling or setting reasonable min/max values\r\n vis_params = {\r\n 'bands': ['B4', 'B3', 'B2'], # RGB bands\r\n 'min': 0, # Adjusted to minimum reflectance values\r\n 'max': 0.3, # Adjusted for TOA reflectance images\r\n 'gamma': 1.4\r\n }\r\n\r\n # Add the Landsat image layer to the Folium map\r\n add_ee_layer(img, vis_params, 'Landsat 8 RGB')\r\n\r\n # Add the AOI to the map\r\n folium.Marker(location=[request.lat, request.lon], popup='AOI', icon=folium.Icon(color='red')).add_to(m)\r\n\r\n # Add relevant metadata as a popup on the map\r\n metadata_html = \"<b>Landsat 8 Metadata<br>(Scientific Analysis):</b><br>\"\r\n for key, value in relevant_metadata.items():\r\n metadata_html += f\"{key}: {value}<br>\"\r\n\r\n metadata_popup = folium.Popup(html=metadata_html, max_width=300)\r\n folium.Marker(location=map_center, popup=metadata_popup).add_to(m)\r\n\r\n # Add base layers for context with attribution\r\n folium.TileLayer(\r\n tiles='Stamen Terrain',\r\n attr='Map data © OpenStreetMap contributors, CC-BY-SA, Stamen Design',\r\n name='Stamen Terrain',\r\n overlay=False,\r\n control=True\r\n ).add_to(m)\r\n\r\n folium.TileLayer(\r\n tiles='Stamen Toner',\r\n attr='Map data © OpenStreetMap contributors, CC-BY-SA, Stamen Design',\r\n name='Stamen Toner',\r\n overlay=False,\r\n control=True\r\n ).add_to(m)\r\n\r\n # Add layer control\r\n folium.LayerControl().add_to(m)\r\n\r\n # Save the map as an HTML file\r\n map_filename = \"static/map_with_metadata.html\"\r\n m.save(map_filename)\r\n\r\n # Return the HTML file\r\n return FileResponse(map_filename, media_type='text/html')\r\n\r\n\r\n\r\n# Landsat 8 Band Wavelengths (in micrometers)\r\nband_wavelengths = {\r\n 'B1': 0.44, # Coastal/Aerosol\r\n 'B2': 0.48, # Blue\r\n 'B3': 0.56, # Green\r\n 'B4': 0.66, # Red\r\n 'B5': 0.86, # NIR\r\n 'B6': 1.6, # SWIR1\r\n 'B7': 2.2, # SWIR2\r\n}\r\n\r\n# Endpoint to generate Reflectance vs Wavelength plot\r\n@app.post(\"/generate-reflectance-plot/\")\r\nasync def generate_reflectance_plot(request: AoiRequest):\r\n aoi = ee.Geometry.Point([request.lon, request.lat])\r\n \r\n # Fetch Landsat 8 TOA images and filter by date and region\r\n landsat_collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\r\n .filterDate(request.start_date, request.end_date) \\\r\n .filterBounds(aoi)\r\n \r\n # Get the first image in the collection\r\n img = landsat_collection.first()\r\n\r\n # Sample reflectance values at the AOI for each band\r\n reflectance = img.sample(region=aoi, scale=30).first().toDictionary()\r\n\r\n # Extract reflectance values for key bands (B1 to B7)\r\n reflectance_values = [\r\n reflectance.get(f'B{band}').getInfo() for band in range(1, 8)\r\n ]\r\n\r\n # Plot Reflectance vs Wavelength\r\n wavelengths = list(band_wavelengths.values())\r\n \r\n plt.figure(figsize=(10, 6))\r\n plt.plot(wavelengths, reflectance_values, marker='o', linestyle='-', color='b')\r\n plt.xlabel('Wavelength (µm)', fontsize=12)\r\n plt.ylabel('Reflectance', fontsize=12)\r\n plt.title('Reflectance vs Wavelength for Landsat 8', fontsize=14)\r\n plt.grid(True)\r\n \r\n # Save the plot\r\n plot_filename = 'static/reflectance_vs_wavelength.png'\r\n plt.savefig(plot_filename)\r\n \r\n # Return the plot as a response\r\n return FileResponse(plot_filename, media_type='image/png')\r\n\r\n\r\n# GET endpoint to serve the index.html\r\n@app.get(\"/fullAnswer/\", response_class=HTMLResponse)\r\nasync def display_dashboard(request: Request):\r\n return templates.TemplateResponse(\"fullOutput.html\", {\"request\": request})\r\n\r\n\r\n# Run the FastAPI app (use uvicorn in terminal to run the server)\r\nif __name__ == \"__main__\":\r\n uvicorn.run(app, host=\"127.0.0.1\", port=8000)\r\n"
}