Esmaeilkianii commited on
Commit
ad60938
·
verified ·
1 Parent(s): 339d280

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -474
app.py CHANGED
@@ -4,16 +4,11 @@ import numpy as np
4
  import plotly.express as px
5
  import plotly.graph_objects as go
6
  from datetime import datetime, timedelta
7
- import calendar
8
- from PIL import Image
9
- import base64
10
- import io
11
- import os
12
- import ee
13
- import json
14
  import folium
15
  from streamlit_folium import folium_static
16
- import time
 
 
17
 
18
  # تنظیمات صفحه
19
  st.set_page_config(
@@ -66,76 +61,11 @@ st.markdown("""
66
  margin-bottom: 20px;
67
  }
68
 
69
- .status-good {
70
- background-color: rgba(0, 200, 83, 0.2);
71
- color: #00694b;
72
- padding: 5px 10px;
73
- border-radius: 5px;
74
- font-weight: bold;
75
- }
76
-
77
- .status-medium {
78
- background-color: rgba(255, 214, 0, 0.2);
79
- color: #b7940a;
80
- padding: 5px 10px;
81
- border-radius: 5px;
82
- font-weight: bold;
83
- }
84
-
85
- .status-bad {
86
- background-color: rgba(255, 61, 0, 0.2);
87
- color: #c62828;
88
- padding: 5px 10px;
89
- border-radius: 5px;
90
- font-weight: bold;
91
- }
92
-
93
  .metric-card {
94
  padding: 20px;
95
  border-radius: 10px;
96
  text-align: center;
97
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
98
- transition: transform 0.3s;
99
- }
100
-
101
- .metric-card:hover {
102
- transform: translateY(-5px);
103
- }
104
-
105
- .metric-green {
106
- background-color: rgba(0, 200, 83, 0.2);
107
- border-left: 5px solid #00c853;
108
- }
109
-
110
- .metric-yellow {
111
- background-color: rgba(255, 214, 0, 0.2);
112
- border-left: 5px solid #ffd600;
113
- }
114
-
115
- .metric-red {
116
- background-color: rgba(255, 61, 0, 0.2);
117
- border-left: 5px solid #ff3d00;
118
- }
119
-
120
- .metric-blue {
121
- background-color: rgba(33, 150, 243, 0.2);
122
- border-left: 5px solid #2196f3;
123
- }
124
-
125
- .stTabs [data-baseweb="tab-list"] {
126
- gap: 10px;
127
- }
128
-
129
- .stTabs [data-baseweb="tab"] {
130
- background-color: #f0f2f6;
131
- border-radius: 8px 8px 0px 0px;
132
- padding: 10px 20px;
133
- margin-top: 5px;
134
- }
135
-
136
- .stTabs [aria-selected="true"] {
137
- background-color: #1e6b45 !important;
138
- color: white !important;
139
  }
140
 
141
  input[type="number"] {
@@ -161,7 +91,11 @@ st.markdown("""
161
  </style>
162
  """, unsafe_allow_html=True)
163
 
164
- # تنظیم Earth Engine (بدون تغییر)
 
 
 
 
165
  @st.cache_resource
166
  def initialize_earth_engine():
167
  try:
@@ -194,96 +128,11 @@ def initialize_earth_engine():
194
 
195
  earth_engine_initialized = initialize_earth_engine()
196
 
197
- # نمونه داده
198
- @st.cache_data
199
- def generate_sample_data():
200
- farm_data = {
201
- 'Farm_ID': [f'{i:02d}-{j:02d}' for i in range(1, 5) for j in range(20, 30)],
202
- 'Farm_Name': [f'مزرعه {i:02d}-{j:02d}' for i in range(1, 5) for j in range(20, 30)],
203
- 'Channel_ID': [f'کانال {(i-1)*10 + j%10 + 1}' for i in range(1, 5) for j in range(20, 30)],
204
- 'Administration_ID': [i for i in range(1, 5) for _ in range(10)],
205
- 'Administration_Name': [f'اداره {i}' for i in range(1, 5) for _ in range(10)],
206
- 'Production_Section': [1 if i <= 2 else 2 for i in range(1, 5) for _ in range(10)],
207
- 'Area': [np.random.randint(50, 200) for _ in range(40)],
208
- 'Variety': [np.random.choice(['CP69', 'CP73']) for _ in range(40)],
209
- 'Crop_Age': [np.random.randint(1, 5) for _ in range(40)]
210
- }
211
- farms_df = pd.DataFrame(farm_data)
212
-
213
- height_data = []
214
- today = datetime.now()
215
- for week in range(1, 6):
216
- date = today - timedelta(days=(5-week)*7)
217
- for farm_id in farms_df['Farm_ID']:
218
- stations = [np.random.randint(150, 220) for _ in range(5)]
219
- avg_height = int(np.mean(stations))
220
- groundwater = [np.random.randint(50, 100) for _ in range(2)]
221
- sheath_moisture = np.random.randint(60, 90)
222
- nitrogen = np.random.randint(20, 40)
223
- height_data.append({
224
- 'Measurement_ID': f"{farm_id}-W{week}",
225
- 'Farm_ID': farm_id,
226
- 'Week': week,
227
- 'Measurement_Date': date.strftime('%Y-%m-%d'),
228
- 'Height': avg_height,
229
- 'Station1': stations[0],
230
- 'Station2': stations[1],
231
- 'Station3': stations[2],
232
- 'Station4': stations[3],
233
- 'Station5': stations[4],
234
- 'Groundwater1': groundwater[0],
235
- 'Groundwater2': groundwater[1],
236
- 'Sheath_Moisture': sheath_moisture,
237
- 'Nitrogen': nitrogen
238
- })
239
- heights_df = pd.DataFrame(height_data)
240
-
241
- weekly_report_data = []
242
- for farm_id in farms_df['Farm_ID']:
243
- farm_heights = heights_df[heights_df['Farm_ID'] == farm_id].sort_values('Week')
244
- for week in range(1, 6):
245
- current_week_data = farm_heights[farm_heights['Week'] == week]
246
- if current_week_data.empty:
247
- continue
248
- current_height = current_week_data['Height'].values[0]
249
- if week > 1:
250
- prev_week_data = farm_heights[farm_heights['Week'] == week-1]
251
- if not prev_week_data.empty:
252
- prev_height = prev_week_data['Height'].values[0]
253
- growth_change = current_height - prev_height
254
- else:
255
- growth_change = 0
256
- else:
257
- growth_change = 0
258
- all_farms_this_week = heights_df[heights_df['Week'] == week]
259
- avg_height_all_farms = all_farms_this_week['Height'].mean()
260
- if current_height > avg_height_all_farms + 5:
261
- growth_status = 'خوب'
262
- elif current_height < avg_height_all_farms - 5:
263
- growth_status = 'ضعیف'
264
- else:
265
- growth_status = 'متوسط'
266
- weekly_report_data.append({
267
- 'Report_ID': f"{farm_id}-R{week}",
268
- 'Farm_ID': farm_id,
269
- 'Week': week,
270
- 'Average_Height': current_height,
271
- 'Growth_Change': growth_change,
272
- 'Growth_Status': growth_status,
273
- 'Regional_Average': int(avg_height_all_farms)
274
- })
275
- weekly_report_df = pd.DataFrame(weekly_report_data)
276
-
277
- return farms_df, heights_df, weekly_report_df
278
-
279
- farms_df, heights_df, weekly_report_df = generate_sample_data()
280
- report_with_details = pd.merge(weekly_report_df, farms_df, on='Farm_ID')
281
- latest_week = heights_df['Week'].max()
282
- latest_reports = report_with_details[report_with_details['Week'] == latest_week]
283
-
284
  # مدیریت وضعیت برنامه
285
  if 'selected_tab' not in st.session_state:
286
  st.session_state.selected_tab = "ورود اطلاعات"
 
 
287
  if 'selected_day' not in st.session_state:
288
  st.session_state.selected_day = "شنبه"
289
  if 'farm_data' not in st.session_state:
@@ -297,232 +146,94 @@ def calculate_average_height(row):
297
  valid_stations = [s for s in stations if s > 0]
298
  return sum(valid_stations) / len(valid_stations) if valid_stations else 0
299
 
300
- # تابع برای ایجاد نقشه NDVI (بدون تغییر)
301
- def create_ndvi_map(farm_id=None, date=None):
302
  if not earth_engine_initialized:
303
  st.warning("اتصال به Earth Engine برقرار نشد. نقشه NDVI نمایش داده نمی‌شود.")
304
  return None
305
  try:
306
- center_point = [31.3183, 48.6706]
307
- m = folium.Map(location=center_point, zoom_start=10)
308
- if farm_id:
309
- farm = farms_df[farms_df['Farm_ID'] == farm_id].iloc[0]
310
- lat = 31.3183 + (int(farm_id.split('-')[0]) - 1) * 0.05
311
- lon = 48.6706 + (int(farm_id.split('-')[1]) - 20) * 0.05
312
- if date:
313
- date_obj = datetime.strptime(date, '%Y-%m-%d')
314
- start_date = date_obj - timedelta(days=5)
315
- end_date = date_obj + timedelta(days=5)
316
- start_date_str = start_date.strftime('%Y-%m-%d')
317
- end_date_str = end_date.strftime('%Y-%m-%d')
318
- else:
319
- start_date_str = '2023-01-01'
320
- end_date_str = '2023-12-31'
321
- region = ee.Geometry.Point([lon, lat]).buffer(1000)
322
- s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
323
- .filterDate(start_date_str, end_date_str) \
324
- .filterBounds(region) \
325
- .sort('CLOUD_COVERAGE_ASSESSMENT') \
326
- .first()
327
- ndvi = s2.normalizedDifference(['B8', 'B4']).rename('NDVI')
328
- ndvi_viz = {
329
- 'min': -0.2,
330
- 'max': 0.8,
331
- 'palette': ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#d9ef8b', '#a6d96a', '#66bd63', '#1a9850']
332
- }
333
- map_id_dict = ee.Image(ndvi).getMapId(ndvi_viz)
334
- folium.TileLayer(
335
- tiles=map_id_dict['tile_fetcher'].url_format,
336
- attr='Google Earth Engine',
337
- name='NDVI',
338
- overlay=True,
339
- control=True
340
- ).add_to(m)
341
- folium.Marker(
342
- location=[lat, lon],
343
- popup=f'مزرعه {farm_id}',
344
- icon=folium.Icon(color='green', icon='leaf')
345
- ).add_to(m)
346
- m.fit_bounds([[lat-0.05, lon-0.05], [lat+0.05, lon+0.05]])
 
 
347
  folium.LayerControl().add_to(m)
348
  return m
349
  except Exception as e:
350
  st.error(f"خطا در ایجاد نقشه NDVI: {e}")
351
  return None
352
 
353
- # منوی کناری (بدون تغییر)
354
  with st.sidebar:
355
  st.image("https://via.placeholder.com/150x150.png?text=لوگو", width=150)
356
  st.title("سامانه پایش مزارع نیشکر")
357
  st.subheader("شرکت کشت و صنعت نیشکر دهخدا")
358
  menu = st.selectbox(
359
  "انتخاب صفحه",
360
- ["داشبورد", "ورود اطلاعات", "گزارش‌گیری", "تحلیل داده‌ها", "تنظیمات"]
361
  )
362
  st.session_state.selected_tab = menu
363
  st.markdown("---")
364
- st.markdown("### راهنمای وضعیت رشد")
365
- col1, col2 = st.columns(2)
366
- with col1:
367
- st.markdown('<div class="status-good">خوب</div>', unsafe_allow_html=True)
368
- st.markdown('<div class="status-medium">متوسط</div>', unsafe_allow_html=True)
369
- st.markdown('<div class="status-bad">ضعیف</div>', unsafe_allow_html=True)
370
- with col2:
371
- st.write("بالاتر از میانگین")
372
- st.write("نزدیک به میانگین")
373
- st.write("پایین‌تر از میانگین")
374
- st.markdown("---")
375
- st.info("نسخه آزمایشی 1.0")
376
-
377
- # داشبورد (بدون تغییر)
378
- if st.session_state.selected_tab == "داشبورد":
379
- st.title("داشبورد پایش مزارع نیشکر")
380
- st.subheader("وضعیت کلی مزارع")
381
- status_counts = latest_reports['Growth_Status'].value_counts()
382
- good_count = status_counts.get('خوب', 0)
383
- medium_count = status_counts.get('متوسط', 0)
384
- bad_count = status_counts.get('ضعیف', 0)
385
- col1, col2, col3, col4 = st.columns(4)
386
- with col1:
387
- st.markdown('<div class="metric-card metric-green">'f'<h2>{good_count}</h2>''<p>مزارع با وضعیت خوب</p>''</div>', unsafe_allow_html=True)
388
- with col2:
389
- st.markdown('<div class="metric-card metric-yellow">'f'<h2>{medium_count}</h2>''<p>مزارع با وضعیت متوسط</p>''</div>', unsafe_allow_html=True)
390
- with col3:
391
- st.markdown('<div class="metric-card metric-red">'f'<h2>{bad_count}</h2>''<p>مزارع با وضعیت ضعیف</p>''</div>', unsafe_allow_html=True)
392
- with col4:
393
- avg_height = int(latest_reports['Average_Height'].mean())
394
- st.markdown('<div class="metric-card metric-blue">'f'<h2>{avg_height} سانتی‌متر</h2>''<p>میانگین ارتفاع هفته جاری</p>''</div>', unsafe_allow_html=True)
395
- st.markdown("---")
396
- col1, col2 = st.columns(2)
397
- with col1:
398
- st.subheader("میانگین ارتفاع به تفکیک اداره")
399
- admin_heights = latest_reports.groupby('Administration_Name')['Average_Height'].mean().reset_index()
400
- admin_heights['Average_Height'] = admin_heights['Average_Height'].astype(int)
401
- fig = px.bar(
402
- admin_heights,
403
- x='Administration_Name',
404
- y='Average_Height',
405
- color='Average_Height',
406
- color_continuous_scale=[(0, "red"), (0.5, "yellow"), (1, "green")],
407
- labels={'Administration_Name': 'اداره', 'Average_Height': 'میانگین ارتفاع (سانتی‌متر)'}
408
- )
409
- fig.update_layout(height=400, xaxis_title="اداره", yaxis_title="میانگین ارتفاع (سانتی‌متر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
410
- st.plotly_chart(fig, use_container_width=True)
411
- with col2:
412
- st.subheader("مقایسه واریته‌ها")
413
- variety_heights = latest_reports.groupby('Variety')['Average_Height'].mean().reset_index()
414
- variety_heights['Average_Height'] = variety_heights['Average_Height'].astype(int)
415
- fig = px.bar(
416
- variety_heights,
417
- x='Variety',
418
- y='Average_Height',
419
- color='Variety',
420
- color_discrete_sequence=["#00c853", "#2196f3"],
421
- labels={'Variety': 'واریته', 'Average_Height': 'میانگین ارتفاع (سانتی‌متر)'}
422
- )
423
- fig.update_layout(height=400, xaxis_title="واریته", yaxis_title="میانگین ارتفاع (سانتی‌متر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
424
- st.plotly_chart(fig, use_container_width=True)
425
- st.subheader("روند میانگین ارتفاع هفتگی")
426
- weekly_avg = report_with_details.groupby('Week')['Average_Height'].mean().reset_index()
427
- weekly_avg['Average_Height'] = weekly_avg['Average_Height'].astype(int)
428
- fig = px.line(
429
- weekly_avg,
430
- x='Week',
431
- y='Average_Height',
432
- markers=True,
433
- line_shape='spline',
434
- labels={'Week': 'هفته', 'Average_Height': 'میانگین ارتفاع (سانتی‌متر)'}
435
- )
436
- fig.update_traces(line=dict(width=3, color="#1e6b45"), marker=dict(size=10))
437
- fig.update_layout(height=400, xaxis_title="هفته", yaxis_title="میانگین ارتفاع (سانتی‌متر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
438
- st.plotly_chart(fig, use_container_width=True)
439
- st.markdown("---")
440
- st.subheader("نقشه NDVI")
441
- col1, col2 = st.columns(2)
442
- with col1:
443
- selected_farm_for_map = st.selectbox(
444
- "انتخاب مزرعه",
445
- farms_df['Farm_ID'].tolist(),
446
- format_func=lambda x: farms_df[farms_df['Farm_ID'] == x]['Farm_Name'].iloc[0]
447
- )
448
- with col2:
449
- latest_date = heights_df[heights_df['Farm_ID'] == selected_farm_for_map].sort_values('Week', ascending=False)['Measurement_Date'].iloc[0]
450
- selected_date_for_map = st.date_input(
451
- "انتخاب تاریخ",
452
- value=datetime.strptime(latest_date, '%Y-%m-%d'),
453
- max_value=datetime.now()
454
- )
455
- if st.button("نمایش نقشه NDVI"):
456
- with st.spinner("در حال تولید نقشه..."):
457
- ndvi_map = create_ndvi_map(selected_farm_for_map, selected_date_for_map.strftime('%Y-%m-%d'))
458
- st.session_state.ndvi_map = ndvi_map
459
- if st.session_state.ndvi_map:
460
- st.markdown('<div class="map-container">', unsafe_allow_html=True)
461
- folium_static(st.session_state.ndvi_map, width=1200, height=500)
462
- st.markdown('</div>', unsafe_allow_html=True)
463
- farm_info = farms_df[farms_df['Farm_ID'] == selected_farm_for_map].iloc[0]
464
- farm_measurements = heights_df[(heights_df['Farm_ID'] == selected_farm_for_map) &
465
- (heights_df['Measurement_Date'] == latest_date)].iloc[0]
466
- st.markdown(f"""
467
- ### اطلاعات مزرعه {farm_info['Farm_Name']}
468
- **اداره:** {farm_info['Administration_Name']} | **کانال:** {farm_info['Channel_ID']} | **واریته:** {farm_info['Variety']} | **سن کشت:** {farm_info['Crop_Age']} سال
469
- **آخرین اندازه‌گیری:** {latest_date}
470
- - **میانگین ارتفاع:** {farm_measurements['Height']} سانتی‌متر
471
- - **رطوبت غلاف:** {farm_measurements['Sheath_Moisture']}%
472
- - **نیتروژن:** {farm_measurements['Nitrogen']}%
473
- """)
474
- else:
475
- st.info("برای نمایش نقشه NDVI، یک مزرعه و تاریخ انتخاب کنید.")
476
- st.markdown("---")
477
- st.subheader("مزارع با بیشترین و کمترین رشد")
478
- col1, col2 = st.columns(2)
479
- with col1:
480
- st.markdown("#### بیشترین رشد هفتگی")
481
- top_growth = report_with_details[report_with_details['Week'] == latest_week].sort_values('Growth_Change', ascending=False).head(5)
482
- for _, row in top_growth.iterrows():
483
- growth_color = "green" if row['Growth_Change'] > 0 else "red"
484
- st.markdown(f"""
485
- <div style="border: 1px solid #eee; padding: 10px; border-radius: 5px; margin-bottom: 10px;">
486
- <h4 style="margin: 0;">{row['Farm_Name']} (اداره {row['Administration_ID']})</h4>
487
- <p style="margin: 5px 0;">ارتفاع: {row['Average_Height']} سانتی‌متر</p>
488
- <p style="color: {growth_color}; font-weight: bold; margin: 0;">
489
- تغییر: {'+' if row['Growth_Change'] > 0 else ''}{row['Growth_Change']} سانتی‌متر
490
- </p>
491
- </div>
492
- """, unsafe_allow_html=True)
493
- with col2:
494
- st.markdown("#### کمترین رشد هفتگی")
495
- bottom_growth = report_with_details[report_with_details['Week'] == latest_week].sort_values('Growth_Change').head(5)
496
- for _, row in bottom_growth.iterrows():
497
- growth_color = "green" if row['Growth_Change'] > 0 else "red"
498
- st.markdown(f"""
499
- <div style="border: 1px solid #eee; padding: 10px; border-radius: 5px; margin-bottom: 10px;">
500
- <h4 style="margin: 0;">{row['Farm_Name']} (اداره {row['Administration_ID']})</h4>
501
- <p style="margin: 5px 0;">ارتفاع: {row['Average_Height']} سانتی‌متر</p>
502
- <p style="color: {growth_color}; font-weight: bold; margin: 0;">
503
- تغییر: {'+' if row['Growth_Change'] > 0 else ''}{row['Growth_Change']} سانتی‌متر
504
- </p>
505
- </div>
506
- """, unsafe_allow_html=True)
507
 
508
- # بخش ورود اطلاعات (بهبود یافته)
509
- elif st.session_state.selected_tab == "ورود اطلاعات":
510
  st.title("ورود اطلاعات روزانه")
511
 
 
 
 
 
 
512
  # انتخاب روز هفته
513
  days_of_week = ["شنبه", "یکشنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنجشنبه"]
514
  selected_day = st.selectbox("انتخاب روز", days_of_week, index=days_of_week.index(st.session_state.selected_day))
515
  st.session_state.selected_day = selected_day
516
 
517
- # انتخاب اداره
518
- selected_admin = st.selectbox("انتخاب اداره", sorted(farms_df['Administration_ID'].unique()))
519
-
520
- # فیلتر مزارع بر اساس اداره انتخاب‌شده
521
- filtered_farms = farms_df[farms_df['Administration_ID'] == selected_admin].copy()
522
 
523
  # تعریف ستون‌های جدول
524
  columns = {
525
- 'مزرعه': filtered_farms['Farm_Name'],
526
  'ایستگاه 1': [0] * len(filtered_farms),
527
  'ایستگاه 2': [0] * len(filtered_farms),
528
  'ایستگاه 3': [0] * len(filtered_farms),
@@ -537,22 +248,23 @@ elif st.session_state.selected_tab == "ورود اطلاعات":
537
  data_df = pd.DataFrame(columns)
538
 
539
  # بارگذاری داده‌های قبلی (اگر وجود داشته باشد)
540
- if selected_day in st.session_state.farm_data:
 
541
  for idx, farm in filtered_farms.iterrows():
542
- farm_id = farm['Farm_ID']
543
- if farm_id in st.session_state.farm_data[selected_day]:
544
- saved_data = st.session_state.farm_data[selected_day][farm_id]
545
  for col in ['ایستگاه 1', 'ایستگاه 2', 'ایستگاه 3', 'ایستگاه 4', 'ایستگاه 5', 'چاهک 1', 'چاهک 2', 'رطوبت غلاف', 'نیتروژن']:
546
  if col in saved_data:
547
  data_df.at[idx, col] = saved_data[col]
548
  data_df.at[idx, 'میانگین ارتفاع'] = calculate_average_height(data_df.iloc[idx])
549
 
550
  # نمایش جدول ورود داده‌ها
551
- st.subheader(f"ورود داده‌های روز {selected_day} - اداره {selected_admin}")
552
  edited_df = st.data_editor(
553
  data_df,
554
  num_rows="fixed",
555
- key=f"data_editor_{selected_day}_{selected_admin}",
556
  hide_index=True,
557
  column_config={
558
  "مزرعه": st.column_config.TextColumn("مزرعه", disabled=True),
@@ -593,11 +305,11 @@ elif st.session_state.selected_tab == "ورود اطلاعات":
593
 
594
  # دکمه ذخیره
595
  if st.button("ذخیره اطلاعات"):
596
- if selected_day not in st.session_state.farm_data:
597
- st.session_state.farm_data[selected_day] = {}
598
  for idx, row in edited_df.iterrows():
599
- farm_id = filtered_farms.iloc[idx]['Farm_ID']
600
- st.session_state.farm_data[selected_day][farm_id] = {
601
  'ایستگاه 1': row['ایستگاه 1'],
602
  'ایستگاه 2': row['ایستگاه 2'],
603
  'ایستگاه 3': row['ایستگاه 3'],
@@ -611,112 +323,24 @@ elif st.session_state.selected_tab == "ورود اطلاعات":
611
  }
612
  st.success("داده‌ها با موفقیت ذخیره شدند.")
613
 
614
- # گزارش‌گیری (بدون تغییر)
615
- elif st.session_state.selected_tab == "گزارش‌گیری":
616
- st.title("گزارش‌های هفتگی")
617
- report_type = st.radio(
618
- "نوع گزارش",
619
- ["گزارش به تفکیک مزرعه", "گزارش به تفکیک اداره", "گزارش به تفکیک کانال", "مزارع با وضعیت ضعیف"]
620
  )
621
- st.markdown("---")
622
- if report_type == "گزارش به تفکیک مزرعه":
623
- st.subheader("گزارش هفتگی به تفکیک مزرعه")
624
- selected_admin = st.selectbox("انتخاب اداره", sorted(farms_df['Administration_ID'].unique()), key="admin_select_farm_report")
625
- filtered_farms = farms_df[farms_df['Administration_ID'] == selected_admin]
626
- selected_farm_id = st.selectbox(
627
- "انتخاب مزرعه",
628
- filtered_farms['Farm_ID'].tolist(),
629
- format_func=lambda x: filtered_farms[filtered_farms['Farm_ID'] == x]['Farm_Name'].iloc[0]
630
- )
631
- farm_reports = weekly_report_df[weekly_report_df['Farm_ID'] == selected_farm_id].sort_values('Week')
632
- if not farm_reports.empty:
633
- farm_info = filtered_farms[filtered_farms['Farm_ID'] == selected_farm_id].iloc[0]
634
- col1, col2, col3 = st.columns(3)
635
- col1.metric("واریته", farm_info['Variety'])
636
- col2.metric("سن کشت", f"{farm_info['Crop_Age']} سال")
637
- col3.metric("مساحت", f"{farm_info['Area']} هکتار")
638
- st.markdown("---")
639
- st.subheader("روند رشد هفتگی")
640
- fig = go.Figure()
641
- fig.add_trace(go.Scatter(
642
- x=farm_reports['Week'],
643
- y=farm_reports['Regional_Average'],
644
- mode='lines+markers',
645
- name='میانگین منطقه',
646
- line=dict(color='gray', width=2, dash='dot'),
647
- marker=dict(size=8)
648
- ))
649
- fig.add_trace(go.Scatter(
650
- x=farm_reports['Week'],
651
- y=farm_reports['Average_Height'],
652
- mode='lines+markers',
653
- name='ارتفاع مزرعه',
654
- line=dict(color='#1e6b45', width=3),
655
- marker=dict(size=10)
656
- ))
657
- fig.update_layout(height=400, xaxis_title="هفته", yaxis_title="ارتفاع (سانتی‌متر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
658
- st.plotly_chart(fig, use_container_width=True)
659
- st.subheader("داده‌های هفتگی")
660
- report_table = pd.DataFrame({
661
- 'هفته': farm_reports['Week'],
662
- 'تاریخ': farm_reports['Week'].apply(lambda x: heights_df[heights_df['Week'] == x]['Measurement_Date'].iloc[0]),
663
- 'ارتفاع': farm_reports['Average_Height'],
664
- 'میانگین منطقه': farm_reports['Regional_Average'],
665
- 'تغییرات': farm_reports['Growth_Change'],
666
- 'وضعیت': farm_reports['Growth_Status']
667
- })
668
- def status_with_color(status):
669
- colors = {'خوب': '#00c853', 'متوسط': '#ffd600', 'ضعیف': '#ff3d00'}
670
- return f'<span style="color: {colors.get(status, "black")};">{status}</span>'
671
- report_table['وضعیت'] = report_table['وضعیت'].apply(status_with_color)
672
- st.markdown(report_table.to_html(escape=False, index=False), unsafe_allow_html=True)
673
- st.subheader("نقشه NDVI مزرعه")
674
- if st.button("نمایش نقشه NDVI این مزرعه"):
675
- with st.spinner("در حال تولید نقشه..."):
676
- latest_date = farm_reports.iloc[-1]['Week']
677
- farm_date = heights_df[heights_df['Week'] == latest_date]['Measurement_Date'].iloc[0]
678
- ndvi_map = create_ndvi_map(selected_farm_id, farm_date)
679
- if ndvi_map:
680
- st.markdown('<div class="map-container">', unsafe_allow_html=True)
681
- folium_static(ndvi_map, width=1200, height=500)
682
- st.markdown('</div>', unsafe_allow_html=True)
683
- st.markdown("---")
684
- st.subheader("توصیه‌های کارشناسی")
685
- latest_report = farm_reports.iloc[-1]
686
- latest_status = latest_report['Growth_Status']
687
- if latest_status == 'خوب':
688
- st.success("وضعیت رشد مزرعه مطلوب است. ادامه برنامه فعلی توصیه می‌شود.")
689
- elif latest_status == 'متوسط':
690
- st.warning("وضعیت رشد مزرعه متوسط است. بررسی وضعیت آبیاری و تغذیه توصیه می‌شود.")
691
- else:
692
- st.error("وضعیت رشد مزرعه ضعیف است. مشکلات احتمالی:")
693
- st.markdown("""
694
- - بررسی سیستم آبیاری و عدم گرفتگی
695
- - بررسی وضعیت تغذیه و نیاز به کود
696
- - بررسی آفات و بیماری‌های احتمالی
697
- - بررسی وضعیت زهکشی مزرعه
698
- """)
699
-
700
- # تحلیل داده‌ها (بدون تغییر)
701
- elif st.session_state.selected_tab == "تحلیل داده‌ها":
702
- st.title("تحلیل پیشرفته داده‌ها")
703
- analysis_type = st.selectbox(
704
- "انتخاب نوع تحلیل",
705
- ["تحلیل واریته‌ها", "تحلیل عوامل مؤثر بر رشد", "پیش‌بینی روند آینده", "مقایسه بخش‌های تولیدی"]
706
  )
707
- st.markdown("---")
708
- if analysis_type == "تحلیل واریته‌ها":
709
- st.subheader("مقایسه واریته‌های مختلف")
710
- variety_weekly = report_with_details.groupby(['Variety', 'Week'])['Average_Height'].mean().reset_index()
711
- variety_weekly['Average_Height'] = variety_weekly['Average_Height'].round().astype(int)
712
- fig = px.line(
713
- variety_weekly,
714
- x='Week',
715
- y='Average_Height',
716
- color='Variety',
717
- markers=True,
718
- labels={'Week': 'هفته', 'Average_Height': 'میانگین ارتفاع (سانتی‌متر)', 'Variety': 'واریته'}
719
- )
720
- fig.update_traces(line=dict(width=3), marker=dict(size=10))
721
- fig.update_layout(height=500, xaxis_title="هفته", yaxis_title="میانگین ارتفاع (سانتی‌متر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
722
- st.plotly_chart(fig, use_container_width=True)
 
4
  import plotly.express as px
5
  import plotly.graph_objects as go
6
  from datetime import datetime, timedelta
 
 
 
 
 
 
 
7
  import folium
8
  from streamlit_folium import folium_static
9
+ import ee
10
+ import os
11
+ import json
12
 
13
  # تنظیمات صفحه
14
  st.set_page_config(
 
61
  margin-bottom: 20px;
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  .metric-card {
65
  padding: 20px;
66
  border-radius: 10px;
67
  text-align: center;
68
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  }
70
 
71
  input[type="number"] {
 
91
  </style>
92
  """, unsafe_allow_html=True)
93
 
94
+ # خواندن فایل‌های پایگاه داده
95
+ farms_df = pd.read_csv("پایگاه داده (1).csv")
96
+ coordinates_df = pd.read_csv("farm_coordinates.csv")
97
+
98
+ # تنظیم Earth Engine
99
  @st.cache_resource
100
  def initialize_earth_engine():
101
  try:
 
128
 
129
  earth_engine_initialized = initialize_earth_engine()
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  # مدیریت وضعیت برنامه
132
  if 'selected_tab' not in st.session_state:
133
  st.session_state.selected_tab = "ورود اطلاعات"
134
+ if 'selected_week' not in st.session_state:
135
+ st.session_state.selected_week = "1"
136
  if 'selected_day' not in st.session_state:
137
  st.session_state.selected_day = "شنبه"
138
  if 'farm_data' not in st.session_state:
 
146
  valid_stations = [s for s in stations if s > 0]
147
  return sum(valid_stations) / len(valid_stations) if valid_stations else 0
148
 
149
+ # تابع برای ایجاد نقشه NDVI با مختصات دقیق
150
+ def create_ndvi_map(farm_id, date=None):
151
  if not earth_engine_initialized:
152
  st.warning("اتصال به Earth Engine برقرار نشد. نقشه NDVI نمایش داده نمی‌شود.")
153
  return None
154
  try:
155
+ # دریافت مختصات مزرعه از فایل coordinates_df
156
+ farm_coords = coordinates_df[coordinates_df['نام'] == farm_id].iloc[0]
157
+ lat = farm_coords['عرض جغرافیایی']
158
+ lon = farm_coords['طول جغرافیایی']
159
+
160
+ # ایجاد نقشه با مختصات دقیق
161
+ m = folium.Map(location=[lat, lon], zoom_start=12)
162
+
163
+ if date:
164
+ date_obj = datetime.strptime(date, '%Y-%m-%d')
165
+ start_date = date_obj - timedelta(days=5)
166
+ end_date = date_obj + timedelta(days=5)
167
+ start_date_str = start_date.strftime('%Y-%m-%d')
168
+ end_date_str = end_date.strftime('%Y-%m-%d')
169
+ else:
170
+ start_date_str = '2023-01-01'
171
+ end_date_str = '2023-12-31'
172
+
173
+ region = ee.Geometry.Point([lon, lat]).buffer(1000)
174
+ s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
175
+ .filterDate(start_date_str, end_date_str) \
176
+ .filterBounds(region) \
177
+ .sort('CLOUD_COVERAGE_ASSESSMENT') \
178
+ .first()
179
+ ndvi = s2.normalizedDifference(['B8', 'B4']).rename('NDVI')
180
+ ndvi_viz = {
181
+ 'min': -0.2,
182
+ 'max': 0.8,
183
+ 'palette': ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#d9ef8b', '#a6d96a', '#66bd63', '#1a9850']
184
+ }
185
+ map_id_dict = ee.Image(ndvi).getMapId(ndvi_viz)
186
+ folium.TileLayer(
187
+ tiles=map_id_dict['tile_fetcher'].url_format,
188
+ attr='Google Earth Engine',
189
+ name='NDVI',
190
+ overlay=True,
191
+ control=True
192
+ ).add_to(m)
193
+ folium.Marker(
194
+ location=[lat, lon],
195
+ popup=f'مزرعه {farm_id}',
196
+ icon=folium.Icon(color='green', icon='leaf')
197
+ ).add_to(m)
198
  folium.LayerControl().add_to(m)
199
  return m
200
  except Exception as e:
201
  st.error(f"خطا در ایجاد نقشه NDVI: {e}")
202
  return None
203
 
204
+ # منوی کناری
205
  with st.sidebar:
206
  st.image("https://via.placeholder.com/150x150.png?text=لوگو", width=150)
207
  st.title("سامانه پایش مزارع نیشکر")
208
  st.subheader("شرکت کشت و صنعت نیشکر دهخدا")
209
  menu = st.selectbox(
210
  "انتخاب صفحه",
211
+ ["ورود اطلاعات", "نقشه NDVI"] # فقط بخش‌های موردنظر برای ساده‌سازی
212
  )
213
  st.session_state.selected_tab = menu
214
  st.markdown("---")
215
+ st.info("نسخه آزمایشی")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
 
217
+ # بخش ورود اطلاعات
218
+ if st.session_state.selected_tab == "ورود اطلاعات":
219
  st.title("ورود اطلاعات روزانه")
220
 
221
+ # انتخاب هفته
222
+ weeks = [str(i) for i in range(1, 23)]
223
+ selected_week = st.selectbox("انتخاب هفته", weeks, index=weeks.index(st.session_state.selected_week))
224
+ st.session_state.selected_week = selected_week
225
+
226
  # انتخاب روز هفته
227
  days_of_week = ["شنبه", "یکشنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنجشنبه"]
228
  selected_day = st.selectbox("انتخاب روز", days_of_week, index=days_of_week.index(st.session_state.selected_day))
229
  st.session_state.selected_day = selected_day
230
 
231
+ # فیلتر مزارع بر اساس روز انتخاب‌شده
232
+ filtered_farms = farms_df[farms_df['روز'] == selected_day].copy()
 
 
 
233
 
234
  # تعریف ستون‌های جدول
235
  columns = {
236
+ 'مزرعه': filtered_farms['مزرعه'],
237
  'ایستگاه 1': [0] * len(filtered_farms),
238
  'ایستگاه 2': [0] * len(filtered_farms),
239
  'ایستگاه 3': [0] * len(filtered_farms),
 
248
  data_df = pd.DataFrame(columns)
249
 
250
  # بارگذاری داده‌های قبلی (اگر وجود داشته باشد)
251
+ week_day_key = f"week_{selected_week}_day_{selected_day}"
252
+ if week_day_key in st.session_state.farm_data:
253
  for idx, farm in filtered_farms.iterrows():
254
+ farm_id = farm['مزرعه']
255
+ if farm_id in st.session_state.farm_data[week_day_key]:
256
+ saved_data = st.session_state.farm_data[week_day_key][farm_id]
257
  for col in ['ایستگاه 1', 'ایستگاه 2', 'ایستگاه 3', 'ایستگاه 4', 'ایستگاه 5', 'چاهک 1', 'چاهک 2', 'رطوبت غلاف', 'نیتروژن']:
258
  if col in saved_data:
259
  data_df.at[idx, col] = saved_data[col]
260
  data_df.at[idx, 'میانگین ارتفاع'] = calculate_average_height(data_df.iloc[idx])
261
 
262
  # نمایش جدول ورود داده‌ها
263
+ st.subheader(f"ورود داده‌های هفته {selected_week} - روز {selected_day}")
264
  edited_df = st.data_editor(
265
  data_df,
266
  num_rows="fixed",
267
+ key=f"data_editor_{week_day_key}",
268
  hide_index=True,
269
  column_config={
270
  "مزرعه": st.column_config.TextColumn("مزرعه", disabled=True),
 
305
 
306
  # دکمه ذخیره
307
  if st.button("ذخیره اطلاعات"):
308
+ if week_day_key not in st.session_state.farm_data:
309
+ st.session_state.farm_data[week_day_key] = {}
310
  for idx, row in edited_df.iterrows():
311
+ farm_id = filtered_farms.iloc[idx]['مزرعه']
312
+ st.session_state.farm_data[week_day_key][farm_id] = {
313
  'ایستگاه 1': row['ایستگاه 1'],
314
  'ایستگاه 2': row['ایستگاه 2'],
315
  'ایستگاه 3': row['ایستگاه 3'],
 
323
  }
324
  st.success("داده‌ها با موفقیت ذخیره شدند.")
325
 
326
+ # بخش نقشه NDVI
327
+ elif st.session_state.selected_tab == "نقشه NDVI":
328
+ st.title("نمایش نقشه NDVI مزارع")
329
+ selected_farm = st.selectbox(
330
+ "انتخاب مزرعه",
331
+ farms_df['مزرعه'].tolist()
332
  )
333
+ selected_date = st.date_input(
334
+ "انتخاب تاریخ",
335
+ value=datetime.now(),
336
+ max_value=datetime.now()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  )
338
+ if st.button("نمایش نقشه"):
339
+ with st.spinner("در حال تولید نقشه..."):
340
+ ndvi_map = create_ndvi_map(selected_farm, selected_date.strftime('%Y-%m-%d'))
341
+ if ndvi_map:
342
+ st.markdown('<div class="map-container">', unsafe_allow_html=True)
343
+ folium_static(ndvi_map, width=1200, height=500)
344
+ st.markdown('</div>', unsafe_allow_html=True)
345
+ else:
346
+ st.error("نقشه NDVI تولید نشد.")