Esmaeilkiani commited on
Commit
5882ae2
1 Parent(s): 83c573a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +177 -0
app.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import ee
3
+ import geemap
4
+ import pandas as pd
5
+ from datetime import datetime, timedelta
6
+ import matplotlib.pyplot as plt
7
+ import folium
8
+ import os
9
+
10
+ # Constants
11
+ NDRE_HARVEST_THRESHOLD = 0.3
12
+ NDMI_HARVEST_THRESHOLD = 0.4
13
+ CSV_URL = "https://huggingface.co/datasets/your-username/sugarcane-farms/raw/main/farms.csv"
14
+ PRIVATE_KEY_PATH = os.environ.get("GEE_PRIVATE_KEY_PATH")
15
+
16
+ # Page configuration
17
+ st.set_page_config(page_title="Sugarcane Field Monitoring", layout="wide")
18
+
19
+ # GEE Authentication
20
+ def authenticate_gee():
21
+ try:
22
+ credentials = ee.ServiceAccountCredentials(None, PRIVATE_KEY_PATH)
23
+ ee.Initialize(credentials)
24
+ return True
25
+ except Exception as e:
26
+ st.error(f"Failed to authenticate with Google Earth Engine: {str(e)}")
27
+ return False
28
+
29
+ # Load farm data
30
+ @st.cache_data
31
+ def load_farm_data():
32
+ try:
33
+ df = pd.read_csv(CSV_URL)
34
+ if not all(col in df.columns for col in ["farm_name", "latitude", "longitude"]):
35
+ raise ValueError("CSV file is missing required columns")
36
+ return df
37
+ except Exception as e:
38
+ st.error(f"Error loading farm data: {str(e)}")
39
+ return None
40
+
41
+ # Get indices data from GEE
42
+ def get_indices_data(farm_coords, start_date, end_date):
43
+ point = ee.Geometry.Point(farm_coords)
44
+ s2 = ee.ImageCollection("COPERNICUS/S2_SR")
45
+
46
+ filtered = s2.filterBounds(point).filterDate(start_date, end_date)
47
+
48
+ def add_indices(image):
49
+ ndre = image.normalizedDifference(['B8', 'B5']).rename('NDRE')
50
+ ndmi = image.normalizedDifference(['B8A', 'B11']).rename('NDMI')
51
+ return image.addBands([ndre, ndmi])
52
+
53
+ with_indices = filtered.map(add_indices)
54
+
55
+ time_series = with_indices.select(['NDRE', 'NDMI']).getRegion(point, 500)
56
+
57
+ return time_series
58
+
59
+ # Extract index data from GEE results
60
+ def extract_index_data(data, index_name):
61
+ try:
62
+ dates = [datetime.utcfromtimestamp(d[3] / 1000) for d in data[1:]]
63
+ values = [float(d[4]) if d[4] is not None else None for d in data[1:]]
64
+ return pd.DataFrame({
65
+ 'date': dates,
66
+ index_name: values
67
+ }).dropna().set_index('date')
68
+ except Exception as e:
69
+ st.error(f"Error extracting {index_name} data: {str(e)}")
70
+ return pd.DataFrame()
71
+
72
+ # Main application
73
+ def main():
74
+ if not authenticate_gee():
75
+ return
76
+
77
+ st.title("Sugarcane Field Monitoring")
78
+
79
+ farm_data = load_farm_data()
80
+ if farm_data is None:
81
+ return
82
+
83
+ # Sidebar
84
+ st.sidebar.header("Settings")
85
+ farm_name = st.sidebar.selectbox("Select Farm", farm_data['farm_name'].tolist())
86
+ start_date = st.sidebar.date_input("Start Date", datetime.now() - timedelta(days=30))
87
+ end_date = st.sidebar.date_input("End Date", datetime.now())
88
+
89
+ if end_date > datetime.now().date():
90
+ st.sidebar.error("End date cannot be in the future.")
91
+ return
92
+
93
+ indices = st.sidebar.multiselect("Select Indices", ["NDRE", "NDMI"], default=["NDRE", "NDMI"])
94
+
95
+ if st.sidebar.button("Submit"):
96
+ farm_row = farm_data[farm_data['farm_name'] == farm_name].iloc[0]
97
+ farm_coords = [farm_row['longitude'], farm_row['latitude']]
98
+
99
+ with st.spinner("Fetching data..."):
100
+ gee_data = get_indices_data(farm_coords, start_date, end_date)
101
+
102
+ if gee_data:
103
+ ndre_data = extract_index_data(gee_data.getInfo(), "NDRE")
104
+ ndmi_data = extract_index_data(gee_data.getInfo(), "NDMI")
105
+
106
+ # Plotting
107
+ fig, ax = plt.subplots(figsize=(12, 6))
108
+
109
+ if "NDRE" in indices and not ndre_data.empty:
110
+ ax.plot(ndre_data.index, ndre_data["NDRE"], label="NDRE")
111
+ ax.axhline(y=NDRE_HARVEST_THRESHOLD, color='r', linestyle='--', label="NDRE Harvest Threshold")
112
+
113
+ if "NDMI" in indices and not ndmi_data.empty:
114
+ ax.plot(ndmi_data.index, ndmi_data["NDMI"], label="NDMI")
115
+ ax.axhline(y=NDMI_HARVEST_THRESHOLD, color='g', linestyle='--', label="NDMI Harvest Threshold")
116
+
117
+ ax.set_xlabel("Date")
118
+ ax.set_ylabel("Index Value")
119
+ ax.set_title(f"Time Series for {farm_name}")
120
+ ax.legend()
121
+
122
+ st.pyplot(fig)
123
+
124
+ # Harvest Analysis
125
+ if "NDRE" in indices and not ndre_data.empty:
126
+ if ndre_data["NDRE"].iloc[-1] > NDRE_HARVEST_THRESHOLD:
127
+ st.success("NDRE indicates the field may be ready for harvest.")
128
+ else:
129
+ st.info("NDRE suggests the field is not yet ready for harvest.")
130
+
131
+ if "NDMI" in indices and not ndmi_data.empty:
132
+ if ndmi_data["NDMI"].iloc[-1] > NDMI_HARVEST_THRESHOLD:
133
+ st.success("NDMI indicates good moisture content for harvest.")
134
+ else:
135
+ st.info("NDMI suggests suboptimal moisture content for harvest.")
136
+
137
+ # Map
138
+ m = geemap.Map(center=farm_coords, zoom=12)
139
+ m.add_basemap("OpenStreetMap")
140
+
141
+ if "NDRE" in indices:
142
+ ndre_layer = geemap.ee_tile_layer(
143
+ with_indices.select('NDRE').mean(),
144
+ {'min': 0, 'max': 1, 'palette': ['red', 'yellow', 'green']},
145
+ 'NDRE'
146
+ )
147
+ m.add_layer(ndre_layer)
148
+
149
+ if "NDMI" in indices:
150
+ ndmi_layer = geemap.ee_tile_layer(
151
+ with_indices.select('NDMI').mean(),
152
+ {'min': -1, 'max': 1, 'palette': ['red', 'white', 'blue']},
153
+ 'NDMI'
154
+ )
155
+ m.add_layer(ndmi_layer)
156
+
157
+ marker = folium.Marker(
158
+ location=farm_coords[::-1],
159
+ popup=f"Farm: {farm_name}<br>Lat: {farm_coords[1]}<br>Lon: {farm_coords[0]}"
160
+ )
161
+ marker.add_to(m)
162
+
163
+ m.to_streamlit(height=600)
164
+
165
+ # Map Download
166
+ map_html = m.to_html()
167
+ st.download_button(
168
+ label="Download Map",
169
+ data=map_html,
170
+ file_name="sugarcane_field_map.html",
171
+ mime="text/html"
172
+ )
173
+ else:
174
+ st.error("Failed to retrieve data from Google Earth Engine.")
175
+
176
+ if __name__ == "__main__":
177
+ main()