Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -18,328 +18,80 @@ eeservice = ee.ServiceAccountCredentials(credentials["client_email"], SERVICE_AC
|
|
18 |
ee.Initialize(eeservice)
|
19 |
|
20 |
# Load farm data
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
# Get time series data
|
94 |
-
time_series = satellite_data.getRegion(ee.Geometry.Point(farm_coords), 500).getInfo()
|
95 |
-
df = pd.DataFrame(time_series[1:], columns=time_series[0])
|
96 |
-
df['datetime'] = pd.to_datetime(df['time'], unit='ms')
|
97 |
-
df = df.sort_values('datetime')
|
98 |
-
|
99 |
-
# Plot time series
|
100 |
-
fig, ax = plt.subplots(figsize=(10, 5))
|
101 |
-
ax.plot(df['datetime'], df['NDVI'], label='NDVI')
|
102 |
-
ax.plot(df['datetime'], df['EVI'], label='EVI')
|
103 |
-
ax.plot(df['datetime'], df['SAVI'], label='SAVI')
|
104 |
-
ax.plot(df['datetime'], df['LAI'], label='LAI')
|
105 |
-
ax.set_xlabel('Date')
|
106 |
-
ax.set_ylabel('Index Value')
|
107 |
-
ax.set_title(f'Vegetation Indices Time Series for {farm_name}')
|
108 |
-
ax.legend()
|
109 |
-
st.pyplot(fig)
|
110 |
-
|
111 |
-
# Calculate statistics
|
112 |
-
lai_stats = df['LAI'].agg(['mean', 'max', 'min', 'std', 'var'])
|
113 |
-
st.write("LAI Statistics:")
|
114 |
-
st.write(f"Mean: {lai_stats['mean']:.2f}")
|
115 |
-
st.write(f"Max: {lai_stats['max']:.2f}")
|
116 |
-
st.write(f"Min: {lai_stats['min']:.2f}")
|
117 |
-
st.write(f"Standard Deviation: {lai_stats['std']:.2f}")
|
118 |
-
st.write(f"Variance: {lai_stats['var']:.2f}")
|
119 |
-
|
120 |
-
# Correlation analysis
|
121 |
-
st.write("\nCorrelation between indices:")
|
122 |
-
corr = df[['NDVI', 'EVI', 'SAVI', 'LAI']].corr()
|
123 |
-
fig, ax = plt.subplots(figsize=(8, 6))
|
124 |
-
sns.heatmap(corr, annot=True, cmap='coolwarm', ax=ax)
|
125 |
-
st.pyplot(fig)
|
126 |
-
|
127 |
-
return df
|
128 |
-
|
129 |
-
# Farm selection and date range for each year
|
130 |
-
st.sidebar.header("Farm Selection")
|
131 |
-
year_selection = st.sidebar.radio("Select Year", ["2023", "2024"])
|
132 |
-
|
133 |
-
farms_of_year = farms_df[farms_df['year'] == int(year_selection)]
|
134 |
-
selected_farms = st.sidebar.multiselect(
|
135 |
-
f"Select Farms for {year_selection}",
|
136 |
-
options=farms_of_year['name'].tolist(),
|
137 |
-
default=farms_of_year['name'].tolist()[:2] # Select first two farms by default
|
138 |
-
)
|
139 |
-
|
140 |
-
start_date = st.sidebar.date_input(f"Start Date for {year_selection}",
|
141 |
-
farms_of_year['planting_date'].min())
|
142 |
-
end_date = st.sidebar.date_input(f"End Date for {year_selection}",
|
143 |
-
datetime.now() if year_selection == "2024" else datetime(2024, 3, 20))
|
144 |
-
|
145 |
-
farm_data = []
|
146 |
-
for i, farm_name in enumerate(selected_farms):
|
147 |
-
farm_data.append(display_analysis(farm_name, start_date.isoformat(), end_date.isoformat(),
|
148 |
-
col1 if i % 2 == 0 else col2))
|
149 |
-
|
150 |
-
# Comparison and interpretation
|
151 |
-
if st.button('Compare and Interpret') and len(farm_data) >= 2:
|
152 |
-
st.write("Comparison and Interpretation:")
|
153 |
-
|
154 |
-
# LAI difference analysis
|
155 |
-
st.write("\nLAI Difference Analysis:")
|
156 |
-
fig, ax = plt.subplots(figsize=(12, 6))
|
157 |
-
for i, data in enumerate(farm_data):
|
158 |
-
ax.plot(data['datetime'], data['LAI'], label=selected_farms[i])
|
159 |
-
ax.set_xlabel('Date')
|
160 |
-
ax.set_ylabel('LAI')
|
161 |
-
ax.set_title(f'LAI Comparison for Selected Farms ({year_selection})')
|
162 |
-
ax.legend()
|
163 |
-
st.pyplot(fig)
|
164 |
-
|
165 |
-
# Regional comparison
|
166 |
-
st.write("\nRegional Comparison:")
|
167 |
-
avg_lai = pd.DataFrame({farm: data['LAI'].mean() for farm, data in zip(selected_farms, farm_data)}, index=['Average LAI'])
|
168 |
-
st.write(avg_lai)
|
169 |
-
|
170 |
-
fig, ax = plt.subplots(figsize=(10, 6))
|
171 |
-
avg_lai.T.plot(kind='bar', ax=ax)
|
172 |
-
ax.set_title(f'Average LAI Comparison for Selected Farms ({year_selection})')
|
173 |
-
ax.set_ylabel('Average LAI')
|
174 |
-
st.pyplot(fig)
|
175 |
-
|
176 |
-
# Strengths and weaknesses analysis
|
177 |
-
st.write("\nStrengths and Weaknesses Analysis:")
|
178 |
-
|
179 |
-
for farm, data in zip(selected_farms, farm_data):
|
180 |
-
st.write(f"\n{farm}:")
|
181 |
-
|
182 |
-
mean_lai = data['LAI'].mean()
|
183 |
-
lai_trend = np.polyfit(range(len(data['LAI'])), data['LAI'], 1)[0]
|
184 |
-
|
185 |
-
st.write(f"- Average LAI: {mean_lai:.2f}")
|
186 |
-
|
187 |
-
if mean_lai > 4:
|
188 |
-
st.write(" Strength: High LAI indicates dense, healthy vegetation.")
|
189 |
-
elif 2 <= mean_lai <= 4:
|
190 |
-
st.write(" Moderate LAI suggests average crop development.")
|
191 |
-
else:
|
192 |
-
st.write(" Weakness: Low LAI may indicate poor crop health or early growth stage.")
|
193 |
-
|
194 |
-
if lai_trend > 0:
|
195 |
-
st.write(f" Strength: Positive LAI trend (slope: {lai_trend:.4f}) suggests improving crop health.")
|
196 |
else:
|
197 |
-
st.
|
198 |
-
|
199 |
-
lai_variability = data['LAI'].std()
|
200 |
-
if lai_variability < 0.5:
|
201 |
-
st.write(" Strength: Low LAI variability suggests consistent crop conditions.")
|
202 |
-
else:
|
203 |
-
st.write(" Weakness: High LAI variability may indicate uneven crop development or stress.")
|
204 |
-
|
205 |
-
# LAI Prediction
|
206 |
-
st.write("\nLAI Prediction:")
|
207 |
-
for farm, data in zip(selected_farms, farm_data):
|
208 |
-
st.write(f"\nPredicting LAI for {farm}:")
|
209 |
-
|
210 |
-
X = data[['NDVI', 'EVI', 'SAVI']]
|
211 |
-
y = data['LAI']
|
212 |
-
|
213 |
-
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
214 |
-
|
215 |
-
model = RandomForestRegressor(n_estimators=100, random_state=42)
|
216 |
-
model.fit(X_train, y_train)
|
217 |
-
|
218 |
-
y_pred = model.predict(X_test)
|
219 |
-
|
220 |
-
mse = mean_squared_error(y_test, y_pred)
|
221 |
-
r2 = r2_score(y_test, y_pred)
|
222 |
-
|
223 |
-
st.write(f"Mean Squared Error: {mse:.4f}")
|
224 |
-
st.write(f"R-squared Score: {r2:.4f}")
|
225 |
-
|
226 |
-
# Plot actual vs predicted LAI
|
227 |
-
fig, ax = plt.subplots(figsize=(8, 6))
|
228 |
-
ax.scatter(y_test, y_pred)
|
229 |
-
ax.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
|
230 |
-
ax.set_xlabel('Actual LAI')
|
231 |
-
ax.set_ylabel('Predicted LAI')
|
232 |
-
ax.set_title(f'Actual vs Predicted LAI for {farm}')
|
233 |
-
st.pyplot(fig)
|
234 |
-
|
235 |
-
st.write("\nRecommendations:")
|
236 |
-
st.write("1. For areas with low LAI, consider investigating potential issues such as nutrient deficiencies, water stress, or pest problems.")
|
237 |
-
st.write("2. Monitor areas with high LAI variability to ensure uniform crop development.")
|
238 |
-
st.write("3. Use the LAI trend information to adjust management practices and optimize crop health throughout the growing season.")
|
239 |
-
st.write("4. Consider conducting ground-truthing in areas with significant LAI differences to validate satellite-based observations.")
|
240 |
-
st.write("5. Utilize the LAI prediction model to forecast future crop health and plan interventions accordingly.")
|
241 |
-
st.write("6. Pay attention to the correlation between different vegetation indices to gain a more comprehensive understanding of crop health.")
|
242 |
-
|
243 |
-
# Environmental analysis
|
244 |
-
st.write("\nEnvironmental Analysis:")
|
245 |
-
st.write("To perform a comprehensive environmental analysis, additional data sources for temperature, humidity, rainfall, and solar radiation would be required. This data could be integrated with the satellite imagery to provide insights into how environmental factors affect LAI and overall crop health.")
|
246 |
-
|
247 |
-
# GIS Advanced Features
|
248 |
-
st.write("\nAdvanced GIS Features:")
|
249 |
-
st.write("LAI Heatmap")
|
250 |
-
Map = geemap.Map()
|
251 |
-
farm_coords = farms_df[farms_df['name'] == selected_farms[0]][['longitude', 'latitude']].values[0]
|
252 |
-
Map.centerObject(ee.Geometry.Point(farm_coords), 13)
|
253 |
-
lai_heatmap = get_satellite_data(selected_farms[0], start_date.isoformat(), end_date.isoformat()).select('LAI').mean()
|
254 |
-
Map.addLayer(lai_heatmap, {'min': 0, 'max': 6, 'palette': ['blue', 'green', 'yellow', 'red']}, 'LAI Heatmap')
|
255 |
-
Map.to_streamlit(height=300)
|
256 |
-
|
257 |
-
# Year-over-year comparison
|
258 |
-
if st.button("Year-over-Year Comparison"):
|
259 |
-
st.write("\nYear-over-Year Comparison:")
|
260 |
-
|
261 |
-
# Get data for both years
|
262 |
-
data_2023 = [display_analysis(farm, "2023-09-29", "2024-03-20", st.empty())
|
263 |
-
for farm in farms_df[farms_df['year'] == 2023]['name']]
|
264 |
-
data_2024 = [display_analysis(farm, "2024-03-21", datetime.now().isoformat(), st.empty())
|
265 |
-
for farm in farms_df[farms_df['year'] == 2024]['name']]
|
266 |
-
|
267 |
-
# Calculate average LAI for each year
|
268 |
-
avg_lai_2023 = np.mean([data['LAI'].mean() for data in data_2023])
|
269 |
-
avg_lai_2024 = np.mean([data['LAI'].mean() for data in data_2024])
|
270 |
-
|
271 |
-
st.write(f"Average LAI for 2023: {avg_lai_2023:.2f}")
|
272 |
-
st.write(f"Average LAI for 2024: {avg_lai_2024:.2f}")
|
273 |
-
|
274 |
-
# Plot comparison
|
275 |
-
fig, ax = plt.subplots(figsize=(12, 6))
|
276 |
-
ax.bar(['2023', '2024'], [avg_lai_2023, avg_lai_2024])
|
277 |
-
ax.set_ylabel('Average LAI')
|
278 |
-
ax.set_title('Year-over-Year Comparison of Average LAI')
|
279 |
-
st.pyplot(fig)
|
280 |
-
|
281 |
-
# Calculate and display percentage change
|
282 |
-
percent_change = ((avg_lai_2024 - avg_lai_2023) / avg_lai_2023) * 100
|
283 |
-
st.write(f"Percentage change in LAI from 2023 to 2024: {percent_change:.2f}%")
|
284 |
-
|
285 |
-
if percent_change > 0:
|
286 |
-
st.write("The increase in LAI suggests improved crop health or more favorable growing conditions in 2024.")
|
287 |
-
elif percent_change < 0:
|
288 |
-
st.write("The decrease in LAI may indicate less favorable conditions or potential issues affecting crop health in 2024.")
|
289 |
-
else:
|
290 |
-
st.write("The LAI remains relatively stable between the two years, suggesting similar growing conditions.")
|
291 |
-
|
292 |
-
# Add a section for downloading the analysis report
|
293 |
-
if st.button("Generate Analysis Report"):
|
294 |
-
report = f"""
|
295 |
-
Sugar Beet Field Analysis Report
|
296 |
-
================================
|
297 |
-
|
298 |
-
Date of Analysis: {datetime.now().strftime('%Y-%m-%d')}
|
299 |
-
|
300 |
-
1. Farms Analyzed:
|
301 |
-
{', '.join(selected_farms)}
|
302 |
-
|
303 |
-
2. Analysis Period:
|
304 |
-
From {start_date} to {end_date}
|
305 |
-
|
306 |
-
3. Key Findings:
|
307 |
-
- Average LAI across all farms: {np.mean([data['LAI'].mean() for data in farm_data]):.2f}
|
308 |
-
- Highest LAI observed: {max([data['LAI'].max() for data in farm_data]):.2f}
|
309 |
-
- Lowest LAI observed: {min([data['LAI'].min() for data in farm_data]):.2f}
|
310 |
-
|
311 |
-
4. Farm-specific Analysis:
|
312 |
-
"""
|
313 |
-
|
314 |
-
for farm, data in zip(selected_farms, farm_data):
|
315 |
-
report += f"""
|
316 |
-
{farm}:
|
317 |
-
- Average LAI: {data['LAI'].mean():.2f}
|
318 |
-
- LAI Trend: {"Positive" if np.polyfit(range(len(data['LAI'])), data['LAI'], 1)[0] > 0 else "Negative"}
|
319 |
-
- LAI Variability: {"Low" if data['LAI'].std() < 0.5 else "High"}
|
320 |
-
"""
|
321 |
-
|
322 |
-
report += """
|
323 |
-
5. Recommendations:
|
324 |
-
- Monitor areas with low LAI for potential issues (nutrient deficiencies, water stress, pests)
|
325 |
-
- Ensure uniform crop development by addressing high LAI variability areas
|
326 |
-
- Adjust management practices based on LAI trends
|
327 |
-
- Validate satellite observations with ground-truthing in areas of significant LAI differences
|
328 |
-
- Use the LAI prediction model for proactive crop health management
|
329 |
-
- Consider the correlation between vegetation indices for comprehensive crop health assessment
|
330 |
-
|
331 |
-
6. Next Steps:
|
332 |
-
- Integrate environmental data (temperature, humidity, rainfall, solar radiation) for more comprehensive analysis
|
333 |
-
- Conduct regular follow-up analyses to track crop development over time
|
334 |
-
- Use insights from this analysis to inform precision agriculture practices
|
335 |
-
"""
|
336 |
-
|
337 |
-
st.download_button(
|
338 |
-
label="Download Analysis Report",
|
339 |
-
data=report,
|
340 |
-
file_name="sugar_beet_analysis_report.txt",
|
341 |
-
mime="text/plain"
|
342 |
-
)
|
343 |
-
|
344 |
-
st.write("Analysis complete. Use the buttons above to compare farms, view year-over-year changes, and generate a downloadable report.")
|
345 |
|
|
|
|
|
|
18 |
ee.Initialize(eeservice)
|
19 |
|
20 |
# Load farm data
|
21 |
+
farm_data_path = "tableConvert.com_wftamx (1).csv"
|
22 |
+
df = pd.read_csv(farm_data_path)
|
23 |
+
|
24 |
+
# Streamlit UI
|
25 |
+
st.title("NDVI Visualization for Dehkhoda Sugarcane Company")
|
26 |
+
st.markdown("Select a date range and farm to view NDVI over time.")
|
27 |
+
|
28 |
+
# Date input widgets
|
29 |
+
default_start = date(2023, 1, 1)
|
30 |
+
default_end = date(2023, 12, 31)
|
31 |
+
start_date = st.date_input("Start Date", default_start)
|
32 |
+
end_date = st.date_input("End Date", default_end)
|
33 |
+
|
34 |
+
# Farm selection
|
35 |
+
selected_farm = st.selectbox("Select Farm", df["name"].unique())
|
36 |
+
farm_info = df[df["name"] == selected_farm].iloc[0]
|
37 |
+
farm_geometry = ee.Geometry.Point([farm_info["longitude"], farm_info["latitude"]])
|
38 |
+
|
39 |
+
# NDVI or NDRE selection
|
40 |
+
index_type = st.selectbox("Select Vegetation Index", ["NDVI", "NDRE"])
|
41 |
+
band_selection = {"NDVI": ["B8", "B4"], "NDRE": ["B8", "B5"]}
|
42 |
+
|
43 |
+
if st.button("Generate NDVI Map"):
|
44 |
+
try:
|
45 |
+
# Convert to string
|
46 |
+
start_date_str = start_date.strftime("%Y-%m-%d")
|
47 |
+
end_date_str = end_date.strftime("%Y-%m-%d")
|
48 |
+
|
49 |
+
# Load Sentinel-2 Image Collection
|
50 |
+
s2 = ee.ImageCollection("COPERNICUS/S2")\
|
51 |
+
.filterDate(start_date_str, end_date_str)\
|
52 |
+
.filterBounds(farm_geometry)\
|
53 |
+
.filter(ee.Filter.listContains('system:band_names', 'B8'))\
|
54 |
+
.sort('system:time_start', False)
|
55 |
+
|
56 |
+
# Select latest available image
|
57 |
+
latest_image = s2.first()
|
58 |
+
|
59 |
+
if latest_image:
|
60 |
+
# Compute NDVI/NDRE
|
61 |
+
index_image = latest_image.normalizedDifference(band_selection[index_type]).rename(index_type).clip(farm_geometry)
|
62 |
+
|
63 |
+
# Check if valid data exists
|
64 |
+
index_stats = index_image.reduceRegion(
|
65 |
+
reducer=ee.Reducer.mean(),
|
66 |
+
geometry=farm_geometry,
|
67 |
+
scale=30,
|
68 |
+
bestEffort=True
|
69 |
+
).get(index_type)
|
70 |
+
|
71 |
+
if index_stats.getInfo() is None:
|
72 |
+
st.warning("No valid NDVI/NDRE data found for the selected date range.")
|
73 |
+
else:
|
74 |
+
st.success(f"NDVI/NDRE data found! Mean value: {index_stats.getInfo()}")
|
75 |
+
|
76 |
+
# Visualization parameters
|
77 |
+
vis_params = {
|
78 |
+
'min': -1, 'max': 1,
|
79 |
+
'palette': ['red', 'yellow', 'green']
|
80 |
+
}
|
81 |
+
|
82 |
+
# Create Folium map
|
83 |
+
m = folium.Map(location=[farm_info["latitude"], farm_info["longitude"]], zoom_start=13)
|
84 |
+
map_id_dict = index_image.getMapId(vis_params)
|
85 |
+
folium.TileLayer(
|
86 |
+
tiles=map_id_dict['tile_fetcher'].url_format,
|
87 |
+
attr='Google Earth Engine',
|
88 |
+
overlay=True,
|
89 |
+
name=index_type
|
90 |
+
).add_to(m)
|
91 |
+
folium.LayerControl().add_to(m)
|
92 |
+
folium_static(m)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
else:
|
94 |
+
st.warning("No Sentinel-2 images available for the selected date range and location.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
+
except Exception as e:
|
97 |
+
st.error(f"An error occurred: {e}")
|