lyimo commited on
Commit
08fa140
·
verified ·
1 Parent(s): bf26f29

Update part2_visualization.py

Browse files
Files changed (1) hide show
  1. part2_visualization.py +152 -172
part2_visualization.py CHANGED
@@ -3,10 +3,9 @@
3
  import plotly.graph_objects as go
4
  from plotly.subplots import make_subplots
5
  import folium
 
6
  import numpy as np
7
- import ee
8
- import geemap
9
- from branca.colormap import LinearColormap
10
 
11
  class VisualizationHandler:
12
  def __init__(self, optimal_conditions):
@@ -25,17 +24,56 @@ class VisualizationHandler:
25
  def create_interactive_plots(self, df):
26
  """Create enhanced interactive Plotly visualizations"""
27
  fig = make_subplots(
28
- rows=3, cols=1,
29
  subplot_titles=(
30
  '<b>Temperature (°C)</b>',
31
  '<b>Humidity (%)</b>',
32
- '<b>Rainfall (mm/day)</b>'
 
33
  ),
34
- vertical_spacing=0.12,
35
- row_heights=[0.33, 0.33, 0.33]
36
  )
37
 
38
- # Temperature plot with forecast types
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  for data_type, color in [('historical', 'royalblue'),
40
  ('forecast_5day', 'firebrick'),
41
  ('forecast_extended', 'rgba(255, 165, 0, 0.5)')]:
@@ -64,7 +102,7 @@ class VisualizationHandler:
64
  row=1, col=1
65
  )
66
 
67
- # Humidity plot with forecast types
68
  for data_type, color in [('historical', 'royalblue'),
69
  ('forecast_5day', 'firebrick'),
70
  ('forecast_extended', 'rgba(255, 165, 0, 0.5)')]:
@@ -93,7 +131,7 @@ class VisualizationHandler:
93
  row=2, col=1
94
  )
95
 
96
- # Rainfall plot with forecast types
97
  for data_type, color in [('historical', 'royalblue'),
98
  ('forecast_5day', 'firebrick'),
99
  ('forecast_extended', 'rgba(255, 165, 0, 0.5)')]:
@@ -109,151 +147,124 @@ class VisualizationHandler:
109
  row=3, col=1
110
  )
111
 
112
- # Add optimal ranges
113
- for row, (param, limits) in enumerate([
114
- ('temperature', self.optimal_conditions['temperature']),
115
- ('humidity', self.optimal_conditions['humidity']),
116
- ('rainfall', self.optimal_conditions['rainfall'])
117
- ], 1):
118
- fig.add_hline(y=limits['min'], line_dash="dash", line_color="green",
119
- annotation_text="Min Optimal", row=row, col=1)
120
- fig.add_hline(y=limits['max'], line_dash="dash", line_color="green",
121
- annotation_text="Max Optimal", row=row, col=1)
 
 
 
 
 
122
 
123
- # Add seasonal indicators
124
- seasons = df['season'].unique()
125
- season_colors = {
126
- 'Spring': 'rgba(0,255,0,0.1)',
127
- 'Summer': 'rgba(255,255,0,0.1)',
128
- 'Fall': 'rgba(255,165,0,0.1)',
129
- 'Winter': 'rgba(0,0,255,0.1)'
130
- }
131
-
132
- for season in seasons:
133
- season_data = df[df['season'] == season]
134
- if not season_data.empty:
135
- fig.add_vrect(
136
- x0=season_data['date'].iloc[0],
137
- x1=season_data['date'].iloc[-1],
138
- fillcolor=season_colors[season],
139
- layer="below",
140
- line_width=0,
141
- row="all"
142
- )
143
 
144
- # Update layout
145
- fig.update_layout(
146
- height=800,
147
- showlegend=True,
148
- paper_bgcolor='white',
149
- plot_bgcolor='rgba(0,0,0,0.05)',
150
- font=dict(size=12),
151
- legend=dict(
152
- orientation="h",
153
- yanchor="bottom",
154
- y=1.02,
155
- xanchor="right",
156
- x=1
157
- ),
158
- margin=dict(l=60, r=30, t=100, b=60)
159
- )
160
 
161
- fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)')
162
- fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)')
 
163
 
164
- return fig
165
-
166
- def create_enhanced_map(self, lat, lon, weather_score, ndvi_data=None):
167
- """Create an interactive map with both weather and NDVI data"""
168
- try:
169
- # Create base map
170
- m = folium.Map(location=[lat, lon], zoom_start=15)
171
-
172
- # If NDVI data is available, add it to the map
173
- if ndvi_data and 'image' in ndvi_data:
174
- try:
175
- # Get NDVI visualization parameters
176
- vis_params = {
177
- 'min': -0.2,
178
- 'max': 0.8,
179
- 'palette': self.ndvi_colors
180
- }
181
-
182
- # Add NDVI layer
183
- map_id_dict = ndvi_data['image'].getMapId(vis_params)
184
- folium.TileLayer(
185
- tiles=map_id_dict['tile_fetcher'].url_format,
186
- attr='NDVI Data',
187
- overlay=True,
188
- name='NDVI Layer'
189
- ).add_to(m)
190
-
191
- # Add NDVI legend
192
- colormap = LinearColormap(
193
- colors=self.ndvi_colors,
194
- vmin=-0.2,
195
- vmax=0.8,
196
- caption='NDVI Values'
197
- )
198
- colormap.add_to(m)
199
-
200
- except Exception as e:
201
- print(f"Error adding NDVI layer: {e}")
202
-
203
- # Calculate combined score if NDVI data is available
204
- if ndvi_data and 'stats' in ndvi_data:
205
- ndvi_score = (ndvi_data['stats'].get('NDVI_mean', 0) + 1) / 2
206
- combined_score = (weather_score * 0.6 + ndvi_score * 0.4)
207
- else:
208
- combined_score = weather_score
209
-
210
- # Color based on combined score
211
- if combined_score >= 0.8:
212
- color = 'green'
213
- elif combined_score >= 0.6:
214
- color = 'yellow'
215
- elif combined_score >= 0.4:
216
- color = 'orange'
217
- else:
218
- color = 'red'
219
-
220
- # Add analysis circles
221
  folium.Circle(
222
- radius=2000,
223
  location=[lat, lon],
224
- popup=f'Combined Score: {combined_score:.2f}<br>Weather Score: {weather_score:.2f}',
225
- color=color,
226
- fill=True,
227
- fillOpacity=0.4
228
  ).add_to(m)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
- # Add smaller analysis zones
231
- for radius in [1000, 1500]:
232
- folium.Circle(
233
- radius=radius,
234
- location=[lat, lon],
235
- color=color,
236
- fill=False,
237
- weight=1
238
- ).add_to(m)
239
-
240
- # Add layer control
241
- folium.LayerControl().add_to(m)
242
-
243
- return m._repr_html_()
244
-
245
- except Exception as e:
246
- print(f"Error creating enhanced map: {e}")
247
- return None
248
 
249
- def create_gauge_chart(self, score, title="Growing Conditions Score"):
250
  """Create an enhanced gauge chart for the overall score"""
251
  fig = go.Figure(go.Indicator(
252
  mode="gauge+number+delta",
253
  value=score,
254
  domain={'x': [0, 1], 'y': [0, 1]},
255
  title={
256
- 'text': title,
257
  'font': {'size': 24}
258
  },
259
  delta={
@@ -288,35 +299,4 @@ class VisualizationHandler:
288
  font={'color': "darkblue", 'family': "Arial"}
289
  )
290
 
291
- return fig
292
-
293
- def create_ndvi_report(self, ndvi_data):
294
- """Create a detailed NDVI analysis report"""
295
- if not ndvi_data or 'stats' not in ndvi_data:
296
- return None
297
-
298
- stats = ndvi_data['stats']
299
- mean_ndvi = stats.get('NDVI_mean', 0)
300
-
301
- # Create analysis text
302
- if mean_ndvi < 0:
303
- vegetation_status = "Very low vegetation - likely bare soil or water"
304
- elif mean_ndvi < 0.2:
305
- vegetation_status = "Low vegetation - sparse cover or stressed vegetation"
306
- elif mean_ndvi < 0.4:
307
- vegetation_status = "Moderate vegetation - typical for agricultural areas"
308
- elif mean_ndvi < 0.6:
309
- vegetation_status = "High vegetation - healthy crops or natural vegetation"
310
- else:
311
- vegetation_status = "Very high vegetation - dense, healthy vegetation"
312
-
313
- report = {
314
- 'mean_ndvi': mean_ndvi,
315
- 'std_dev': stats.get('NDVI_stdDev', 0),
316
- 'min_ndvi': stats.get('NDVI_min', 0),
317
- 'max_ndvi': stats.get('NDVI_max', 0),
318
- 'vegetation_status': vegetation_status,
319
- 'optimal_range': self.optimal_conditions['ndvi']
320
- }
321
-
322
- return report
 
3
  import plotly.graph_objects as go
4
  from plotly.subplots import make_subplots
5
  import folium
6
+ from folium import plugins
7
  import numpy as np
8
+ import branca.colormap as cm
 
 
9
 
10
  class VisualizationHandler:
11
  def __init__(self, optimal_conditions):
 
24
  def create_interactive_plots(self, df):
25
  """Create enhanced interactive Plotly visualizations"""
26
  fig = make_subplots(
27
+ rows=4, cols=1, # Added one more row for NDVI
28
  subplot_titles=(
29
  '<b>Temperature (°C)</b>',
30
  '<b>Humidity (%)</b>',
31
+ '<b>Rainfall (mm/day)</b>',
32
+ '<b>Vegetation Index (NDVI)</b>'
33
  ),
34
+ vertical_spacing=0.08,
35
+ row_heights=[0.25, 0.25, 0.25, 0.25]
36
  )
37
 
38
+ # Add standard weather plots
39
+ self.add_weather_plots(fig, df)
40
+
41
+ # Add NDVI plot
42
+ self.add_ndvi_plot(fig, df)
43
+
44
+ # Update layout
45
+ fig.update_layout(
46
+ height=1000, # Increased height for additional plot
47
+ showlegend=True,
48
+ title={
49
+ 'text': "Enhanced Tobacco Growing Conditions Analysis",
50
+ 'y':0.95,
51
+ 'x':0.5,
52
+ 'xanchor': 'center',
53
+ 'yanchor': 'top',
54
+ 'font': dict(size=20)
55
+ },
56
+ paper_bgcolor='white',
57
+ plot_bgcolor='rgba(0,0,0,0.05)',
58
+ font=dict(size=12),
59
+ legend=dict(
60
+ orientation="h",
61
+ yanchor="bottom",
62
+ y=1.02,
63
+ xanchor="right",
64
+ x=1
65
+ ),
66
+ margin=dict(l=60, r=30, t=100, b=60)
67
+ )
68
+
69
+ fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)')
70
+ fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)')
71
+
72
+ return fig
73
+
74
+ def add_weather_plots(self, fig, df):
75
+ """Add weather-related plots"""
76
+ # Temperature plot
77
  for data_type, color in [('historical', 'royalblue'),
78
  ('forecast_5day', 'firebrick'),
79
  ('forecast_extended', 'rgba(255, 165, 0, 0.5)')]:
 
102
  row=1, col=1
103
  )
104
 
105
+ # Humidity plot
106
  for data_type, color in [('historical', 'royalblue'),
107
  ('forecast_5day', 'firebrick'),
108
  ('forecast_extended', 'rgba(255, 165, 0, 0.5)')]:
 
131
  row=2, col=1
132
  )
133
 
134
+ # Rainfall plot
135
  for data_type, color in [('historical', 'royalblue'),
136
  ('forecast_5day', 'firebrick'),
137
  ('forecast_extended', 'rgba(255, 165, 0, 0.5)')]:
 
147
  row=3, col=1
148
  )
149
 
150
+ def add_ndvi_plot(self, fig, df):
151
+ """Add NDVI plot"""
152
+ # Historical NDVI
153
+ mask = df['type'] == 'historical'
154
+ if any(mask):
155
+ fig.add_trace(
156
+ go.Scatter(
157
+ x=df[mask]['date'],
158
+ y=df[mask]['estimated_ndvi'],
159
+ name='Historical NDVI',
160
+ line=dict(color='green', width=2),
161
+ mode='lines'
162
+ ),
163
+ row=4, col=1
164
+ )
165
 
166
+ # Forecast NDVI
167
+ mask = df['type'].isin(['forecast_5day', 'forecast_extended'])
168
+ if any(mask):
169
+ fig.add_trace(
170
+ go.Scatter(
171
+ x=df[mask]['date'],
172
+ y=df[mask]['estimated_ndvi'],
173
+ name='Forecast NDVI',
174
+ line=dict(color='orange', width=2, dash='dot'),
175
+ mode='lines'
176
+ ),
177
+ row=4, col=1
178
+ )
 
 
 
 
 
 
 
179
 
180
+ # Add optimal NDVI range
181
+ fig.add_hline(y=self.optimal_conditions['ndvi']['min'],
182
+ line_dash="dash", line_color="green",
183
+ annotation_text="Min Optimal NDVI",
184
+ row=4, col=1)
185
+ fig.add_hline(y=self.optimal_conditions['ndvi']['max'],
186
+ line_dash="dash", line_color="green",
187
+ annotation_text="Max Optimal NDVI",
188
+ row=4, col=1)
 
 
 
 
 
 
 
189
 
190
+ def create_enhanced_map(self, lat, lon, score, ndvi_value):
191
+ """Create an interactive map with both weather and vegetation analysis"""
192
+ m = folium.Map(location=[lat, lon], zoom_start=13)
193
 
194
+ # Add base marker
195
+ folium.Marker(
196
+ [lat, lon],
197
+ popup='Analysis Location',
198
+ icon=folium.Icon(color='red', icon='info-sign')
199
+ ).add_to(m)
200
+
201
+ # Create NDVI colormap
202
+ ndvi_colormap = cm.LinearColormap(
203
+ colors=self.ndvi_colors,
204
+ vmin=-1,
205
+ vmax=1,
206
+ caption='NDVI Values'
207
+ )
208
+
209
+ # Add NDVI-based circle
210
+ ndvi_color = ndvi_colormap(ndvi_value)
211
+ folium.Circle(
212
+ radius=2000,
213
+ location=[lat, lon],
214
+ popup=f'NDVI: {ndvi_value:.2f}',
215
+ color=ndvi_color,
216
+ fill=True,
217
+ fillOpacity=0.4
218
+ ).add_to(m)
219
+
220
+ # Add score-based circles
221
+ score_color = self.get_score_color(score)
222
+ for radius in [500, 1000, 1500]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  folium.Circle(
224
+ radius=radius,
225
  location=[lat, lon],
226
+ color=score_color,
227
+ popup=f'Growing Score: {score:.2f}',
228
+ fill=False,
229
+ weight=2
230
  ).add_to(m)
231
+
232
+ # Add measurement tools
233
+ plugins.MeasureControl(position='topright').add_to(m)
234
+
235
+ # Add fullscreen option
236
+ plugins.Fullscreen().add_to(m)
237
+
238
+ # Add mini map
239
+ minimap = plugins.MiniMap()
240
+ m.add_child(minimap)
241
+
242
+ # Add layer control
243
+ folium.LayerControl().add_to(m)
244
+
245
+ # Add colormap to map
246
+ m.add_child(ndvi_colormap)
247
+
248
+ return m._repr_html_()
249
 
250
+ def get_score_color(self, score):
251
+ """Get color based on score"""
252
+ if score >= 0.8:
253
+ return 'green'
254
+ elif score >= 0.6:
255
+ return 'yellow'
256
+ elif score >= 0.4:
257
+ return 'orange'
258
+ return 'red'
 
 
 
 
 
 
 
 
 
259
 
260
+ def create_gauge_chart(self, score):
261
  """Create an enhanced gauge chart for the overall score"""
262
  fig = go.Figure(go.Indicator(
263
  mode="gauge+number+delta",
264
  value=score,
265
  domain={'x': [0, 1], 'y': [0, 1]},
266
  title={
267
+ 'text': "Growing Conditions Score",
268
  'font': {'size': 24}
269
  },
270
  delta={
 
299
  font={'color': "darkblue", 'family': "Arial"}
300
  )
301
 
302
+ return fig