Skip to content

Commit

Permalink
Merge pull request #24 from IndigoWizard/feature/enhanced-geojson-pro…
Browse files Browse the repository at this point in the history
…cessing

Enhanced GeoJSON Processing and Dynamic Map Focus
  • Loading branch information
IndigoWizard authored Oct 28, 2023
2 parents 32a37b4 + d6b2c7f commit 14c18ac
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 34 deletions.
4 changes: 2 additions & 2 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <a href="https://www.flaticon.com/free-icons/agriculture" title="agriculture icons">dreamicons - Flaticon</a>
The app was developped by [IndigoWizard](https://github.com/IndigoWizard) using; Streamlit, Google Earth Engine Python API, geemap, Folium. Agriculture icons created by <a href="https://www.flaticon.com/free-icons/agriculture" title="agriculture icons">dreamicons - Flaticon</a>

**Contributors**: [Emmarie-Ahtunan](https://github.com/Emmarie-Ahtunan)
122 changes: 91 additions & 31 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@
"""
<style>
/* Header*/
.css-1avcm0n{
.st-emotion-cache-1avcm0n{
height: 1rem;
}
/* Smooth scrolling*/
.main {
scroll-behavior: smooth;
}
/* main app body with less padding*/
.css-z5fcl4 {
.st-emotion-cache-z5fcl4 {
padding-block: 0;
}
/*Sidebar*/
.css-1544g2n {
.st-emotion-cache-10oheav {
padding: 0 1rem;
}
Expand Down Expand Up @@ -84,7 +84,7 @@
/* Upload info box */
/*Upload button: dark theme*/
.css-1erivf3.e1b2p2ww15 {
.st-emotion-cache-1erivf3 {
display: flex;
flex-direction: column;
align-items: inherit;
Expand All @@ -96,17 +96,44 @@
margin-inline: 0;
}
/*Upload button: light theme*/
.css-1gulkj5.e1b2p2ww15 {
.st-emotion-cache-1gulkj5 {
display: flex;
flex-direction: column;
align-items: inherit;
font-size: 14px;
}
.css-u8hs99.e1b2p2ww14 {
.st-emotion-cache-u8hs99 {
display: flex;
flex-direction: row;
margin-inline: 0;
}
/*Legend style*/
.ndvilegend {
transition: 0.2s ease-in-out;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
background: rgba(0, 0, 0, 0.05);
}
.ndvilegend:hover {
transition: 0.3s ease-in-out;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.12);
cursor: pointer;
}
.reclassifiedndvi {
transition: 0.2s ease-in-out;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
background: rgba(0, 0, 0, 0.05);
}
.reclassifiedndvi:hover {
transition: 0.3s ease-in-out;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.12);
cursor: pointer;
}
</style>
""", unsafe_allow_html=True)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
""")

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) \
Expand Down Expand Up @@ -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 = """
<div class="ndvilegend" style="border-radius: 5px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.05);">
<div class="ndvilegend">
<h5>Raw NDVI</h5>
<div style="display: flex; flex-direction: row; align-items: flex-start; gap: 1rem; width: 100%;">
<div style="width: 30px; height: 200px; background: linear-gradient({0},{1},{2},{3},{4},{5});"></div>
Expand All @@ -432,8 +487,8 @@ def classify_ndvi(masked_image): # better used an masked image to avoid water bo
with col4:
# Create an HTML legend for NDVI classes
reclassified_ndvi_legend_html = """
<div class="reclassifiedndvi" style="border-radius: 5px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.05);">
<h5>Reclassified NDVI</h5>
<div class="reclassifiedndvi">
<h5>NDVI Classes</h5>
<ul style="list-style-type: none; padding: 0;">
<li style="margin: 0.2em 0px; padding: 0;"><span style="color: {0};">&#9632;</span> Absent Vegetation. (Water/Clouds/Built-up/Rocks/Sand Surfaces..)</li>
<li style="margin: 0.2em 0px; padding: 0;"><span style="color: {1};">&#9632;</span> Bare Soil.</li>
Expand Down Expand Up @@ -499,17 +554,16 @@ def classify_ndvi(masked_image): # better used an masked image to avoid water bo

#### Miscs Info - END

#### About App - START
st.subheader("About:")
st.markdown("This project was first developed by me ([IndigoWizard](https://github.com/IndigoWizard)) and [Emmarie-Ahtunan](https://github.com/Emmarie-Ahtunan) as a submission to the **Environemental Data Challenge** of [Global Hack Week: Data](https://ghw.mlh.io/) by [Major League Hacking](https://mlh.io/).<br> I continued developing the base project to make it a feature-complete app. Check the project's GitHub Repo here: [IndigoWizard/NDVI-Viewer](https://github.com/IndigoWizard/NDVI-Viewer)", unsafe_allow_html=True)
st.image("https://www.pixenli.com/image/Hn1xkB-6")
#### About App - END

#### Contributiuon - START
st.header("Contribute to the App")
st.markdown("""
con1, con2 = st.columns(2)
con1.image("https://www.pixenli.com/image/SoL3iZMG")
con2.markdown("""
Contributions are welcome from the community to help improve this app! Whether you're interested in fixing bugs 🐞, implementing a new feature 🌟, or enhancing the user experience 🪄, your contributions are valuable.
The project is listed under **Hacktoberfest** lalbel for those of you [Hacktoberfest](https://hacktoberfest.com/) enthusiasts! Since the reward for contributing 4 PRs is getting a tree planted in your name through [TreeNation](https://tree-nation.com/), I see it fits the theme of this project.
""")
st.markdown("""
#### Ways to Contribute
- **Report Issues**: If you come across any bugs, issues, or unexpected behavior, please report them in the [GitHub Issue Tracker](https://github.com/IndigoWizard/NDVI-Viewer/issues).
Expand All @@ -521,6 +575,12 @@ def classify_ndvi(masked_image): # better used an masked image to avoid water bo

#### Contributiuon - START

#### About App - START
st.subheader("About:")
st.markdown("This project was first developed by me ([IndigoWizard](https://github.com/IndigoWizard)) and [Emmarie-Ahtunan](https://github.com/Emmarie-Ahtunan) as a submission to the **Environemental Data Challenge** of [Global Hack Week: Data](https://ghw.mlh.io/) by [Major League Hacking](https://mlh.io/).<br> I continued developing the base project to make it a feature-complete app. Check the project's GitHub Repo here: [IndigoWizard/NDVI-Viewer](https://github.com/IndigoWizard/NDVI-Viewer)", unsafe_allow_html=True)
st.image("https://www.pixenli.com/image/Hn1xkB-6")
#### About App - END

#### Credit - START
st.subheader("Credit:")
st.markdown("""The app was developped by [IndigoWizard](https://github.com/IndigoWizard) using; [Streamlit](https://streamlit.io/), [Google Earth Engine](https://github.com/google/earthengine-api) Python API, [geemap](https://github.com/gee-community/geemap), [Folium](https://github.com/python-visualization/folium). Agriculture icons created by <a href="https://www.flaticon.com/free-icons/agriculture" title="agriculture icons">dreamicons - Flaticon</a>""", unsafe_allow_html=True)
Expand Down
Binary file modified requirements.txt
Binary file not shown.

0 comments on commit 14c18ac

Please sign in to comment.