Asimuddin11 commited on
Commit
b2e615f
Β·
verified Β·
1 Parent(s): ef86bbb

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +412 -0
app.py ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import ee
3
+ import geemap.foliumap as geemap
4
+ import folium
5
+ import pandas as pd
6
+ import numpy as np
7
+ import plotly.express as px
8
+ import plotly.graph_objects as go
9
+ from datetime import datetime, date
10
+ import json
11
+
12
+ # Configure Streamlit page
13
+ st.set_page_config(
14
+ page_title="Interactive Landsat 9 Analysis",
15
+ page_icon="πŸ›°οΈ",
16
+ layout="wide",
17
+ initial_sidebar_state="expanded"
18
+ )
19
+
20
+ # Initialize Earth Engine function
21
+ @st.cache_resource
22
+ def init_ee_with_project(project_id=None):
23
+ try:
24
+ if project_id:
25
+ ee.Initialize(project=project_id)
26
+ else:
27
+ ee.Initialize()
28
+ return True, None
29
+ except Exception as e:
30
+ return False, str(e)
31
+
32
+ # Main title and description
33
+ st.title("πŸ›°οΈ Interactive Landsat 9 OLI/TIRS Analysis")
34
+ st.markdown("""
35
+ This interactive application allows you to analyze Landsat 9 satellite imagery with various spectral indices
36
+ and visualizations. Customize your analysis parameters using the sidebar controls.
37
+ """)
38
+
39
+ # Earth Engine initialization with project handling
40
+ ee_initialized = False
41
+
42
+ # Try to initialize without project first
43
+ success, error = init_ee_with_project()
44
+
45
+ if not success:
46
+ st.warning("Earth Engine initialization failed. Please provide your Google Cloud Project ID.")
47
+ st.info("""
48
+ **To get your Project ID:**
49
+ 1. Go to https://console.cloud.google.com/
50
+ 2. Create a new project or select an existing one
51
+ 3. Enable the Earth Engine API for your project
52
+ 4. Copy the Project ID from the project selector
53
+ """)
54
+
55
+ project_id = st.text_input(
56
+ "Enter your Google Cloud Project ID:",
57
+ help="Find this in your Google Cloud Console dashboard"
58
+ )
59
+
60
+ if project_id:
61
+ success, error = init_ee_with_project(project_id)
62
+ if success:
63
+ st.success(f"Successfully initialized Earth Engine with project: {project_id}")
64
+ ee_initialized = True
65
+ else:
66
+ st.error(f"Failed to initialize with project {project_id}: {error}")
67
+
68
+ if not ee_initialized:
69
+ st.stop()
70
+ else:
71
+ ee_initialized = True
72
+ st.success("Earth Engine initialized successfully!")
73
+
74
+ # Sidebar controls
75
+ st.sidebar.header("πŸŽ›οΈ Analysis Parameters")
76
+
77
+ # Location settings
78
+ st.sidebar.subheader("πŸ“ Location Settings")
79
+ center_lat = st.sidebar.number_input("Center Latitude", value=34.741, format="%.3f")
80
+ center_lon = st.sidebar.number_input("Center Longitude", value=71.878, format="%.3f")
81
+ buffer_size = st.sidebar.slider("Buffer Size (km)", min_value=10, max_value=100, value=50)
82
+
83
+ # Date range settings
84
+ st.sidebar.subheader("πŸ“… Date Range")
85
+ start_date = st.sidebar.date_input("Start Date", value=date(2022, 1, 1))
86
+ end_date = st.sidebar.date_input("End Date", value=date(2022, 12, 31))
87
+
88
+ # Cloud cover filter
89
+ cloud_cover = st.sidebar.slider("Maximum Cloud Cover (%)", min_value=0, max_value=100, value=20)
90
+
91
+ # Visualization options
92
+ st.sidebar.subheader("🎨 Visualization Options")
93
+ vis_options = {
94
+ "True Color (432)": {"bands": ["B4", "B3", "B2"], "min": 8000, "max": 18000},
95
+ "False Color (543)": {"bands": ["B5", "B4", "B3"], "min": 8000, "max": 20000},
96
+ "Agriculture (654)": {"bands": ["B6", "B5", "B4"], "min": 8000, "max": 20000},
97
+ "Geology (764)": {"bands": ["B7", "B6", "B4"], "min": 8000, "max": 20000},
98
+ "Bathymetric (431)": {"bands": ["B4", "B3", "B1"], "min": 8000, "max": 18000}
99
+ }
100
+
101
+ selected_vis = st.sidebar.selectbox("Select Band Combination", list(vis_options.keys()))
102
+
103
+ # Index calculations
104
+ st.sidebar.subheader("πŸ“Š Spectral Indices")
105
+ show_indices = st.sidebar.multiselect(
106
+ "Select Indices to Display",
107
+ ["NDVI", "EVI", "SAVI", "NDWI", "MNDWI", "NDBI", "NBR", "NDSI"],
108
+ default=["NDVI", "NDWI"]
109
+ )
110
+
111
+ # Analysis function
112
+ @st.cache_data
113
+ def perform_analysis(lat, lon, buffer_km, start_dt, end_dt, max_cloud):
114
+ # Define area of interest
115
+ aoi = ee.Geometry.Point([lon, lat]).buffer(buffer_km * 1000)
116
+
117
+ # Load Landsat 9 dataset
118
+ dataset = ee.ImageCollection('LANDSAT/LC09/C02/T1') \
119
+ .filterDate(start_dt.strftime('%Y-%m-%d'), end_dt.strftime('%Y-%m-%d')) \
120
+ .filterBounds(aoi) \
121
+ .filter(ee.Filter.lt('CLOUD_COVER', max_cloud)) \
122
+ .sort('CLOUD_COVER')
123
+
124
+ # Get dataset info
125
+ size = dataset.size().getInfo()
126
+
127
+ if size == 0:
128
+ return None, None, "No images found for the specified criteria."
129
+
130
+ # Create composite
131
+ composite = dataset.median().clip(aoi)
132
+
133
+ # Calculate indices
134
+ indices = {}
135
+
136
+ # Vegetation indices
137
+ indices['NDVI'] = composite.normalizedDifference(['B5', 'B4']).rename('NDVI')
138
+ indices['EVI'] = composite.expression(
139
+ '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
140
+ 'NIR': composite.select('B5'),
141
+ 'RED': composite.select('B4'),
142
+ 'BLUE': composite.select('B2')
143
+ }).rename('EVI')
144
+ indices['SAVI'] = composite.expression(
145
+ '((NIR - RED) / (NIR + RED + 0.5)) * (1 + 0.5)', {
146
+ 'NIR': composite.select('B5'),
147
+ 'RED': composite.select('B4')
148
+ }).rename('SAVI')
149
+
150
+ # Water indices
151
+ indices['NDWI'] = composite.normalizedDifference(['B3', 'B5']).rename('NDWI')
152
+ indices['MNDWI'] = composite.normalizedDifference(['B3', 'B6']).rename('MNDWI')
153
+
154
+ # Urban indices
155
+ indices['NDBI'] = composite.normalizedDifference(['B6', 'B5']).rename('NDBI')
156
+
157
+ # Burn index
158
+ indices['NBR'] = composite.normalizedDifference(['B5', 'B7']).rename('NBR')
159
+
160
+ # Snow index
161
+ indices['NDSI'] = composite.normalizedDifference(['B3', 'B6']).rename('NDSI')
162
+
163
+ # Calculate statistics
164
+ stats = {}
165
+ for name, index in indices.items():
166
+ stat = index.reduceRegion(
167
+ reducer=ee.Reducer.mean().combine(ee.Reducer.stdDev(), sharedInputs=True),
168
+ geometry=aoi,
169
+ scale=30,
170
+ maxPixels=1e9
171
+ ).getInfo()
172
+ stats[name] = stat
173
+
174
+ return composite, indices, stats, aoi, size
175
+
176
+ # Run analysis button
177
+ if st.sidebar.button("πŸš€ Run Analysis", type="primary"):
178
+ with st.spinner("Analyzing Landsat 9 imagery..."):
179
+ try:
180
+ result = perform_analysis(
181
+ center_lat, center_lon, buffer_size,
182
+ start_date, end_date, cloud_cover
183
+ )
184
+
185
+ if result[0] is None:
186
+ st.error(result[2])
187
+ else:
188
+ composite, indices, stats, aoi, image_count = result
189
+ st.success(f"Analysis complete! Found {image_count} images.")
190
+
191
+ # Store results in session state
192
+ st.session_state.composite = composite
193
+ st.session_state.indices = indices
194
+ st.session_state.stats = stats
195
+ st.session_state.aoi = aoi
196
+ st.session_state.analysis_params = {
197
+ 'lat': center_lat, 'lon': center_lon, 'buffer': buffer_size
198
+ }
199
+
200
+ except Exception as e:
201
+ st.error(f"Analysis failed: {str(e)}")
202
+
203
+ # Display results if analysis has been run
204
+ if 'composite' in st.session_state:
205
+ # Create tabs for different views
206
+ tab1, tab2, tab3, tab4 = st.tabs(["πŸ—ΊοΈ Interactive Map", "πŸ“Š Statistics", "πŸ“ˆ Charts", "πŸ“‹ Data Export"])
207
+
208
+ with tab1:
209
+ st.subheader("Interactive Satellite Imagery Map")
210
+
211
+ # Create the map
212
+ Map = geemap.Map(center=[st.session_state.analysis_params['lat'],
213
+ st.session_state.analysis_params['lon']], zoom=12)
214
+
215
+ # Add selected visualization
216
+ vis_params = vis_options[selected_vis]
217
+ Map.addLayer(
218
+ st.session_state.composite.select(vis_params['bands']),
219
+ {
220
+ 'min': vis_params['min'],
221
+ 'max': vis_params['max'],
222
+ 'bands': vis_params['bands']
223
+ },
224
+ selected_vis
225
+ )
226
+
227
+ # Add selected indices
228
+ index_vis_params = {
229
+ 'NDVI': {'min': -0.5, 'max': 0.8, 'palette': ['red', 'yellow', 'green']},
230
+ 'EVI': {'min': -0.5, 'max': 0.8, 'palette': ['red', 'yellow', 'green']},
231
+ 'SAVI': {'min': -0.5, 'max': 0.8, 'palette': ['red', 'yellow', 'green']},
232
+ 'NDWI': {'min': -0.5, 'max': 0.5, 'palette': ['white', 'blue']},
233
+ 'MNDWI': {'min': -0.5, 'max': 0.5, 'palette': ['white', 'blue']},
234
+ 'NDBI': {'min': -0.5, 'max': 0.5, 'palette': ['blue', 'white', 'red']},
235
+ 'NBR': {'min': -0.5, 'max': 0.5, 'palette': ['green', 'yellow', 'red']},
236
+ 'NDSI': {'min': 0, 'max': 0.8, 'palette': ['red', 'yellow', 'white']}
237
+ }
238
+
239
+ for index_name in show_indices:
240
+ if index_name in st.session_state.indices:
241
+ Map.addLayer(
242
+ st.session_state.indices[index_name].selfMask(),
243
+ index_vis_params[index_name],
244
+ index_name,
245
+ False # Start with layer hidden
246
+ )
247
+
248
+ # Add AOI boundary
249
+ Map.addLayer(st.session_state.aoi, {'color': 'yellow'}, 'Area of Interest')
250
+
251
+ # Display the map
252
+ Map.to_streamlit(height=600)
253
+
254
+ with tab2:
255
+ st.subheader("πŸ“Š Spectral Index Statistics")
256
+
257
+ # Create statistics dataframe
258
+ stats_data = []
259
+ for index_name, stat_dict in st.session_state.stats.items():
260
+ if index_name in show_indices:
261
+ mean_key = f"{index_name}_mean"
262
+ std_key = f"{index_name}_stdDev"
263
+
264
+ mean_val = stat_dict.get(mean_key, 0)
265
+ std_val = stat_dict.get(std_key, 0)
266
+
267
+ stats_data.append({
268
+ 'Index': index_name,
269
+ 'Mean': round(mean_val, 4) if mean_val else 0,
270
+ 'Standard Deviation': round(std_val, 4) if std_val else 0,
271
+ 'Range': f"{round(mean_val - std_val, 4)} to {round(mean_val + std_val, 4)}" if mean_val and std_val else "N/A"
272
+ })
273
+
274
+ if stats_data:
275
+ df_stats = pd.DataFrame(stats_data)
276
+ st.dataframe(df_stats, use_container_width=True)
277
+
278
+ # Create bar chart of mean values
279
+ fig_bar = px.bar(
280
+ df_stats,
281
+ x='Index',
282
+ y='Mean',
283
+ title='Mean Values of Spectral Indices',
284
+ color='Mean',
285
+ color_continuous_scale='viridis'
286
+ )
287
+ fig_bar.update_layout(height=400)
288
+ st.plotly_chart(fig_bar, use_container_width=True)
289
+
290
+ with tab3:
291
+ st.subheader("πŸ“ˆ Data Visualization")
292
+
293
+ # Index interpretation guide
294
+ with st.expander("πŸ“– Index Interpretation Guide"):
295
+ st.markdown("""
296
+ **Vegetation Indices:**
297
+ - **NDVI**: -1 to 1 (higher = more vegetation)
298
+ - **EVI**: -1 to 1 (enhanced vegetation, reduces atmospheric effects)
299
+ - **SAVI**: -1 to 1 (soil-adjusted vegetation index)
300
+
301
+ **Water Indices:**
302
+ - **NDWI**: -1 to 1 (higher = more water)
303
+ - **MNDWI**: -1 to 1 (modified NDWI, better for water detection)
304
+
305
+ **Urban/Built-up:**
306
+ - **NDBI**: -1 to 1 (higher = more built-up areas)
307
+
308
+ **Environmental:**
309
+ - **NBR**: -1 to 1 (normalized burn ratio for fire detection)
310
+ - **NDSI**: 0 to 1 (normalized difference snow index)
311
+ """)
312
+
313
+ # Create comparison chart if multiple indices selected
314
+ if len(show_indices) > 1:
315
+ comparison_data = []
316
+ for index_name in show_indices:
317
+ if index_name in st.session_state.stats:
318
+ stat_dict = st.session_state.stats[index_name]
319
+ mean_key = f"{index_name}_mean"
320
+ mean_val = stat_dict.get(mean_key, 0)
321
+ comparison_data.append({'Index': index_name, 'Mean Value': mean_val})
322
+
323
+ if comparison_data:
324
+ df_comparison = pd.DataFrame(comparison_data)
325
+ fig_comparison = px.bar(
326
+ df_comparison,
327
+ x='Index',
328
+ y='Mean Value',
329
+ title='Spectral Index Comparison',
330
+ color='Mean Value',
331
+ color_continuous_scale='RdYlGn'
332
+ )
333
+ fig_comparison.update_layout(height=400)
334
+ st.plotly_chart(fig_comparison, use_container_width=True)
335
+
336
+ with tab4:
337
+ st.subheader("πŸ“‹ Data Export Options")
338
+
339
+ col1, col2 = st.columns(2)
340
+
341
+ with col1:
342
+ st.markdown("**πŸ“Š Statistics Export**")
343
+ if st.button("Download Statistics as CSV"):
344
+ if 'stats' in st.session_state:
345
+ stats_data = []
346
+ for index_name, stat_dict in st.session_state.stats.items():
347
+ mean_key = f"{index_name}_mean"
348
+ std_key = f"{index_name}_stdDev"
349
+ stats_data.append({
350
+ 'Index': index_name,
351
+ 'Mean': stat_dict.get(mean_key, 0),
352
+ 'Standard_Deviation': stat_dict.get(std_key, 0)
353
+ })
354
+
355
+ df_export = pd.DataFrame(stats_data)
356
+ csv = df_export.to_csv(index=False)
357
+ st.download_button(
358
+ label="πŸ“₯ Download CSV",
359
+ data=csv,
360
+ file_name=f"landsat9_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
361
+ mime="text/csv"
362
+ )
363
+
364
+ with col2:
365
+ st.markdown("**πŸ—ΊοΈ Map Export**")
366
+ st.info("Use the map's built-in export tools to save visualizations as images.")
367
+
368
+ # Analysis summary
369
+ st.markdown("**πŸ“‹ Analysis Summary**")
370
+ summary_info = f"""
371
+ - **Location**: {st.session_state.analysis_params['lat']:.3f}Β°N, {st.session_state.analysis_params['lon']:.3f}Β°E
372
+ - **Buffer Size**: {st.session_state.analysis_params['buffer']} km
373
+ - **Date Range**: {start_date} to {end_date}
374
+ - **Cloud Cover**: ≀ {cloud_cover}%
375
+ - **Selected Visualization**: {selected_vis}
376
+ - **Active Indices**: {', '.join(show_indices)}
377
+ """
378
+ st.markdown(summary_info)
379
+
380
+ else:
381
+ # Instructions when no analysis has been run
382
+ st.info("πŸ‘ˆ Configure your analysis parameters in the sidebar and click 'Run Analysis' to get started!")
383
+
384
+ # Feature overview
385
+ st.markdown("""
386
+ ## 🌟 Features
387
+
388
+ **πŸ›°οΈ Satellite Data Analysis**
389
+ - Landsat 9 OLI/TIRS imagery (30m resolution)
390
+ - Customizable date ranges and cloud cover filtering
391
+ - Multiple band combinations for different applications
392
+
393
+ **πŸ“Š Spectral Indices**
394
+ - Vegetation: NDVI, EVI, SAVI
395
+ - Water: NDWI, MNDWI
396
+ - Urban: NDBI
397
+ - Environmental: NBR (burn), NDSI (snow)
398
+
399
+ **🎨 Interactive Visualizations**
400
+ - True color, false color, and specialized composites
401
+ - Statistical analysis and charting
402
+ - Export capabilities for further analysis
403
+
404
+ **πŸ—ΊοΈ Interactive Mapping**
405
+ - Zoom, pan, and layer control
406
+ - Real-time visualization switching
407
+ - Area of interest boundary display
408
+ """)
409
+
410
+ # Footer
411
+ st.markdown("---")
412
+ st.markdown("Built with ❀️ using Streamlit, Google Earth Engine, and geemap")