diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 71e7777..15ee8a4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -10,7 +10,7 @@ All contribution is welcome (_adding features✨, bug fix🔧, bug report🐛, d - Open a new issue stating the subject of your upcoming contribution if no already existing open issue is related to the subject. - If it's a **one-time issue**, ask a maintainer to assign you to the issue before starting to work on it. - Always make sure your own fork of the repo is up to date (sync) with the original repo. - +- Updating the `Streamlit` package changes the class names of elements > Requires updating CSS class names. ### Issues - Issues are labbeled to make them easier for contributors/mantainers to identify. @@ -19,7 +19,7 @@ All contribution is welcome (_adding features✨, bug fix🔧, bug report🐛, d ### Branches -I'm using integrated GitFfow for this project, so the setup is: +I'm using integrated GitFlow for this project, so the setup is: **Branches:** - Master = streamlit-app diff --git a/README.md b/README.md index f72ca44..2ff70c5 100644 --- a/README.md +++ b/README.md @@ -40,4 +40,6 @@ This project was first developed as a submission to the Environemental Data Chal ### Credit -The app was developped by [IndigoWizard](https://github.com/IndigoWizard) and [Emmarie-Ahtunan](https://github.com/Emmarie-Ahtunan) using; Streamlit, Google Earth Engine Python API, geemap, Folium. Agriculture icons created by dreamicons - Flaticon +The app was developped by [IndigoWizard](https://github.com/IndigoWizard) using; Streamlit, Google Earth Engine Python API, geemap, Folium. Agriculture icons created by dreamicons - Flaticon + +**Contributors**: [Emmarie-Ahtunan](https://github.com/Emmarie-Ahtunan) diff --git a/app.py b/app.py index b1b2348..d09edff 100644 --- a/app.py +++ b/app.py @@ -23,7 +23,7 @@ """ """, unsafe_allow_html=True) @@ -148,27 +175,46 @@ def clipCollection(image): collection = collection.map(clipCollection) return collection -# Uplaod function +# Upload function +# Define a global variable to store the centroid of the last uploaded geometry +last_uploaded_centroid = None def upload_files_proc(upload_files): + # A global variable to track the latest geojson uploaded + global last_uploaded_centroid + # Setting up a variable that takes all polygons/geometries within the same/different geojson geometry_aoi_list = [] + for upload_file in upload_files: bytes_data = upload_file.read() - # Parse GeoJSON data geojson_data = json.loads(bytes_data) - # Extract the coordinates from the GeoJSON data - coordinates = geojson_data['features'][0]['geometry']['coordinates'] - # Creating gee geometry object based on coordinates - geometry = ee.Geometry.Polygon(coordinates) - # Adding geometry to the list - geometry_aoi_list.append(geometry) - # Combine multiple geometries from same/different files + + if 'features' in geojson_data and isinstance(geojson_data['features'], list): + # Handle GeoJSON files with a 'features' list + features = geojson_data['features'] + elif 'geometries' in geojson_data and isinstance(geojson_data['geometries'], list): + # Handle GeoJSON files with a 'geometries' list + features = [{'geometry': geo} for geo in geojson_data['geometries']] + else: + # handling cases of unexpected file format or missing 'features' or 'geometries' + continue + + for feature in features: + if 'geometry' in feature and 'coordinates' in feature['geometry']: + coordinates = feature['geometry']['coordinates'] + geometry = ee.Geometry.Polygon(coordinates) if feature['geometry']['type'] == 'Polygon' else ee.Geometry.MultiPolygon(coordinates) + geometry_aoi_list.append(geometry) + + # Update the last uploaded centroid + last_uploaded_centroid = geometry.centroid(maxError=1).getInfo()['coordinates'] + if geometry_aoi_list: geometry_aoi = ee.Geometry.MultiPolygon(geometry_aoi_list) else: - # Set default geometry if no file uploaded geometry_aoi = ee.Geometry.Point([27.98, 36.13]) + return geometry_aoi + # Time input processing function def date_input_proc(input_date, time_range): end_date = input_date @@ -196,8 +242,8 @@ def main(): - [Interpreting the Results](#interpreting-the-results) - [Environmental Index](#using-an-environmental-index-ndvi) - [Data](#data-sentinel-2-imagery-and-l2a-product) - - [About](#about) - [Contribution](#contribute-to-the-app) + - [About](#about) - [Credit](#credit) """) @@ -272,8 +318,17 @@ def main(): #### User input section - END #### Map section - START - # Setting up main map - m = folium.Map(location=[36.45, 2.85], tiles=None, zoom_start=9, control_scale=True) + global last_uploaded_centroid + + # Create the initial map + if last_uploaded_centroid is not None: + latitude = last_uploaded_centroid[1] + longitude = last_uploaded_centroid[0] + m = folium.Map(location=[latitude, longitude], tiles=None, zoom_start=12, control_scale=True) + else: + # Default location if no file is uploaded + m = folium.Map(location=[36.45, 10.85], tiles=None, zoom_start=4, control_scale=True) + ### BASEMAPS - START ## Primary basemaps @@ -347,7 +402,7 @@ def satImageMask(sat_image): updated_ndvi = satImageMask(updated_ndvi) # ##### NDVI classification: 7 classes - def classify_ndvi(masked_image): # better used an masked image to avoid water bodies obstracting the result + def classify_ndvi(masked_image): # better use a masked image to avoid water bodies obstracting the result as possible ndvi_classified = ee.Image(masked_image) \ .where(masked_image.gte(0).And(masked_image.lt(0.15)), 1) \ .where(masked_image.gte(0.15).And(masked_image.lt(0.25)), 2) \ @@ -414,7 +469,7 @@ def classify_ndvi(masked_image): # better used an masked image to avoid water bo with col3: # Create an HTML legend for NDVI classes ndvi_legend_html = """ -