Esmaeilkianii commited on
Commit
b466e9f
·
verified ·
1 Parent(s): 8b37100

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +319 -54
app.py CHANGED
@@ -18,6 +18,7 @@ from sklearn.model_selection import train_test_split
18
  from sklearn.metrics import mean_squared_error
19
  import os
20
  import json
 
21
 
22
  # تنظیمات صفحه
23
  st.set_page_config(
@@ -111,6 +112,30 @@ st.markdown("""
111
  </style>
112
  """, unsafe_allow_html=True)
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  # تابع برای اتصال به Google Earth Engine با استفاده از اطلاعات حساب سرویس
115
  @st.cache_resource
116
  def initialize_earth_engine():
@@ -244,29 +269,50 @@ def display_metric_card(title, value, icon="📊"):
244
  </div>
245
  """, unsafe_allow_html=True)
246
 
 
 
 
 
 
 
 
 
 
247
  # تابع برای بارگذاری داده‌های مزارع نیشکر
248
  def load_farm_data():
249
  try:
 
 
 
 
250
  # بارگذاری فایل مختصات مزارع
251
  farm_coordinates = pd.read_csv('farm_coordinates.csv')
252
 
253
  # بارگذاری فایل پایگاه داده مزارع
254
  farm_database = pd.read_csv('پایگاه داده (1).csv')
255
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  # ادغام داده‌ها بر اساس ستون مزرعه
257
  merged_data = pd.merge(farm_database, farm_coordinates, on='مزرعه', how='inner')
258
 
259
- # تبدیل ستون‌های سن به نوع عددی
260
- if 'سن_x' in merged_data.columns:
261
- merged_data['سن_x'] = pd.to_numeric(merged_data['سن_x'], errors='coerce')
262
- if 'سن' in merged_data.columns:
263
- merged_data['سن'] = pd.to_numeric(merged_data['سن'], errors='coerce')
264
-
265
  return farm_coordinates, farm_database, merged_data
266
  except Exception as e:
267
  st.error(f"خطا در بارگذاری داده‌ها: {e}")
268
 
269
  # ایجاد داده‌های نمونه در صورت عدم وجود فایل‌ها
 
270
  farm_coordinates = pd.DataFrame({
271
  'مزرعه': [f'مزرعه {i}' for i in range(1, 21)],
272
  'سن': np.random.randint(1, 10, 20),
@@ -275,6 +321,7 @@ def load_farm_data():
275
  'عرض جغرافیایی': np.random.uniform(31.0, 32.0, 20)
276
  })
277
 
 
278
  days = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه']
279
  farm_database = pd.DataFrame({
280
  'مزرعه': [f'مزرعه {i}' for i in range(1, 21)],
@@ -291,28 +338,26 @@ def load_farm_data():
291
  # ادغام داده‌ها
292
  merged_data = pd.merge(farm_database, farm_coordinates, on='مزرعه', how='inner')
293
 
294
- # تبدیل ستون‌های سن به نوع عددی
295
- if 'سن_x' in merged_data.columns:
296
- merged_data['سن_x'] = pd.to_numeric(merged_data['سن_x'], errors='coerce')
297
- if 'سن' in merged_data.columns:
298
- merged_data['سن'] = pd.to_numeric(merged_data['سن'], errors='coerce')
299
-
300
  return farm_coordinates, farm_database, merged_data
301
 
302
  # تابع برای ایجاد نقشه مزارع
303
  def create_farm_map(df, selected_farms=None):
 
304
  center_lat = df['عرض جغرافیایی'].mean()
305
  center_lon = df['طول جغرافیایی'].mean()
306
  m = folium.Map(location=[center_lat, center_lon], zoom_start=10)
307
 
 
308
  folium.TileLayer('openstreetmap').add_to(m)
309
  folium.TileLayer('Stamen Terrain').add_to(m)
310
  folium.TileLayer('Stamen Toner').add_to(m)
311
  folium.TileLayer('Stamen Watercolor').add_to(m)
312
  folium.TileLayer('CartoDB positron').add_to(m)
313
 
 
314
  folium.LayerControl().add_to(m)
315
 
 
316
  for idx, row in df.iterrows():
317
  color = 'green'
318
  if selected_farms is not None and row['مزرعه'] in selected_farms:
@@ -341,6 +386,7 @@ def create_farm_map(df, selected_farms=None):
341
 
342
  # تابع برای ایجاد نمودارهای تحلیلی
343
  def create_analysis_charts(df):
 
344
  variety_column = 'واریته' if 'واریته' in df.columns else 'تنوع'
345
  fig_variety = px.pie(
346
  df,
@@ -354,6 +400,7 @@ def create_analysis_charts(df):
354
  title_font_size=20
355
  )
356
 
 
357
  age_column = 'سن_x' if 'سن_x' in df.columns else 'سن'
358
  fig_age = px.histogram(
359
  df,
@@ -369,23 +416,41 @@ def create_analysis_charts(df):
369
  title_font_size=20
370
  )
371
 
 
372
  if 'مساحت' in df.columns:
373
- fig_area = px.scatter(
374
- df,
375
- x='مساحت',
376
- y='مساحت زیرمجموعه' if 'مساحت زیرمجموعه' in df.columns else 'مساحت',
377
- color=variety_column,
378
- size=age_column,
379
- hover_name='مزرعه',
380
- title='رابطه بین مساحت و مساحت زیرمجموعه مزارع',
381
- labels={'مساحت': 'مساحت کل (هکتار)', 'مساحت زیرمجموعه': 'مساحت زیرمجموعه (هکتار)'},
382
- color_discrete_sequence=px.colors.sequential.Greens
383
- )
384
- fig_area.update_layout(
385
- font_family="Vazirmatn",
386
- title_font_family="Vazirmatn",
387
- title_font_size=20
388
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  else:
390
  fig_area = None
391
 
@@ -393,6 +458,7 @@ def create_analysis_charts(df):
393
 
394
  # تابع برای ایجاد مدل پیش‌بینی
395
  def create_prediction_model(df):
 
396
  dates = pd.date_range(end=datetime.now(), periods=90)
397
  farm_ids = df['مزرعه'].unique()
398
 
@@ -402,15 +468,16 @@ def create_prediction_model(df):
402
  base_height = np.random.uniform(0.5, 3.0)
403
 
404
  for date in dates:
 
405
  day_of_year = date.dayofyear
406
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.2
407
  trend_factor = date.dayofyear / 365 * 0.3
408
 
409
  ndvi = base_ndvi + seasonal_factor + trend_factor + np.random.normal(0, 0.05)
410
- ndvi = max(0, min(1, ndvi))
411
 
412
  height = base_height + seasonal_factor * 2 + trend_factor + np.random.normal(0, 0.1)
413
- height = max(0, height)
414
 
415
  time_series_data.append({
416
  'farm_id': farm_id,
@@ -423,17 +490,22 @@ def create_prediction_model(df):
423
 
424
  time_df = pd.DataFrame(time_series_data)
425
 
 
426
  X = time_df[['ndvi', 'day_of_year', 'month']].values
427
  y = time_df['height'].values
428
 
 
429
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
430
 
 
431
  model = RandomForestRegressor(n_estimators=100, random_state=42)
432
  model.fit(X_train, y_train)
433
 
 
434
  y_pred = model.predict(X_test)
435
  mse = mean_squared_error(y_test, y_pred)
436
 
 
437
  results_df = pd.DataFrame({
438
  'Actual': y_test,
439
  'Predicted': y_pred
@@ -462,7 +534,8 @@ def create_prediction_model(df):
462
  title_font_size=20
463
  )
464
 
465
- farm_id = farm_ids[0]
 
466
  farm_data = time_df[time_df['farm_id'] == farm_id]
467
 
468
  fig_ts = px.line(
@@ -480,7 +553,10 @@ def create_prediction_model(df):
480
  yaxis_title='مقدار'
481
  )
482
 
483
- return model, fig, fig_ts, time_df
 
 
 
484
 
485
  # بارگذاری داده‌های مزارع نیشکر
486
  farm_coordinates, farm_database, merged_data = load_farm_data()
@@ -488,6 +564,7 @@ farm_coordinates, farm_database, merged_data = load_farm_data()
488
  # منوی اصلی
489
  st.title("🌱 سامانه مانیتورینگ مزارع نیشکر")
490
 
 
491
  tabs = st.tabs([
492
  "📊 داشبورد",
493
  "🗺️ نقشه مزارع",
@@ -497,9 +574,11 @@ tabs = st.tabs([
497
  "⚙️ تنظیمات"
498
  ])
499
 
 
500
  with tabs[0]:
501
  st.header("داشبورد مدیریت مزارع نیشکر")
502
 
 
503
  col1, col2, col3, col4 = st.columns(4)
504
 
505
  with col1:
@@ -510,18 +589,41 @@ with tabs[0]:
510
  display_metric_card("تعداد واریته‌ها", unique_varieties, "🌿")
511
 
512
  with col3:
513
- avg_age = merged_data['سن_x'].mean() if 'سن_x' in merged_data.columns else merged_data['سن'].mean()
514
- display_metric_card("میانگین سن", f"{avg_age:.1f} سال", "📅")
 
 
 
 
 
 
 
 
 
 
 
 
515
 
516
  with col4:
517
  if 'مساحت' in merged_data.columns:
518
- total_area = merged_data['مساحت'].sum()
519
- display_metric_card("مساحت کل", f"{total_area:.1f} هکتار", "📏")
 
 
 
 
 
 
 
 
 
 
520
  else:
521
  display_metric_card("تعداد کانال‌ها", len(merged_data['کانال'].unique()) if 'کانال' in merged_data.columns else "نامشخص", "🚿")
522
 
523
  st.markdown("---")
524
 
 
525
  st.subheader("تحلیل کلی مزارع")
526
 
527
  col1, col2 = st.columns(2)
@@ -535,8 +637,10 @@ with tabs[0]:
535
  if fig_area:
536
  st.plotly_chart(fig_area, use_container_width=True)
537
 
 
538
  st.subheader("اطلاعات مزارع")
539
 
 
540
  if 'مساحت' in merged_data.columns:
541
  display_columns = ['مزرعه', 'کانال', 'اداره', 'سن_x', 'واریته', 'مساحت', 'روز']
542
  column_config = {
@@ -564,6 +668,7 @@ with tabs[0]:
564
  hide_index=True
565
  )
566
 
 
567
  with tabs[1]:
568
  st.header("نقشه مزارع نیشکر")
569
 
@@ -572,15 +677,19 @@ with tabs[1]:
572
  with col1:
573
  st.subheader("فیلتر مزارع")
574
 
 
575
  days = ['همه روزها', 'شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه']
576
  selected_day = st.selectbox("انتخاب روز هفته", days)
577
 
 
578
  variety_column = 'واریته' if 'واریته' in merged_data.columns else 'تنوع'
579
  varieties = ['همه واریته‌ها'] + list(merged_data[variety_column].unique())
580
  selected_variety = st.selectbox("انتخاب واریته", varieties)
581
 
 
582
  age_column = 'سن_x' if 'سن_x' in merged_data.columns else 'سن'
583
- min_age, max_age = int(merged_data[age_column].min()), int(merged_data[age_column].max())
 
584
  age_range = st.slider(
585
  "محدوده سن (سال)",
586
  min_value=min_age,
@@ -588,6 +697,7 @@ with tabs[1]:
588
  value=(min_age, max_age)
589
  )
590
 
 
591
  filtered_df = merged_data.copy()
592
 
593
  if selected_day != 'همه روزها' and 'روز' in filtered_df.columns:
@@ -596,17 +706,21 @@ with tabs[1]:
596
  if selected_variety != 'همه واریته‌ها':
597
  filtered_df = filtered_df[filtered_df[variety_column] == selected_variety]
598
 
599
- filtered_df = filtered_df[(filtered_df[age_column] >= age_range[0]) & (filtered_df[age_column] <= age_range[1])]
 
 
600
 
601
  st.write(f"تعداد مزارع نمایش داده شده: {len(filtered_df)}")
602
 
603
  with col2:
 
604
  if len(filtered_df) > 0:
605
  farm_map = create_farm_map(filtered_df)
606
  folium_static(farm_map, width=800, height=500)
607
  else:
608
  st.warning("هیچ مزرعه‌ای با فیلترهای انتخاب شده یافت نشد.")
609
 
 
610
  with tabs[2]:
611
  st.header("ورود و آپلود اطلاعات")
612
 
@@ -618,12 +732,14 @@ with tabs[2]:
618
  col1, col2 = st.columns(2)
619
 
620
  with col1:
 
621
  option = st.radio("انتخاب گزینه", ["ویرایش مزرعه موجود", "ایجاد مزرعه جدید"])
622
 
623
  if option == "ویرایش مزرعه موجود":
624
  farm_name = st.selectbox("انتخاب مزرعه", merged_data['مزرعه'].tolist())
625
  selected_farm = merged_data[merged_data['مزرعه'] == farm_name].iloc[0]
626
 
 
627
  if 'کانال' in merged_data.columns:
628
  canal = st.text_input("کانال", value=selected_farm['کانال'])
629
  office = st.text_input("اداره", value=selected_farm['اداره'])
@@ -634,7 +750,7 @@ with tabs[2]:
634
  day = st.selectbox("روز", options=['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'], index=['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'].index(selected_farm['روز']))
635
 
636
  age_column = 'سن_x' if 'سن_x' in selected_farm else 'سن'
637
- age = st.number_input("سن (سال)", value=int(selected_farm[age_column]), min_value=1, format="%d")
638
 
639
  lat = st.number_input("عرض جغرافیایی", value=float(selected_farm['عرض جغرافیایی']), format="%.6f")
640
  lon = st.number_input("طول جغرافیایی", value=float(selected_farm['طول جغرافیایی']), format="%.6f")
@@ -642,8 +758,10 @@ with tabs[2]:
642
  if st.button("بروزرسانی اطلاعات"):
643
  st.success("اطلاعات مزرعه با موفقیت بروزرسانی شد.")
644
  else:
 
645
  farm_name = st.text_input("نام مزرعه", value=f"مزرعه جدید")
646
 
 
647
  if 'کانال' in merged_data.columns:
648
  canal = st.text_input("کانال")
649
  office = st.text_input("اداره")
@@ -653,7 +771,7 @@ with tabs[2]:
653
  group = st.text_input("گروه")
654
  day = st.selectbox("روز", options=['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'])
655
 
656
- age = st.number_input("سن (سال)", value=1, min_value=1, format="%d")
657
  lat = st.number_input("عرض جغرافیایی", value=31.5, format="%.6f")
658
  lon = st.number_input("طول جغرافیایی", value=48.5, format="%.6f")
659
 
@@ -661,9 +779,11 @@ with tabs[2]:
661
  st.success("مزرعه جدید با موفقیت ثبت شد.")
662
 
663
  with col2:
 
664
  st.subheader("انتخاب موقعیت روی نقشه")
665
  st.write("برای انتخاب موقعیت دقیق، روی نقشه کلیک کنید.")
666
 
 
667
  center_lat = merged_data['عرض جغرافیایی'].mean()
668
  center_lon = merged_data['طول جغرافیایی'].mean()
669
  m = folium.Map(location=[center_lat, center_lon], zoom_start=10)
@@ -722,6 +842,7 @@ with tabs[2]:
722
  except Exception as e:
723
  st.error(f"خطا در خواندن فایل: {e}")
724
 
 
725
  with tabs[3]:
726
  st.header("تحلیل داده‌ها")
727
 
@@ -730,27 +851,35 @@ with tabs[3]:
730
  with analysis_tabs[0]:
731
  st.subheader("محاسبه و نمایش شاخص‌های گیاهی")
732
 
 
733
  ee_connected = initialize_earth_engine()
734
 
735
  if ee_connected:
 
736
  farm_name = st.selectbox("انتخاب مزرعه برای تحلیل", merged_data['مزرعه'].tolist(), key="farm_select_indices")
737
  selected_farm = merged_data[merged_data['مزرعه'] == farm_name].iloc[0]
738
 
 
739
  date = st.date_input("انتخاب تاریخ", value=datetime.now() - timedelta(days=7))
740
 
741
  if st.button("محاسبه شاخص‌ها"):
742
  with st.spinner("در حال محاسبه شاخص‌ها..."):
 
743
  point = ee.Geometry.Point([selected_farm['طول جغرافیایی'], selected_farm['عرض جغرافیایی']])
744
- buffer = point.buffer(100)
745
 
 
746
  indices = calculate_indices(date.strftime('%Y-%m-%d'), buffer)
747
 
748
  if indices is not None:
 
749
  st.success("شاخص‌ها با موفقیت محاسبه شدند.")
750
 
 
751
  Map = geemap.Map()
752
  Map.centerObject(buffer, 14)
753
 
 
754
  vis_params = {
755
  'min': 0,
756
  'max': 1,
@@ -764,10 +893,13 @@ with tabs[3]:
764
  Map.addLayer(indices.select('LAI'), {'min': 0, 'max': 5, 'palette': ['red', 'yellow', 'green']}, 'LAI')
765
  Map.addLayer(indices.select('CHL'), {'min': 0, 'max': 3, 'palette': ['red', 'yellow', 'green']}, 'CHL')
766
 
 
767
  Map.addLayerControl()
768
 
 
769
  Map.to_streamlit(height=500)
770
 
 
771
  col1, col2, col3 = st.columns(3)
772
 
773
  with col1:
@@ -787,12 +919,16 @@ with tabs[3]:
787
  with analysis_tabs[1]:
788
  st.subheader("تحلیل سری زمانی")
789
 
790
- model, fig_model, fig_ts, time_df = create_prediction_model(merged_data)
 
791
 
 
792
  farm_name = st.selectbox("انتخاب مزرعه برای تحلیل", merged_data['مزرعه'].tolist(), key="farm_select_ts")
793
 
 
794
  farm_time_data = time_df[time_df['farm_id'] == farm_name]
795
 
 
796
  fig_farm_ts = px.line(
797
  farm_time_data,
798
  x='date',
@@ -810,16 +946,19 @@ with tabs[3]:
810
 
811
  st.plotly_chart(fig_farm_ts, use_container_width=True)
812
 
 
813
  st.subheader("تحلیل روند")
814
 
815
  col1, col2 = st.columns(2)
816
 
817
  with col1:
 
818
  window_size = st.slider("اندازه پنجره میانگین متحرک", min_value=3, max_value=30, value=7)
819
 
820
  farm_time_data['ndvi_ma'] = farm_time_data['ndvi'].rolling(window=window_size).mean()
821
  farm_time_data['height_ma'] = farm_time_data['height'].rolling(window=window_size).mean()
822
 
 
823
  fig_ma = px.line(
824
  farm_time_data.dropna(),
825
  x='date',
@@ -838,6 +977,7 @@ with tabs[3]:
838
  st.plotly_chart(fig_ma, use_container_width=True)
839
 
840
  with col2:
 
841
  monthly_data = farm_time_data.groupby('month').agg({
842
  'ndvi': 'mean',
843
  'height': 'mean'
@@ -864,14 +1004,18 @@ with tabs[3]:
864
  with analysis_tabs[2]:
865
  st.subheader("تشخیص تنش‌ها")
866
 
 
867
  farm_name = st.selectbox("انتخاب مزرعه برای تحلیل", merged_data['مزرعه'].tolist(), key="farm_select_stress")
868
 
 
869
  dates = pd.date_range(end=datetime.now(), periods=90)
870
  stress_data = []
871
 
 
872
  water_stress_threshold = 0.3
873
  base_ndwi = np.random.uniform(0.2, 0.5)
874
 
 
875
  disease_threshold = 0.4
876
  base_chl = np.random.uniform(1.5, 2.5)
877
 
@@ -879,6 +1023,7 @@ with tabs[3]:
879
  day_of_year = date.dayofyear
880
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.2
881
 
 
882
  water_stress_event = False
883
  if 30 <= day_of_year <= 40 or 70 <= day_of_year <= 75:
884
  water_stress_event = True
@@ -886,6 +1031,7 @@ with tabs[3]:
886
  else:
887
  ndwi = base_ndwi + seasonal_factor + np.random.normal(0, 0.05)
888
 
 
889
  disease_event = False
890
  if 50 <= day_of_year <= 60:
891
  disease_event = True
@@ -893,6 +1039,7 @@ with tabs[3]:
893
  else:
894
  chl = base_chl + seasonal_factor + np.random.normal(0, 0.1)
895
 
 
896
  ndwi = max(-0.5, min(0.8, ndwi))
897
  chl = max(0.5, min(3.0, chl))
898
 
@@ -903,13 +1050,15 @@ with tabs[3]:
903
  'water_stress': 1 if ndwi < water_stress_threshold else 0,
904
  'disease_stress': 1 if chl < disease_threshold else 0,
905
  'water_stress_event': water_stress_event,
906
- 'disease_stress_event': disease_event
907
  })
908
 
909
  stress_df = pd.DataFrame(stress_data)
910
 
 
911
  fig_stress = go.Figure()
912
 
 
913
  fig_stress.add_trace(go.Scatter(
914
  x=stress_df['date'],
915
  y=stress_df['ndwi'],
@@ -917,6 +1066,7 @@ with tabs[3]:
917
  line=dict(color='blue')
918
  ))
919
 
 
920
  fig_stress.add_trace(go.Scatter(
921
  x=stress_df['date'],
922
  y=stress_df['chl'],
@@ -925,6 +1075,7 @@ with tabs[3]:
925
  yaxis='y2'
926
  ))
927
 
 
928
  fig_stress.add_shape(
929
  type='line',
930
  x0=stress_df['date'].min(),
@@ -935,6 +1086,7 @@ with tabs[3]:
935
  name='آستانه تنش آبی'
936
  )
937
 
 
938
  fig_stress.add_shape(
939
  type='line',
940
  x0=stress_df['date'].min(),
@@ -946,6 +1098,7 @@ with tabs[3]:
946
  name='آستانه تنش بیماری'
947
  )
948
 
 
949
  fig_stress.update_layout(
950
  title='تشخیص تنش‌های آبی و بیماری',
951
  font_family="Vazirmatn",
@@ -976,11 +1129,13 @@ with tabs[3]:
976
 
977
  st.plotly_chart(fig_stress, use_container_width=True)
978
 
 
979
  st.subheader("هشدارهای تنش")
980
 
981
  col1, col2 = st.columns(2)
982
 
983
  with col1:
 
984
  water_stress_days = stress_df[stress_df['water_stress'] == 1]
985
 
986
  if len(water_stress_days) > 0:
@@ -998,6 +1153,7 @@ with tabs[3]:
998
  st.success("هیچ تنش آبی تشخیص داده نشده است.")
999
 
1000
  with col2:
 
1001
  disease_stress_days = stress_df[stress_df['disease_stress'] == 1]
1002
 
1003
  if len(disease_stress_days) > 0:
@@ -1017,10 +1173,13 @@ with tabs[3]:
1017
  with analysis_tabs[3]:
1018
  st.subheader("پیش‌بینی رشد")
1019
 
 
1020
  farm_name = st.selectbox("انتخاب مزرعه برای پیش‌بینی", merged_data['مزرعه'].tolist(), key="farm_select_predict")
1021
 
 
1022
  farm_time_data = time_df[time_df['farm_id'] == farm_name]
1023
 
 
1024
  st.subheader("تنظیمات پیش‌بینی")
1025
 
1026
  col1, col2 = st.columns(2)
@@ -1033,6 +1192,7 @@ with tabs[3]:
1033
 
1034
  if st.button("انجام پیش‌بینی"):
1035
  with st.spinner("در حال انجام پیش‌بینی..."):
 
1036
  last_date = farm_time_data['date'].max()
1037
  future_dates = pd.date_range(start=last_date + timedelta(days=1), periods=days_to_predict)
1038
 
@@ -1046,6 +1206,7 @@ with tabs[3]:
1046
 
1047
  future_df = pd.DataFrame(future_data)
1048
 
 
1049
  base_ndvi = farm_time_data['ndvi'].iloc[-1]
1050
  future_ndvi = []
1051
 
@@ -1053,28 +1214,38 @@ with tabs[3]:
1053
  seasonal_factor = np.sin(day / 365 * 2 * np.pi) * 0.2
1054
  trend_factor = day / 365 * 0.1
1055
  ndvi = base_ndvi + seasonal_factor + trend_factor
1056
- ndvi = max(0, min(1, ndvi))
1057
  future_ndvi.append(ndvi)
1058
 
1059
  future_df['ndvi'] = future_ndvi
1060
 
 
1061
  X_future = future_df[['ndvi', 'day_of_year', 'month']].values
1062
  future_df['height'] = model.predict(X_future)
1063
 
1064
- z_score = {90: 1.645, 95: 1.96, 99: 2.576}.get(confidence_interval, 1.96)
 
 
 
 
 
 
1065
  mse = mean_squared_error(y_test, y_pred)
1066
  std_dev = np.sqrt(mse)
1067
 
1068
  future_df['height_lower'] = future_df['height'] - z_score * std_dev
1069
  future_df['height_upper'] = future_df['height'] + z_score * std_dev
1070
 
 
1071
  combined_df = pd.concat([
1072
  farm_time_data[['date', 'ndvi', 'height']],
1073
  future_df[['date', 'ndvi', 'height', 'height_lower', 'height_upper']]
1074
  ])
1075
 
 
1076
  fig_predict = go.Figure()
1077
 
 
1078
  past_data = combined_df[combined_df['date'] <= last_date]
1079
 
1080
  fig_predict.add_trace(go.Scatter(
@@ -1084,6 +1255,7 @@ with tabs[3]:
1084
  line=dict(color='blue')
1085
  ))
1086
 
 
1087
  future_data = combined_df[combined_df['date'] > last_date]
1088
 
1089
  fig_predict.add_trace(go.Scatter(
@@ -1093,6 +1265,7 @@ with tabs[3]:
1093
  line=dict(color='red')
1094
  ))
1095
 
 
1096
  fig_predict.add_trace(go.Scatter(
1097
  x=future_data['date'],
1098
  y=future_data['height_upper'],
@@ -1111,6 +1284,7 @@ with tabs[3]:
1111
  showlegend=True
1112
  ))
1113
 
 
1114
  fig_predict.update_layout(
1115
  title=f'پیش‌بینی ارتفاع برای {days_to_predict} روز آینده',
1116
  font_family="Vazirmatn",
@@ -1129,6 +1303,7 @@ with tabs[3]:
1129
 
1130
  st.plotly_chart(fig_predict, use_container_width=True)
1131
 
 
1132
  st.subheader("جدول پیش‌بینی")
1133
 
1134
  st.dataframe(
@@ -1143,6 +1318,7 @@ with tabs[3]:
1143
  hide_index=True
1144
  )
1145
 
 
1146
  st.subheader("خلاصه پیش‌بینی")
1147
 
1148
  col1, col2, col3 = st.columns(3)
@@ -1170,14 +1346,17 @@ with tabs[3]:
1170
  f"{final_height:.2f} متر"
1171
  )
1172
 
 
1173
  with tabs[4]:
1174
  st.header("گزارش‌گیری")
1175
 
 
1176
  report_type = st.selectbox(
1177
  "انتخاب نوع گزارش",
1178
  ["گزارش وضعیت کلی مزارع", "گزارش تحلیل شاخص‌ها", "گزارش تنش‌ها", "گزارش پیش‌بینی رشد"]
1179
  )
1180
 
 
1181
  col1, col2 = st.columns(2)
1182
 
1183
  with col1:
@@ -1186,14 +1365,16 @@ with tabs[4]:
1186
  with col2:
1187
  end_date = st.date_input("تاریخ پایان", value=datetime.now())
1188
 
 
1189
  selected_farms = st.multiselect(
1190
  "انتخاب مزارع",
1191
  options=merged_data['مزرعه'].tolist()
1192
  )
1193
 
1194
  if not selected_farms:
1195
- selected_farms = merged_data['مزرعه'].tolist()
1196
 
 
1197
  filtered_farm_df = merged_data[merged_data['مزرعه'].isin(selected_farms)]
1198
 
1199
  if st.button("تولید گزارش"):
@@ -1201,6 +1382,7 @@ with tabs[4]:
1201
  if report_type == "گزارش وضعیت کلی مزارع":
1202
  st.subheader("گزارش وضعیت کلی مزارع")
1203
 
 
1204
  fig_variety, fig_age, fig_area = create_analysis_charts(filtered_farm_df)
1205
 
1206
  col1, col2 = st.columns(2)
@@ -1214,8 +1396,10 @@ with tabs[4]:
1214
  if fig_area:
1215
  st.plotly_chart(fig_area, use_container_width=True)
1216
 
 
1217
  st.subheader("اطلاعات مزارع")
1218
 
 
1219
  if 'مساحت' in filtered_farm_df.columns:
1220
  display_columns = ['مزرعه', 'کانال', 'اداره', 'سن_x', 'واریته', 'مساحت', 'روز']
1221
  column_config = {
@@ -1243,6 +1427,7 @@ with tabs[4]:
1243
  hide_index=True
1244
  )
1245
 
 
1246
  st.subheader("آمار خلاصه")
1247
 
1248
  col1, col2, col3, col4 = st.columns(4)
@@ -1252,13 +1437,15 @@ with tabs[4]:
1252
 
1253
  with col2:
1254
  if 'مساحت' in filtered_farm_df.columns:
1255
- st.metric("میانگین مساحت", f"{filtered_farm_df['مساحت'].mean():.2f} هکتار")
 
1256
  else:
1257
  st.metric("تعداد واریته‌ها", len(filtered_farm_df['تنوع'].unique()))
1258
 
1259
  with col3:
1260
  age_column = 'سن_x' if 'سن_x' in filtered_farm_df.columns else 'سن'
1261
- st.metric("میانگین سن", f"{filtered_farm_df[age_column].mean():.1f} سال")
 
1262
 
1263
  with col4:
1264
  if 'روز' in filtered_farm_df.columns:
@@ -1266,12 +1453,15 @@ with tabs[4]:
1266
  else:
1267
  st.metric("تعداد مزارع", len(filtered_farm_df))
1268
 
 
1269
  st.subheader("نقشه مزارع")
1270
  farm_map = create_farm_map(filtered_farm_df)
1271
  folium_static(farm_map, width=800, height=500)
1272
 
 
1273
  st.subheader("دانلود گزارش")
1274
 
 
1275
  figs = [fig_variety, fig_age]
1276
  if fig_area:
1277
  figs.append(fig_area)
@@ -1280,6 +1470,7 @@ with tabs[4]:
1280
 
1281
  pdf_buffer = create_report_pdf(figs, tables, "گزارش وضعیت کلی مزارع")
1282
 
 
1283
  st.download_button(
1284
  label="دانلود گزارش (PDF)",
1285
  data=pdf_buffer,
@@ -1287,6 +1478,7 @@ with tabs[4]:
1287
  mime="application/pdf"
1288
  )
1289
 
 
1290
  excel_buffer = io.BytesIO()
1291
  filtered_farm_df.to_excel(excel_buffer, index=False)
1292
  excel_buffer.seek(0)
@@ -1301,9 +1493,11 @@ with tabs[4]:
1301
  elif report_type == "گزارش تحلیل شاخص‌ها":
1302
  st.subheader("گزارش تحلیل شاخص‌ها")
1303
 
 
1304
  indices_data = []
1305
 
1306
  for farm_name in selected_farms:
 
1307
  base_ndvi = np.random.uniform(0.3, 0.8)
1308
  base_ndwi = np.random.uniform(0.1, 0.5)
1309
  base_evi = np.random.uniform(0.3, 0.7)
@@ -1311,9 +1505,11 @@ with tabs[4]:
1311
  base_lai = np.random.uniform(1.0, 4.0)
1312
  base_chl = np.random.uniform(1.0, 3.0)
1313
 
 
1314
  date_range = pd.date_range(start=start_date, end=end_date)
1315
 
1316
  for date in date_range:
 
1317
  day_of_year = date.dayofyear
1318
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.1
1319
 
@@ -1324,6 +1520,7 @@ with tabs[4]:
1324
  lai = base_lai + seasonal_factor * 2 + np.random.normal(0, 0.2)
1325
  chl = base_chl + seasonal_factor + np.random.normal(0, 0.1)
1326
 
 
1327
  ndvi = max(0, min(1, ndvi))
1328
  ndwi = max(-0.5, min(0.8, ndwi))
1329
  evi = max(0, min(1, evi))
@@ -1344,6 +1541,7 @@ with tabs[4]:
1344
 
1345
  indices_df = pd.DataFrame(indices_data)
1346
 
 
1347
  avg_indices = indices_df.groupby('farm_name').agg({
1348
  'ndvi': 'mean',
1349
  'ndwi': 'mean',
@@ -1368,8 +1566,10 @@ with tabs[4]:
1368
  hide_index=True
1369
  )
1370
 
 
1371
  st.subheader("مقایسه شاخص‌ها بین مزارع")
1372
 
 
1373
  selected_index = st.selectbox(
1374
  "انتخاب شاخص",
1375
  ["NDVI", "NDWI", "EVI", "NDMI", "LAI", "CHL"]
@@ -1384,6 +1584,7 @@ with tabs[4]:
1384
  "CHL": "chl"
1385
  }
1386
 
 
1387
  fig_compare = px.bar(
1388
  avg_indices,
1389
  x='farm_name',
@@ -1402,15 +1603,19 @@ with tabs[4]:
1402
 
1403
  st.plotly_chart(fig_compare, use_container_width=True)
1404
 
 
1405
  st.subheader("سری زمانی شاخص‌ها")
1406
 
 
1407
  selected_farm_name = st.selectbox(
1408
  "انتخاب مزرعه",
1409
  options=selected_farms
1410
  )
1411
 
 
1412
  farm_indices = indices_df[indices_df['farm_name'] == selected_farm_name]
1413
 
 
1414
  fig_ts = px.line(
1415
  farm_indices,
1416
  x='date',
@@ -1428,13 +1633,16 @@ with tabs[4]:
1428
 
1429
  st.plotly_chart(fig_ts, use_container_width=True)
1430
 
 
1431
  st.subheader("دانلود گزارش")
1432
 
 
1433
  figs = [fig_compare, fig_ts]
1434
  tables = [avg_indices]
1435
 
1436
  pdf_buffer = create_report_pdf(figs, tables, "گزارش تحلیل شاخص‌ها")
1437
 
 
1438
  st.download_button(
1439
  label="دانلود گزارش (PDF)",
1440
  data=pdf_buffer,
@@ -1442,6 +1650,7 @@ with tabs[4]:
1442
  mime="application/pdf"
1443
  )
1444
 
 
1445
  excel_buffer = io.BytesIO()
1446
  indices_df.to_excel(excel_buffer, index=False)
1447
  excel_buffer.seek(0)
@@ -1456,35 +1665,42 @@ with tabs[4]:
1456
  elif report_type == "گزارش تنش‌ها":
1457
  st.subheader("گزارش تنش‌ها")
1458
 
 
1459
  stress_data = []
1460
 
1461
  for farm_name in selected_farms:
 
1462
  base_ndwi = np.random.uniform(0.2, 0.5)
1463
  base_chl = np.random.uniform(1.5, 2.5)
1464
 
 
1465
  water_stress_threshold = 0.3
1466
  disease_threshold = 0.4
1467
 
 
1468
  date_range = pd.date_range(start=start_date, end=end_date)
1469
 
1470
  for date in date_range:
1471
  day_of_year = date.dayofyear
1472
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.2
1473
 
 
1474
  water_stress_event = False
1475
- if (day_of_year % 30) < 5:
1476
  water_stress_event = True
1477
  ndwi = base_ndwi - 0.3 + np.random.normal(0, 0.05)
1478
  else:
1479
  ndwi = base_ndwi + seasonal_factor + np.random.normal(0, 0.05)
1480
 
 
1481
  disease_event = False
1482
- if (day_of_year % 45) < 7:
1483
  disease_event = True
1484
  chl = base_chl - 0.5 + np.random.normal(0, 0.1)
1485
  else:
1486
  chl = base_chl + seasonal_factor + np.random.normal(0, 0.1)
1487
 
 
1488
  ndwi = max(-0.5, min(0.8, ndwi))
1489
  chl = max(0.5, min(3.0, chl))
1490
 
@@ -1496,11 +1712,12 @@ with tabs[4]:
1496
  'water_stress': 1 if ndwi < water_stress_threshold else 0,
1497
  'disease_stress': 1 if chl < disease_threshold else 0,
1498
  'water_stress_event': water_stress_event,
1499
- 'disease_stress_event': disease_event
1500
  })
1501
 
1502
  stress_df = pd.DataFrame(stress_data)
1503
 
 
1504
  stress_stats = stress_df.groupby('farm_name').agg({
1505
  'water_stress': 'sum',
1506
  'disease_stress': 'sum'
@@ -1514,6 +1731,7 @@ with tabs[4]:
1514
  st.subheader("آمار تنش‌ها برای هر مزرعه")
1515
  st.dataframe(stress_stats, hide_index=True)
1516
 
 
1517
  fig_stress_compare = px.bar(
1518
  stress_stats,
1519
  x='farm_name',
@@ -1531,18 +1749,23 @@ with tabs[4]:
1531
 
1532
  st.plotly_chart(fig_stress_compare, use_container_width=True)
1533
 
 
1534
  st.subheader("سری زمانی تنش‌ها")
1535
 
 
1536
  selected_farm_name = st.selectbox(
1537
  "انتخاب مزرعه",
1538
  options=selected_farms,
1539
  key="farm_select_stress_report"
1540
  )
1541
 
 
1542
  farm_stress = stress_df[stress_df['farm_name'] == selected_farm_name]
1543
 
 
1544
  fig_stress_ts = go.Figure()
1545
 
 
1546
  fig_stress_ts.add_trace(go.Scatter(
1547
  x=farm_stress['date'],
1548
  y=farm_stress['ndwi'],
@@ -1550,6 +1773,7 @@ with tabs[4]:
1550
  line=dict(color='blue')
1551
  ))
1552
 
 
1553
  fig_stress_ts.add_trace(go.Scatter(
1554
  x=farm_stress['date'],
1555
  y=farm_stress['chl'],
@@ -1558,25 +1782,28 @@ with tabs[4]:
1558
  yaxis='y2'
1559
  ))
1560
 
 
1561
  fig_stress_ts.add_shape(
1562
  type='line',
1563
  x0=farm_stress['date'].min(),
1564
- y0=0.3,
1565
  x1=farm_stress['date'].max(),
1566
  y1=0.3,
1567
  line=dict(color='red', dash='dash')
1568
  )
1569
 
 
1570
  fig_stress_ts.add_shape(
1571
  type='line',
1572
  x0=farm_stress['date'].min(),
1573
- y0=0.4,
1574
  x1=farm_stress['date'].max(),
1575
  y1=0.4,
1576
  line=dict(color='orange', dash='dash'),
1577
  yaxis='y2'
1578
  )
1579
 
 
1580
  fig_stress_ts.update_layout(
1581
  title=f'سری زمانی تنش‌ها برای {selected_farm_name}',
1582
  font_family="Vazirmatn",
@@ -1607,8 +1834,10 @@ with tabs[4]:
1607
 
1608
  st.plotly_chart(fig_stress_ts, use_container_width=True)
1609
 
 
1610
  st.subheader("روزهای تنش")
1611
 
 
1612
  stress_days = farm_stress[(farm_stress['water_stress'] == 1) | (farm_stress['disease_stress'] == 1)]
1613
  stress_days = stress_days[['date', 'ndwi', 'chl', 'water_stress', 'disease_stress']]
1614
 
@@ -1627,13 +1856,16 @@ with tabs[4]:
1627
  else:
1628
  st.info("هیچ روز تنشی برای این مزرعه در بازه زمانی انتخاب شده یافت نشد.")
1629
 
 
1630
  st.subheader("دانلود گزارش")
1631
 
 
1632
  figs = [fig_stress_compare, fig_stress_ts]
1633
  tables = [stress_stats, stress_days]
1634
 
1635
  pdf_buffer = create_report_pdf(figs, tables, "گزارش تنش‌ها")
1636
 
 
1637
  st.download_button(
1638
  label="دانلود گزارش (PDF)",
1639
  data=pdf_buffer,
@@ -1641,6 +1873,7 @@ with tabs[4]:
1641
  mime="application/pdf"
1642
  )
1643
 
 
1644
  excel_buffer = io.BytesIO()
1645
  stress_df.to_excel(excel_buffer, index=False)
1646
  excel_buffer.seek(0)
@@ -1655,10 +1888,13 @@ with tabs[4]:
1655
  elif report_type == "گزارش پیش‌بینی رشد":
1656
  st.subheader("گزارش پیش‌بینی رشد")
1657
 
1658
- model, fig_model, fig_ts, time_df = create_prediction_model(merged_data)
 
1659
 
 
1660
  filtered_time_df = time_df[time_df['farm_id'].isin(selected_farms)]
1661
 
 
1662
  growth_stats = filtered_time_df.groupby('farm_id').agg({
1663
  'height': ['first', 'last', lambda x: x.iloc[-1] - x.iloc[0]]
1664
  })
@@ -1678,6 +1914,7 @@ with tabs[4]:
1678
  hide_index=True
1679
  )
1680
 
 
1681
  fig_growth = px.bar(
1682
  growth_stats,
1683
  x='farm_id',
@@ -1696,16 +1933,20 @@ with tabs[4]:
1696
 
1697
  st.plotly_chart(fig_growth, use_container_width=True)
1698
 
 
1699
  st.subheader("سری زمانی رشد")
1700
 
 
1701
  selected_farm_name = st.selectbox(
1702
  "انتخاب مزرعه",
1703
  options=selected_farms,
1704
  key="farm_select_growth_report"
1705
  )
1706
 
 
1707
  farm_growth = filtered_time_df[filtered_time_df['farm_id'] == selected_farm_name]
1708
 
 
1709
  fig_growth_ts = px.line(
1710
  farm_growth,
1711
  x='date',
@@ -1722,13 +1963,16 @@ with tabs[4]:
1722
 
1723
  st.plotly_chart(fig_growth_ts, use_container_width=True)
1724
 
 
1725
  st.subheader("دانلود گزارش")
1726
 
 
1727
  figs = [fig_growth, fig_growth_ts]
1728
  tables = [growth_stats]
1729
 
1730
  pdf_buffer = create_report_pdf(figs, tables, "گزارش پیش‌بینی رشد")
1731
 
 
1732
  st.download_button(
1733
  label="دانلود گزارش (PDF)",
1734
  data=pdf_buffer,
@@ -1736,6 +1980,7 @@ with tabs[4]:
1736
  mime="application/pdf"
1737
  )
1738
 
 
1739
  excel_buffer = io.BytesIO()
1740
  filtered_time_df.to_excel(excel_buffer, index=False)
1741
  excel_buffer.seek(0)
@@ -1747,6 +1992,7 @@ with tabs[4]:
1747
  mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1748
  )
1749
 
 
1750
  with tabs[5]:
1751
  st.header("تنظیمات")
1752
 
@@ -1755,6 +2001,7 @@ with tabs[5]:
1755
  with settings_tabs[0]:
1756
  st.subheader("تنظیمات عمومی")
1757
 
 
1758
  st.write("### تنظیمات ظاهری")
1759
 
1760
  col1, col2 = st.columns(2)
@@ -1781,6 +2028,7 @@ with tabs[5]:
1781
  ["Viridis (پیش‌فرض)", "Plasma", "Inferno", "Magma", "Cividis"]
1782
  )
1783
 
 
1784
  st.write("### تنظیمات زبان")
1785
 
1786
  language = st.radio(
@@ -1788,6 +2036,7 @@ with tabs[5]:
1788
  ["فارسی (پیش‌فرض)", "انگلیسی"]
1789
  )
1790
 
 
1791
  st.write("### تنظیمات واحدها")
1792
 
1793
  col1, col2 = st.columns(2)
@@ -1814,12 +2063,14 @@ with tabs[5]:
1814
  ["1,234.56 (پیش‌فرض)", "1.234,56"]
1815
  )
1816
 
 
1817
  if st.button("ذخیره تنظیمات"):
1818
  st.success("تنظیمات با موفقیت ذخیره شد.")
1819
 
1820
  with settings_tabs[1]:
1821
  st.subheader("اتصال به Google Earth Engine")
1822
 
 
1823
  st.write("""
1824
  برای اتصال به Google Earth Engine، از حساب سرویس زیر استفاده می‌شود:
1825
 
@@ -1827,19 +2078,23 @@ with tabs[5]:
1827
  - پروژه: `ee-esmaeilkiani13877`
1828
  """)
1829
 
 
1830
  ee_connected = initialize_earth_engine()
1831
 
1832
  if ee_connected:
1833
  st.success("اتصال به Google Earth Engine برقرار است.")
1834
 
 
1835
  if st.button("تست اتصال"):
1836
  with st.spinner("در حال تست اتصال..."):
 
1837
  import time
1838
  time.sleep(2)
1839
  st.success("اتصال با موفقیت برقرار شد.")
1840
  else:
1841
  st.error("اتصال به Google Earth Engine برقرار نشد. لطفاً تنظیمات را بررسی کنید.")
1842
 
 
1843
  st.write("### تنظیمات پیشرفته")
1844
 
1845
  col1, col2 = st.columns(2)
@@ -1857,6 +2112,7 @@ with tabs[5]:
1857
  with settings_tabs[2]:
1858
  st.subheader("مدیریت کاربران")
1859
 
 
1860
  users_data = {
1861
  'user_id': list(range(1, 6)),
1862
  'username': ['admin', 'user1', 'user2', 'user3', 'user4'],
@@ -1873,6 +2129,7 @@ with tabs[5]:
1873
 
1874
  users_df = pd.DataFrame(users_data)
1875
 
 
1876
  st.write("### لیست کاربران")
1877
 
1878
  st.dataframe(
@@ -1887,6 +2144,7 @@ with tabs[5]:
1887
  hide_index=True
1888
  )
1889
 
 
1890
  st.write("### افزودن کاربر جدید")
1891
 
1892
  col1, col2 = st.columns(2)
@@ -1905,8 +2163,10 @@ with tabs[5]:
1905
  else:
1906
  st.error("لطفاً تمام فیلدها را پر کنید.")
1907
 
 
1908
  st.write("### مدیریت دسترسی‌ها")
1909
 
 
1910
  access_data = {
1911
  'role': ['مدیر', 'کارشناس', 'کاربر'],
1912
  'dashboard': ['خواندن/نوشتن', 'خواندن/نوشتن', 'خواندن'],
@@ -1933,9 +2193,14 @@ with tabs[5]:
1933
  hide_index=True
1934
  )
1935
 
 
1936
  if st.button("ویرایش دسترسی‌ها"):
1937
  st.info("برای ویرایش دسترسی‌ها، لطفاً با مدیر سیستم تماس بگیرید.")
1938
 
 
 
 
 
1939
  st.sidebar.markdown("---")
1940
  st.sidebar.info("نسخه 1.0.0")
1941
  st.sidebar.info("توسعه داده شده با Streamlit")
 
18
  from sklearn.metrics import mean_squared_error
19
  import os
20
  import json
21
+ import requests
22
 
23
  # تنظیمات صفحه
24
  st.set_page_config(
 
112
  </style>
113
  """, unsafe_allow_html=True)
114
 
115
+ # تابع برای دانلود فایل‌های داده
116
+ @st.cache_data
117
+ def download_data_files():
118
+ # دانلود فایل مختصات مزارع
119
+ farm_coordinates_url = "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/farm_coordinates%20%281%29-nEgA8Z2YT3t4IcKbVOOGI1mPp95QeM.csv"
120
+ farm_database_url = "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/%D9%BE%D8%A7%DB%8C%DA%AF%D8%A7%D9%87%20%D8%AF%D8%A7%D8%AF%D9%87%20%281%29-nt53xRXa8kvJKe5wyYpUCNtd0wej9R.csv"
121
+
122
+ try:
123
+ # دانلود فایل‌ها
124
+ farm_coordinates_response = requests.get(farm_coordinates_url)
125
+ farm_database_response = requests.get(farm_database_url)
126
+
127
+ # ذخیره فایل‌ها
128
+ with open('farm_coordinates.csv', 'wb') as f:
129
+ f.write(farm_coordinates_response.content)
130
+
131
+ with open('پایگاه داده (1).csv', 'wb') as f:
132
+ f.write(farm_database_response.content)
133
+
134
+ return True
135
+ except Exception as e:
136
+ st.error(f"خطا در دانلود فایل‌های داده: {e}")
137
+ return False
138
+
139
  # تابع برای اتصال به Google Earth Engine با استفاده از اطلاعات حساب سرویس
140
  @st.cache_resource
141
  def initialize_earth_engine():
 
269
  </div>
270
  """, unsafe_allow_html=True)
271
 
272
+ # تابع برای تبدیل ستون به مقادیر عددی با مدیریت خطا
273
+ def convert_to_numeric(df, column_name):
274
+ try:
275
+ # تلاش برای تبدیل ستون به عدد و جایگزینی خطاها با NaN
276
+ return pd.to_numeric(df[column_name], errors='coerce')
277
+ except Exception as e:
278
+ st.warning(f"خطا در تبدیل ستون {column_name} به عدد: {e}")
279
+ return pd.Series([np.nan] * len(df))
280
+
281
  # تابع برای بارگذاری داده‌های مزارع نیشکر
282
  def load_farm_data():
283
  try:
284
+ # دانلود فایل‌های داده اگر موجود نیستند
285
+ if not os.path.exists('farm_coordinates.csv') or not os.path.exists('پایگاه داده (1).csv'):
286
+ download_data_files()
287
+
288
  # بارگذاری فایل مختصات مزارع
289
  farm_coordinates = pd.read_csv('farm_coordinates.csv')
290
 
291
  # بارگذاری فایل پایگاه داده مزارع
292
  farm_database = pd.read_csv('پایگاه داده (1).csv')
293
 
294
+ # تبدیل ستون‌های عددی به عدد با مدیریت خطا
295
+ if 'سن' in farm_coordinates.columns:
296
+ farm_coordinates['سن'] = convert_to_numeric(farm_coordinates, 'سن')
297
+
298
+ if 'سن' in farm_database.columns:
299
+ farm_database['سن'] = convert_to_numeric(farm_database, 'سن')
300
+
301
+ if 'مساحت' in farm_database.columns:
302
+ farm_database['مساحت'] = convert_to_numeric(farm_database, 'مساحت')
303
+
304
+ if 'مساحت زیرمجموعه' in farm_database.columns:
305
+ farm_database['مساحت زیرمجموعه'] = convert_to_numeric(farm_database, 'مساحت زیرمجموعه')
306
+
307
  # ادغام داده‌ها بر اساس ستون مزرعه
308
  merged_data = pd.merge(farm_database, farm_coordinates, on='مزرعه', how='inner')
309
 
 
 
 
 
 
 
310
  return farm_coordinates, farm_database, merged_data
311
  except Exception as e:
312
  st.error(f"خطا در بارگذاری داده‌ها: {e}")
313
 
314
  # ایجاد داده‌های نمونه در صورت عدم وجود فایل‌ها
315
+ # داده‌های نمونه برای مختصات مزارع
316
  farm_coordinates = pd.DataFrame({
317
  'مزرعه': [f'مزرعه {i}' for i in range(1, 21)],
318
  'سن': np.random.randint(1, 10, 20),
 
321
  'عرض جغرافیایی': np.random.uniform(31.0, 32.0, 20)
322
  })
323
 
324
+ # داده‌های نمونه برای پایگاه داده مزارع
325
  days = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه']
326
  farm_database = pd.DataFrame({
327
  'مزرعه': [f'مزرعه {i}' for i in range(1, 21)],
 
338
  # ادغام داده‌ها
339
  merged_data = pd.merge(farm_database, farm_coordinates, on='مزرعه', how='inner')
340
 
 
 
 
 
 
 
341
  return farm_coordinates, farm_database, merged_data
342
 
343
  # تابع برای ایجاد نقشه مزارع
344
  def create_farm_map(df, selected_farms=None):
345
+ # ایجاد نقشه با مرکزیت میانگین مختصات
346
  center_lat = df['عرض جغرافیایی'].mean()
347
  center_lon = df['طول جغرافیایی'].mean()
348
  m = folium.Map(location=[center_lat, center_lon], zoom_start=10)
349
 
350
+ # اضافه کردن لایه‌های مختلف
351
  folium.TileLayer('openstreetmap').add_to(m)
352
  folium.TileLayer('Stamen Terrain').add_to(m)
353
  folium.TileLayer('Stamen Toner').add_to(m)
354
  folium.TileLayer('Stamen Watercolor').add_to(m)
355
  folium.TileLayer('CartoDB positron').add_to(m)
356
 
357
+ # اضافه کردن کنترل لایه‌ها
358
  folium.LayerControl().add_to(m)
359
 
360
+ # اضافه کردن مارکرها برای هر مزرعه
361
  for idx, row in df.iterrows():
362
  color = 'green'
363
  if selected_farms is not None and row['مزرعه'] in selected_farms:
 
386
 
387
  # تابع برای ایجاد نمودارهای تحلیلی
388
  def create_analysis_charts(df):
389
+ # نمودار توزیع واریته
390
  variety_column = 'واریته' if 'واریته' in df.columns else 'تنوع'
391
  fig_variety = px.pie(
392
  df,
 
400
  title_font_size=20
401
  )
402
 
403
+ # نمودار سن مزارع
404
  age_column = 'سن_x' if 'سن_x' in df.columns else 'سن'
405
  fig_age = px.histogram(
406
  df,
 
416
  title_font_size=20
417
  )
418
 
419
+ # نمودار مساحت مزارع
420
  if 'مساحت' in df.columns:
421
+ # تبدیل ستون‌های عددی به عدد با مدیریت خطا
422
+ area = pd.to_numeric(df['مساحت'], errors='coerce')
423
+ sub_area = pd.to_numeric(df['مساحت زیرمجموعه'], errors='coerce') if 'مساحت زیرمجموعه' in df.columns else area
424
+ age_values = pd.to_numeric(df[age_column], errors='coerce')
425
+
426
+ # ایجاد DataFrame جدید با مقادیر عددی
427
+ plot_df = df.copy()
428
+ plot_df['مساحت'] = area
429
+ plot_df['مساحت زیرمجموعه'] = sub_area
430
+ plot_df[age_column] = age_values
431
+
432
+ # حذف ردیف‌های با مقادیر NaN
433
+ plot_df = plot_df.dropna(subset=['مساحت', 'مساحت زیرمجموعه', age_column])
434
+
435
+ if len(plot_df) > 0:
436
+ fig_area = px.scatter(
437
+ plot_df,
438
+ x='مساحت',
439
+ y='مساحت زیرمجموعه' if 'مساحت زیرمجموعه' in plot_df.columns else 'مساحت',
440
+ color=variety_column,
441
+ size=age_column,
442
+ hover_name='مزرعه',
443
+ title='رابطه بین مساحت و مساحت زیرمجموعه مزارع',
444
+ labels={'مساحت': 'مساحت کل (هکتار)', 'مساحت زیرمجموعه': 'مساحت زیرمجموعه (هکتار)'},
445
+ color_discrete_sequence=px.colors.sequential.Greens
446
+ )
447
+ fig_area.update_layout(
448
+ font_family="Vazirmatn",
449
+ title_font_family="Vazirmatn",
450
+ title_font_size=20
451
+ )
452
+ else:
453
+ fig_area = None
454
  else:
455
  fig_area = None
456
 
 
458
 
459
  # تابع برای ایجاد مدل پیش‌بینی
460
  def create_prediction_model(df):
461
+ # ایجاد داده‌های نمونه برای سری زمانی
462
  dates = pd.date_range(end=datetime.now(), periods=90)
463
  farm_ids = df['مزرعه'].unique()
464
 
 
468
  base_height = np.random.uniform(0.5, 3.0)
469
 
470
  for date in dates:
471
+ # شبیه‌سازی رشد با الگوی سینوسی + روند
472
  day_of_year = date.dayofyear
473
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.2
474
  trend_factor = date.dayofyear / 365 * 0.3
475
 
476
  ndvi = base_ndvi + seasonal_factor + trend_factor + np.random.normal(0, 0.05)
477
+ ndvi = max(0, min(1, ndvi)) # محدود کردن به بازه 0 تا 1
478
 
479
  height = base_height + seasonal_factor * 2 + trend_factor + np.random.normal(0, 0.1)
480
+ height = max(0, height) # ارتفاع نمی‌تواند منفی باشد
481
 
482
  time_series_data.append({
483
  'farm_id': farm_id,
 
490
 
491
  time_df = pd.DataFrame(time_series_data)
492
 
493
+ # ایجاد ویژگی‌ها برای مدل
494
  X = time_df[['ndvi', 'day_of_year', 'month']].values
495
  y = time_df['height'].values
496
 
497
+ # تقسیم داده‌ها به آموزش و آزمون
498
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
499
 
500
+ # آموزش مدل
501
  model = RandomForestRegressor(n_estimators=100, random_state=42)
502
  model.fit(X_train, y_train)
503
 
504
+ # ارزیابی مدل
505
  y_pred = model.predict(X_test)
506
  mse = mean_squared_error(y_test, y_pred)
507
 
508
+ # ایجاد نمودار برای نمایش نتایج
509
  results_df = pd.DataFrame({
510
  'Actual': y_test,
511
  'Predicted': y_pred
 
534
  title_font_size=20
535
  )
536
 
537
+ # ایجاد نمودار سری زمانی
538
+ farm_id = farm_ids[0] # انتخاب اولین مزرعه برای نمایش
539
  farm_data = time_df[time_df['farm_id'] == farm_id]
540
 
541
  fig_ts = px.line(
 
553
  yaxis_title='مقدار'
554
  )
555
 
556
+ return model, fig, fig_ts, time_df, y_test, y_pred
557
+
558
+ # دانلود فایل‌های داده
559
+ download_data_files()
560
 
561
  # بارگذاری داده‌های مزارع نیشکر
562
  farm_coordinates, farm_database, merged_data = load_farm_data()
 
564
  # منوی اصلی
565
  st.title("🌱 سامانه مانیتورینگ مزارع نیشکر")
566
 
567
+ # منوی افقی
568
  tabs = st.tabs([
569
  "📊 داشبورد",
570
  "🗺️ نقشه مزارع",
 
574
  "⚙️ تنظیمات"
575
  ])
576
 
577
+ # تب داشبورد
578
  with tabs[0]:
579
  st.header("داشبورد مدیریت مزارع نیشکر")
580
 
581
+ # کارت‌های اطلاعاتی
582
  col1, col2, col3, col4 = st.columns(4)
583
 
584
  with col1:
 
589
  display_metric_card("تعداد واریته‌ها", unique_varieties, "🌿")
590
 
591
  with col3:
592
+ # محاسبه میانگین سن با مدیریت خطا
593
+ try:
594
+ age_column = 'سن_x' if 'سن_x' in merged_data.columns else 'سن'
595
+ # تبدیل به عدد با مدیریت خطا
596
+ age_values = pd.to_numeric(merged_data[age_column], errors='coerce')
597
+ # محاسبه میانگین با نادیده گرفتن مقادیر NaN
598
+ avg_age = age_values.mean()
599
+ if pd.isna(avg_age):
600
+ display_metric_card("میانگین سن", "نامشخص", "📅")
601
+ else:
602
+ display_metric_card("میانگین سن", f"{avg_age:.1f} سال", "📅")
603
+ except Exception as e:
604
+ st.warning(f"خطا در محاسبه میانگین سن: {e}")
605
+ display_metric_card("میانگین سن", "نامشخص", "📅")
606
 
607
  with col4:
608
  if 'مساحت' in merged_data.columns:
609
+ try:
610
+ # تبدیل به عدد با مدیریت خطا
611
+ area_values = pd.to_numeric(merged_data['مساحت'], errors='coerce')
612
+ # محاسبه مجموع با نادیده گرفتن مقادیر NaN
613
+ total_area = area_values.sum()
614
+ if pd.isna(total_area):
615
+ display_metric_card("مساحت کل", "نامشخص", "📏")
616
+ else:
617
+ display_metric_card("مساحت کل", f"{total_area:.1f} هکتار", "📏")
618
+ except Exception as e:
619
+ st.warning(f"خطا در محاسبه مساحت کل: {e}")
620
+ display_metric_card("مساحت کل", "نامشخص", "📏")
621
  else:
622
  display_metric_card("تعداد کانال‌ها", len(merged_data['کانال'].unique()) if 'کانال' in merged_data.columns else "نامشخص", "🚿")
623
 
624
  st.markdown("---")
625
 
626
+ # نمودارهای تحلیلی
627
  st.subheader("تحلیل کلی مزارع")
628
 
629
  col1, col2 = st.columns(2)
 
637
  if fig_area:
638
  st.plotly_chart(fig_area, use_container_width=True)
639
 
640
+ # جدول اطلاعات مزارع
641
  st.subheader("اطلاعات مزارع")
642
 
643
+ # انتخاب ستون‌های مهم برای نمایش
644
  if 'مساحت' in merged_data.columns:
645
  display_columns = ['مزرعه', 'کانال', 'اداره', 'سن_x', 'واریته', 'مساحت', 'روز']
646
  column_config = {
 
668
  hide_index=True
669
  )
670
 
671
+ # تب نقشه مزارع
672
  with tabs[1]:
673
  st.header("نقشه مزارع نیشکر")
674
 
 
677
  with col1:
678
  st.subheader("فیلتر مزارع")
679
 
680
+ # فیلتر بر اساس روز هفته
681
  days = ['همه روزها', 'شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه']
682
  selected_day = st.selectbox("انتخاب روز هفته", days)
683
 
684
+ # فیلتر بر اساس واریته
685
  variety_column = 'واریته' if 'واریته' in merged_data.columns else 'تنوع'
686
  varieties = ['همه واریته‌ها'] + list(merged_data[variety_column].unique())
687
  selected_variety = st.selectbox("انتخاب واریته", varieties)
688
 
689
+ # فیلتر بر اساس سن
690
  age_column = 'سن_x' if 'سن_x' in merged_data.columns else 'سن'
691
+ age_values = pd.to_numeric(merged_data[age_column], errors='coerce')
692
+ min_age, max_age = int(age_values.min()), int(age_values.max())
693
  age_range = st.slider(
694
  "محدوده سن (سال)",
695
  min_value=min_age,
 
697
  value=(min_age, max_age)
698
  )
699
 
700
+ # اعمال فیلترها
701
  filtered_df = merged_data.copy()
702
 
703
  if selected_day != 'همه روزها' and 'روز' in filtered_df.columns:
 
706
  if selected_variety != 'همه واریته‌ها':
707
  filtered_df = filtered_df[filtered_df[variety_column] == selected_variety]
708
 
709
+ # تبدیل ستون سن به عددی برای فیلتر کردن
710
+ age_values = pd.to_numeric(filtered_df[age_column], errors='coerce')
711
+ filtered_df = filtered_df[(age_values >= age_range[0]) & (age_values <= age_range[1])]
712
 
713
  st.write(f"تعداد مزارع نمایش داده شده: {len(filtered_df)}")
714
 
715
  with col2:
716
+ # نمایش نقشه
717
  if len(filtered_df) > 0:
718
  farm_map = create_farm_map(filtered_df)
719
  folium_static(farm_map, width=800, height=500)
720
  else:
721
  st.warning("هیچ مزرعه‌ای با فیلترهای انتخاب شده یافت نشد.")
722
 
723
+ # تب ورود اطلاعات
724
  with tabs[2]:
725
  st.header("ورود و آپلود اطلاعات")
726
 
 
732
  col1, col2 = st.columns(2)
733
 
734
  with col1:
735
+ # انتخاب مزرعه موجود یا ایجاد مزرعه جدید
736
  option = st.radio("انتخاب گزینه", ["ویرایش مزرعه موجود", "ایجاد مزرعه جدید"])
737
 
738
  if option == "ویرایش مزرعه موجود":
739
  farm_name = st.selectbox("انتخاب مزرعه", merged_data['مزرعه'].tolist())
740
  selected_farm = merged_data[merged_data['مزرعه'] == farm_name].iloc[0]
741
 
742
+ # فیلدهای ورودی بر اساس ستون‌های موجود
743
  if 'کانال' in merged_data.columns:
744
  canal = st.text_input("کانال", value=selected_farm['کانال'])
745
  office = st.text_input("اداره", value=selected_farm['اداره'])
 
750
  day = st.selectbox("روز", options=['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'], index=['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'].index(selected_farm['روز']))
751
 
752
  age_column = 'سن_x' if 'سن_x' in selected_farm else 'سن'
753
+ age = st.text_input("سن", value=selected_farm[age_column])
754
 
755
  lat = st.number_input("عرض جغرافیایی", value=float(selected_farm['عرض جغرافیایی']), format="%.6f")
756
  lon = st.number_input("طول جغرافیایی", value=float(selected_farm['طول جغرافیایی']), format="%.6f")
 
758
  if st.button("بروزرسانی اطلاعات"):
759
  st.success("اطلاعات مزرعه با موفقیت بروزرسانی شد.")
760
  else:
761
+ # ایجاد مزرعه جدید
762
  farm_name = st.text_input("نام مزرعه", value=f"مزرعه جدید")
763
 
764
+ # فیلدهای ورودی بر اساس ستون‌های موجود
765
  if 'کانال' in merged_data.columns:
766
  canal = st.text_input("کانال")
767
  office = st.text_input("اداره")
 
771
  group = st.text_input("گروه")
772
  day = st.selectbox("روز", options=['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'])
773
 
774
+ age = st.text_input("سن", value="R1")
775
  lat = st.number_input("عرض جغرافیایی", value=31.5, format="%.6f")
776
  lon = st.number_input("طول جغرافیایی", value=48.5, format="%.6f")
777
 
 
779
  st.success("مزرعه جدید با موفقیت ثبت شد.")
780
 
781
  with col2:
782
+ # نمایش نقشه برای انتخاب موقعیت
783
  st.subheader("انتخاب موقعیت روی نقشه")
784
  st.write("برای انتخاب موقعیت دقیق، روی نقشه کلیک کنید.")
785
 
786
+ # نمایش نقشه
787
  center_lat = merged_data['عرض جغرافیایی'].mean()
788
  center_lon = merged_data['طول جغرافیایی'].mean()
789
  m = folium.Map(location=[center_lat, center_lon], zoom_start=10)
 
842
  except Exception as e:
843
  st.error(f"خطا در خواندن فایل: {e}")
844
 
845
+ # تب تحلیل داده‌ها
846
  with tabs[3]:
847
  st.header("تحلیل داده‌ها")
848
 
 
851
  with analysis_tabs[0]:
852
  st.subheader("محاسبه و نمایش شاخص‌های گیاهی")
853
 
854
+ # اتصال به Google Earth Engine
855
  ee_connected = initialize_earth_engine()
856
 
857
  if ee_connected:
858
+ # انتخاب مزرعه
859
  farm_name = st.selectbox("انتخاب مزرعه برای تحلیل", merged_data['مزرعه'].tolist(), key="farm_select_indices")
860
  selected_farm = merged_data[merged_data['مزرعه'] == farm_name].iloc[0]
861
 
862
+ # انتخاب تاریخ
863
  date = st.date_input("انتخاب تاریخ", value=datetime.now() - timedelta(days=7))
864
 
865
  if st.button("محاسبه شاخص‌ها"):
866
  with st.spinner("در حال محاسبه شاخص‌ها..."):
867
+ # ایجاد geometry برای مزرعه
868
  point = ee.Geometry.Point([selected_farm['طول جغرافیایی'], selected_farm['عرض جغرافیایی']])
869
+ buffer = point.buffer(100) # بافر 100 متری
870
 
871
+ # محاسبه شاخص‌ها
872
  indices = calculate_indices(date.strftime('%Y-%m-%d'), buffer)
873
 
874
  if indices is not None:
875
+ # نمایش نتایج
876
  st.success("شاخص‌ها با موفقیت محاسبه شدند.")
877
 
878
+ # ایجاد نقشه برای نمایش شاخص‌ها
879
  Map = geemap.Map()
880
  Map.centerObject(buffer, 14)
881
 
882
+ # اضافه کردن لایه‌های مختلف
883
  vis_params = {
884
  'min': 0,
885
  'max': 1,
 
893
  Map.addLayer(indices.select('LAI'), {'min': 0, 'max': 5, 'palette': ['red', 'yellow', 'green']}, 'LAI')
894
  Map.addLayer(indices.select('CHL'), {'min': 0, 'max': 3, 'palette': ['red', 'yellow', 'green']}, 'CHL')
895
 
896
+ # اضافه کردن کنترل لایه‌ها
897
  Map.addLayerControl()
898
 
899
+ # نمایش نقشه
900
  Map.to_streamlit(height=500)
901
 
902
+ # نمایش مقادیر میانگین
903
  col1, col2, col3 = st.columns(3)
904
 
905
  with col1:
 
919
  with analysis_tabs[1]:
920
  st.subheader("تحلیل سری زمانی")
921
 
922
+ # ایجاد مدل و نمودارها
923
+ model, fig_model, fig_ts, time_df, y_test, y_pred = create_prediction_model(merged_data)
924
 
925
+ # انتخاب مزرعه
926
  farm_name = st.selectbox("انتخاب مزرعه برای تحلیل", merged_data['مزرعه'].tolist(), key="farm_select_ts")
927
 
928
+ # فیلتر داده‌ها برای مزرعه انتخاب شده
929
  farm_time_data = time_df[time_df['farm_id'] == farm_name]
930
 
931
+ # نمایش نمودار سری زمانی
932
  fig_farm_ts = px.line(
933
  farm_time_data,
934
  x='date',
 
946
 
947
  st.plotly_chart(fig_farm_ts, use_container_width=True)
948
 
949
+ # تحلیل روند
950
  st.subheader("تحلیل روند")
951
 
952
  col1, col2 = st.columns(2)
953
 
954
  with col1:
955
+ # محاسبه میانگین متحرک
956
  window_size = st.slider("اندازه پنجره میانگین متحرک", min_value=3, max_value=30, value=7)
957
 
958
  farm_time_data['ndvi_ma'] = farm_time_data['ndvi'].rolling(window=window_size).mean()
959
  farm_time_data['height_ma'] = farm_time_data['height'].rolling(window=window_size).mean()
960
 
961
+ # نمایش نمودار میانگین متحرک
962
  fig_ma = px.line(
963
  farm_time_data.dropna(),
964
  x='date',
 
977
  st.plotly_chart(fig_ma, use_container_width=True)
978
 
979
  with col2:
980
+ # تحلیل فصلی
981
  monthly_data = farm_time_data.groupby('month').agg({
982
  'ndvi': 'mean',
983
  'height': 'mean'
 
1004
  with analysis_tabs[2]:
1005
  st.subheader("تشخیص تنش‌ها")
1006
 
1007
+ # انتخاب مزرعه
1008
  farm_name = st.selectbox("انتخاب مزرعه برای تحلیل", merged_data['مزرعه'].tolist(), key="farm_select_stress")
1009
 
1010
+ # ایجاد داده‌های نمونه برای تنش‌ها
1011
  dates = pd.date_range(end=datetime.now(), periods=90)
1012
  stress_data = []
1013
 
1014
+ # شبیه‌سازی تنش آبی
1015
  water_stress_threshold = 0.3
1016
  base_ndwi = np.random.uniform(0.2, 0.5)
1017
 
1018
+ # شبیه‌سازی تنش بیماری
1019
  disease_threshold = 0.4
1020
  base_chl = np.random.uniform(1.5, 2.5)
1021
 
 
1023
  day_of_year = date.dayofyear
1024
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.2
1025
 
1026
+ # شبیه‌سازی تنش آبی در روزهای خاص
1027
  water_stress_event = False
1028
  if 30 <= day_of_year <= 40 or 70 <= day_of_year <= 75:
1029
  water_stress_event = True
 
1031
  else:
1032
  ndwi = base_ndwi + seasonal_factor + np.random.normal(0, 0.05)
1033
 
1034
+ # شبیه‌سازی تنش بیماری در روزهای خاص
1035
  disease_event = False
1036
  if 50 <= day_of_year <= 60:
1037
  disease_event = True
 
1039
  else:
1040
  chl = base_chl + seasonal_factor + np.random.normal(0, 0.1)
1041
 
1042
+ # محدود کردن مقادیر
1043
  ndwi = max(-0.5, min(0.8, ndwi))
1044
  chl = max(0.5, min(3.0, chl))
1045
 
 
1050
  'water_stress': 1 if ndwi < water_stress_threshold else 0,
1051
  'disease_stress': 1 if chl < disease_threshold else 0,
1052
  'water_stress_event': water_stress_event,
1053
+ 'disease_stress_event': disease_stress_event
1054
  })
1055
 
1056
  stress_df = pd.DataFrame(stress_data)
1057
 
1058
+ # نمایش نمودار تنش‌ها
1059
  fig_stress = go.Figure()
1060
 
1061
+ # اضافه کردن NDWI
1062
  fig_stress.add_trace(go.Scatter(
1063
  x=stress_df['date'],
1064
  y=stress_df['ndwi'],
 
1066
  line=dict(color='blue')
1067
  ))
1068
 
1069
+ # اضافه کردن CHL
1070
  fig_stress.add_trace(go.Scatter(
1071
  x=stress_df['date'],
1072
  y=stress_df['chl'],
 
1075
  yaxis='y2'
1076
  ))
1077
 
1078
+ # اضافه کردن خط آستانه تنش آبی
1079
  fig_stress.add_shape(
1080
  type='line',
1081
  x0=stress_df['date'].min(),
 
1086
  name='آستانه تنش آبی'
1087
  )
1088
 
1089
+ # اضافه کردن خط آستانه تنش بیماری
1090
  fig_stress.add_shape(
1091
  type='line',
1092
  x0=stress_df['date'].min(),
 
1098
  name='آستانه تنش بیماری'
1099
  )
1100
 
1101
+ # تنظیمات نمودار
1102
  fig_stress.update_layout(
1103
  title='تشخیص تنش‌های آبی و بیماری',
1104
  font_family="Vazirmatn",
 
1129
 
1130
  st.plotly_chart(fig_stress, use_container_width=True)
1131
 
1132
+ # نمایش هشدارها
1133
  st.subheader("هشدارهای تنش")
1134
 
1135
  col1, col2 = st.columns(2)
1136
 
1137
  with col1:
1138
+ # هشدارهای تنش آبی
1139
  water_stress_days = stress_df[stress_df['water_stress'] == 1]
1140
 
1141
  if len(water_stress_days) > 0:
 
1153
  st.success("هیچ تنش آبی تشخیص داده نشده است.")
1154
 
1155
  with col2:
1156
+ # هشدارهای تنش بیماری
1157
  disease_stress_days = stress_df[stress_df['disease_stress'] == 1]
1158
 
1159
  if len(disease_stress_days) > 0:
 
1173
  with analysis_tabs[3]:
1174
  st.subheader("پیش‌بینی رشد")
1175
 
1176
+ # انتخاب مزرعه
1177
  farm_name = st.selectbox("انتخاب مزرعه برای پیش‌بینی", merged_data['مزرعه'].tolist(), key="farm_select_predict")
1178
 
1179
+ # فیلتر داده‌ها برای مزرعه انتخاب شده
1180
  farm_time_data = time_df[time_df['farm_id'] == farm_name]
1181
 
1182
+ # تنظیمات پیش‌بینی
1183
  st.subheader("تنظیمات پیش‌بینی")
1184
 
1185
  col1, col2 = st.columns(2)
 
1192
 
1193
  if st.button("انجام پیش‌بینی"):
1194
  with st.spinner("در حال انجام پیش‌بینی..."):
1195
+ # ایجاد داده‌های آینده برای پیش‌بینی
1196
  last_date = farm_time_data['date'].max()
1197
  future_dates = pd.date_range(start=last_date + timedelta(days=1), periods=days_to_predict)
1198
 
 
1206
 
1207
  future_df = pd.DataFrame(future_data)
1208
 
1209
+ # پیش‌بینی NDVI برای روزهای آینده (با الگوی سینوسی + روند)
1210
  base_ndvi = farm_time_data['ndvi'].iloc[-1]
1211
  future_ndvi = []
1212
 
 
1214
  seasonal_factor = np.sin(day / 365 * 2 * np.pi) * 0.2
1215
  trend_factor = day / 365 * 0.1
1216
  ndvi = base_ndvi + seasonal_factor + trend_factor
1217
+ ndvi = max(0, min(1, ndvi)) # محدود کردن به بازه 0 تا 1
1218
  future_ndvi.append(ndvi)
1219
 
1220
  future_df['ndvi'] = future_ndvi
1221
 
1222
+ # پیش‌بینی ارتفاع با استفاده از مدل
1223
  X_future = future_df[['ndvi', 'day_of_year', 'month']].values
1224
  future_df['height'] = model.predict(X_future)
1225
 
1226
+ # محاسبه فاصله اطمینان
1227
+ z_score = {
1228
+ 90: 1.645,
1229
+ 95: 1.96,
1230
+ 99: 2.576
1231
+ }.get(confidence_interval, 1.96)
1232
+
1233
  mse = mean_squared_error(y_test, y_pred)
1234
  std_dev = np.sqrt(mse)
1235
 
1236
  future_df['height_lower'] = future_df['height'] - z_score * std_dev
1237
  future_df['height_upper'] = future_df['height'] + z_score * std_dev
1238
 
1239
+ # ترکیب داده‌های گذشته و آینده
1240
  combined_df = pd.concat([
1241
  farm_time_data[['date', 'ndvi', 'height']],
1242
  future_df[['date', 'ndvi', 'height', 'height_lower', 'height_upper']]
1243
  ])
1244
 
1245
+ # نمایش نمودار پیش‌بینی
1246
  fig_predict = go.Figure()
1247
 
1248
+ # داده‌های گذشته
1249
  past_data = combined_df[combined_df['date'] <= last_date]
1250
 
1251
  fig_predict.add_trace(go.Scatter(
 
1255
  line=dict(color='blue')
1256
  ))
1257
 
1258
+ # داده‌های پیش‌بینی شده
1259
  future_data = combined_df[combined_df['date'] > last_date]
1260
 
1261
  fig_predict.add_trace(go.Scatter(
 
1265
  line=dict(color='red')
1266
  ))
1267
 
1268
+ # فاصله اطمینان
1269
  fig_predict.add_trace(go.Scatter(
1270
  x=future_data['date'],
1271
  y=future_data['height_upper'],
 
1284
  showlegend=True
1285
  ))
1286
 
1287
+ # تنظیمات نمودار
1288
  fig_predict.update_layout(
1289
  title=f'پیش‌بینی ارتفاع برای {days_to_predict} روز آینده',
1290
  font_family="Vazirmatn",
 
1303
 
1304
  st.plotly_chart(fig_predict, use_container_width=True)
1305
 
1306
+ # نمایش جدول پیش‌بینی
1307
  st.subheader("جدول پیش‌بینی")
1308
 
1309
  st.dataframe(
 
1318
  hide_index=True
1319
  )
1320
 
1321
+ # نمایش خلاصه پیش‌بینی
1322
  st.subheader("خلاصه پیش‌بینی")
1323
 
1324
  col1, col2, col3 = st.columns(3)
 
1346
  f"{final_height:.2f} متر"
1347
  )
1348
 
1349
+ # تب گزارش‌گیری
1350
  with tabs[4]:
1351
  st.header("گزارش‌گیری")
1352
 
1353
+ # انتخاب نوع گزارش
1354
  report_type = st.selectbox(
1355
  "انتخاب نوع گزارش",
1356
  ["گزارش وضعیت کلی مزارع", "گزارش تحلیل شاخص‌ها", "گزارش تنش‌ها", "گزارش پیش‌بینی رشد"]
1357
  )
1358
 
1359
+ # انتخاب بازه زمانی
1360
  col1, col2 = st.columns(2)
1361
 
1362
  with col1:
 
1365
  with col2:
1366
  end_date = st.date_input("تاریخ پایان", value=datetime.now())
1367
 
1368
+ # انتخاب مزارع
1369
  selected_farms = st.multiselect(
1370
  "انتخاب مزارع",
1371
  options=merged_data['مزرعه'].tolist()
1372
  )
1373
 
1374
  if not selected_farms:
1375
+ selected_farms = merged_data['مزرعه'].tolist() # اگر هیچ مزرعه‌ای انتخاب نشده باشد، همه مزارع انتخاب می‌شوند
1376
 
1377
+ # فیلتر داده‌ها بر اساس مزارع انتخاب شده
1378
  filtered_farm_df = merged_data[merged_data['مزرعه'].isin(selected_farms)]
1379
 
1380
  if st.button("تولید گزارش"):
 
1382
  if report_type == "گزارش وضعیت کلی مزارع":
1383
  st.subheader("گزارش وضعیت کلی مزارع")
1384
 
1385
+ # نمودارهای تحلیلی
1386
  fig_variety, fig_age, fig_area = create_analysis_charts(filtered_farm_df)
1387
 
1388
  col1, col2 = st.columns(2)
 
1396
  if fig_area:
1397
  st.plotly_chart(fig_area, use_container_width=True)
1398
 
1399
+ # جدول اطلاعات مزارع
1400
  st.subheader("اطلاعات مزارع")
1401
 
1402
+ # انتخاب ستون‌های مهم برای نمایش
1403
  if 'مساحت' in filtered_farm_df.columns:
1404
  display_columns = ['مزرعه', 'کانال', 'اداره', 'سن_x', 'واریته', 'مساحت', 'روز']
1405
  column_config = {
 
1427
  hide_index=True
1428
  )
1429
 
1430
+ # آمار خلاصه
1431
  st.subheader("آمار خلاصه")
1432
 
1433
  col1, col2, col3, col4 = st.columns(4)
 
1437
 
1438
  with col2:
1439
  if 'مساحت' in filtered_farm_df.columns:
1440
+ area_values = pd.to_numeric(filtered_farm_df['مساحت'], errors='coerce')
1441
+ st.metric("میانگین مساحت", f"{area_values.mean():.2f} هکتار")
1442
  else:
1443
  st.metric("تعداد واریته‌ها", len(filtered_farm_df['تنوع'].unique()))
1444
 
1445
  with col3:
1446
  age_column = 'سن_x' if 'سن_x' in filtered_farm_df.columns else 'سن'
1447
+ age_values = pd.to_numeric(filtered_farm_df[age_column], errors='coerce')
1448
+ st.metric("میانگین سن", f"{age_values.mean():.1f} سال")
1449
 
1450
  with col4:
1451
  if 'روز' in filtered_farm_df.columns:
 
1453
  else:
1454
  st.metric("تعداد مزارع", len(filtered_farm_df))
1455
 
1456
+ # نقشه مزارع
1457
  st.subheader("نقشه مزارع")
1458
  farm_map = create_farm_map(filtered_farm_df)
1459
  folium_static(farm_map, width=800, height=500)
1460
 
1461
+ # دانلود گزارش
1462
  st.subheader("دانلود گزارش")
1463
 
1464
+ # ایجاد فایل PDF
1465
  figs = [fig_variety, fig_age]
1466
  if fig_area:
1467
  figs.append(fig_area)
 
1470
 
1471
  pdf_buffer = create_report_pdf(figs, tables, "گزارش وضعیت کلی مزارع")
1472
 
1473
+ # دانلود PDF
1474
  st.download_button(
1475
  label="دانلود گزارش (PDF)",
1476
  data=pdf_buffer,
 
1478
  mime="application/pdf"
1479
  )
1480
 
1481
+ # دانلود Excel
1482
  excel_buffer = io.BytesIO()
1483
  filtered_farm_df.to_excel(excel_buffer, index=False)
1484
  excel_buffer.seek(0)
 
1493
  elif report_type == "گزارش تحلیل شاخص‌ها":
1494
  st.subheader("گزارش تحلیل شاخص‌ها")
1495
 
1496
+ # ایجاد داده‌های نمونه برای شاخص‌ها
1497
  indices_data = []
1498
 
1499
  for farm_name in selected_farms:
1500
+ # مقادیر پایه برای هر مزرعه
1501
  base_ndvi = np.random.uniform(0.3, 0.8)
1502
  base_ndwi = np.random.uniform(0.1, 0.5)
1503
  base_evi = np.random.uniform(0.3, 0.7)
 
1505
  base_lai = np.random.uniform(1.0, 4.0)
1506
  base_chl = np.random.uniform(1.0, 3.0)
1507
 
1508
+ # ایجاد داده‌ها برای بازه زمانی انتخاب شده
1509
  date_range = pd.date_range(start=start_date, end=end_date)
1510
 
1511
  for date in date_range:
1512
+ # شبیه‌سازی تغییرات با الگوی سینوسی
1513
  day_of_year = date.dayofyear
1514
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.1
1515
 
 
1520
  lai = base_lai + seasonal_factor * 2 + np.random.normal(0, 0.2)
1521
  chl = base_chl + seasonal_factor + np.random.normal(0, 0.1)
1522
 
1523
+ # محدود کردن مقادیر
1524
  ndvi = max(0, min(1, ndvi))
1525
  ndwi = max(-0.5, min(0.8, ndwi))
1526
  evi = max(0, min(1, evi))
 
1541
 
1542
  indices_df = pd.DataFrame(indices_data)
1543
 
1544
+ # نمایش میانگین شاخص‌ها برای هر مزرعه
1545
  avg_indices = indices_df.groupby('farm_name').agg({
1546
  'ndvi': 'mean',
1547
  'ndwi': 'mean',
 
1566
  hide_index=True
1567
  )
1568
 
1569
+ # نمودار مقایسه‌ای شاخص‌ها
1570
  st.subheader("مقایسه شاخص‌ها بین مزارع")
1571
 
1572
+ # انتخاب شاخص برای نمایش
1573
  selected_index = st.selectbox(
1574
  "انتخاب شاخص",
1575
  ["NDVI", "NDWI", "EVI", "NDMI", "LAI", "CHL"]
 
1584
  "CHL": "chl"
1585
  }
1586
 
1587
+ # نمودار مقایسه‌ای
1588
  fig_compare = px.bar(
1589
  avg_indices,
1590
  x='farm_name',
 
1603
 
1604
  st.plotly_chart(fig_compare, use_container_width=True)
1605
 
1606
+ # نمودار سری زمانی
1607
  st.subheader("سری زمانی شاخص‌ها")
1608
 
1609
+ # انتخاب مزرعه برای نمایش سری زمانی
1610
  selected_farm_name = st.selectbox(
1611
  "انتخاب مزرعه",
1612
  options=selected_farms
1613
  )
1614
 
1615
+ # فیلتر داده‌ها برای مزرعه انتخاب شده
1616
  farm_indices = indices_df[indices_df['farm_name'] == selected_farm_name]
1617
 
1618
+ # نمودار سری زمانی
1619
  fig_ts = px.line(
1620
  farm_indices,
1621
  x='date',
 
1633
 
1634
  st.plotly_chart(fig_ts, use_container_width=True)
1635
 
1636
+ # دانلود گزارش
1637
  st.subheader("دانلود گزارش")
1638
 
1639
+ # ایجاد فایل PDF
1640
  figs = [fig_compare, fig_ts]
1641
  tables = [avg_indices]
1642
 
1643
  pdf_buffer = create_report_pdf(figs, tables, "گزارش تحلیل شاخص‌ها")
1644
 
1645
+ # دانلود PDF
1646
  st.download_button(
1647
  label="دانلود گزارش (PDF)",
1648
  data=pdf_buffer,
 
1650
  mime="application/pdf"
1651
  )
1652
 
1653
+ # دانلود Excel
1654
  excel_buffer = io.BytesIO()
1655
  indices_df.to_excel(excel_buffer, index=False)
1656
  excel_buffer.seek(0)
 
1665
  elif report_type == "گزارش تنش‌ها":
1666
  st.subheader("گزارش تنش‌ها")
1667
 
1668
+ # ایجاد داده‌های نمونه برای تنش‌ها
1669
  stress_data = []
1670
 
1671
  for farm_name in selected_farms:
1672
+ # مقادیر پایه برای هر مزرعه
1673
  base_ndwi = np.random.uniform(0.2, 0.5)
1674
  base_chl = np.random.uniform(1.5, 2.5)
1675
 
1676
+ # آستانه‌های تنش
1677
  water_stress_threshold = 0.3
1678
  disease_threshold = 0.4
1679
 
1680
+ # ایجاد داده‌ها برای بازه زمانی انتخاب شده
1681
  date_range = pd.date_range(start=start_date, end=end_date)
1682
 
1683
  for date in date_range:
1684
  day_of_year = date.dayofyear
1685
  seasonal_factor = np.sin(day_of_year / 365 * 2 * np.pi) * 0.2
1686
 
1687
+ # شبیه‌سازی تنش آبی در روزهای خاص
1688
  water_stress_event = False
1689
+ if (day_of_year % 30) < 5: # هر 30 روز، 5 روز تنش آبی
1690
  water_stress_event = True
1691
  ndwi = base_ndwi - 0.3 + np.random.normal(0, 0.05)
1692
  else:
1693
  ndwi = base_ndwi + seasonal_factor + np.random.normal(0, 0.05)
1694
 
1695
+ # شبیه‌سازی تنش بیماری در روزهای خاص
1696
  disease_event = False
1697
+ if (day_of_year % 45) < 7: # هر 45 روز، 7 روز تنش بیماری
1698
  disease_event = True
1699
  chl = base_chl - 0.5 + np.random.normal(0, 0.1)
1700
  else:
1701
  chl = base_chl + seasonal_factor + np.random.normal(0, 0.1)
1702
 
1703
+ # محدود کردن مقادیر
1704
  ndwi = max(-0.5, min(0.8, ndwi))
1705
  chl = max(0.5, min(3.0, chl))
1706
 
 
1712
  'water_stress': 1 if ndwi < water_stress_threshold else 0,
1713
  'disease_stress': 1 if chl < disease_threshold else 0,
1714
  'water_stress_event': water_stress_event,
1715
+ 'disease_stress_event': disease_stress_event
1716
  })
1717
 
1718
  stress_df = pd.DataFrame(stress_data)
1719
 
1720
+ # آمار تنش‌ها
1721
  stress_stats = stress_df.groupby('farm_name').agg({
1722
  'water_stress': 'sum',
1723
  'disease_stress': 'sum'
 
1731
  st.subheader("آمار تنش‌ها برای هر مزرعه")
1732
  st.dataframe(stress_stats, hide_index=True)
1733
 
1734
+ # نمودار مقایسه‌ای تنش‌ها
1735
  fig_stress_compare = px.bar(
1736
  stress_stats,
1737
  x='farm_name',
 
1749
 
1750
  st.plotly_chart(fig_stress_compare, use_container_width=True)
1751
 
1752
+ # نمودار سری زمانی تنش‌ها
1753
  st.subheader("سری زمانی تنش‌ها")
1754
 
1755
+ # انتخاب مزرعه برای نمایش سری زمانی
1756
  selected_farm_name = st.selectbox(
1757
  "انتخاب مزرعه",
1758
  options=selected_farms,
1759
  key="farm_select_stress_report"
1760
  )
1761
 
1762
+ # فیلتر داده‌ها برای مزرعه انتخاب شده
1763
  farm_stress = stress_df[stress_df['farm_name'] == selected_farm_name]
1764
 
1765
+ # نمودار سری زمانی
1766
  fig_stress_ts = go.Figure()
1767
 
1768
+ # اضافه کردن NDWI
1769
  fig_stress_ts.add_trace(go.Scatter(
1770
  x=farm_stress['date'],
1771
  y=farm_stress['ndwi'],
 
1773
  line=dict(color='blue')
1774
  ))
1775
 
1776
+ # اضافه کردن CHL
1777
  fig_stress_ts.add_trace(go.Scatter(
1778
  x=farm_stress['date'],
1779
  y=farm_stress['chl'],
 
1782
  yaxis='y2'
1783
  ))
1784
 
1785
+ # اضافه کردن خط آستانه تنش آبی
1786
  fig_stress_ts.add_shape(
1787
  type='line',
1788
  x0=farm_stress['date'].min(),
1789
+ y0=0.3, # water_stress_threshold
1790
  x1=farm_stress['date'].max(),
1791
  y1=0.3,
1792
  line=dict(color='red', dash='dash')
1793
  )
1794
 
1795
+ # اضافه کردن خط آستانه تنش بیماری
1796
  fig_stress_ts.add_shape(
1797
  type='line',
1798
  x0=farm_stress['date'].min(),
1799
+ y0=0.4, # disease_threshold
1800
  x1=farm_stress['date'].max(),
1801
  y1=0.4,
1802
  line=dict(color='orange', dash='dash'),
1803
  yaxis='y2'
1804
  )
1805
 
1806
+ # تنظیمات نمودار
1807
  fig_stress_ts.update_layout(
1808
  title=f'سری زمانی تنش‌ها برای {selected_farm_name}',
1809
  font_family="Vazirmatn",
 
1834
 
1835
  st.plotly_chart(fig_stress_ts, use_container_width=True)
1836
 
1837
+ # جدول روزهای تنش
1838
  st.subheader("روزهای تنش")
1839
 
1840
+ # فیلتر روزهای تنش
1841
  stress_days = farm_stress[(farm_stress['water_stress'] == 1) | (farm_stress['disease_stress'] == 1)]
1842
  stress_days = stress_days[['date', 'ndwi', 'chl', 'water_stress', 'disease_stress']]
1843
 
 
1856
  else:
1857
  st.info("هیچ روز تنشی برای این مزرعه در بازه زمانی انتخاب شده یافت نشد.")
1858
 
1859
+ # دانلود گزارش
1860
  st.subheader("دانلود گزارش")
1861
 
1862
+ # ایجاد فایل PDF
1863
  figs = [fig_stress_compare, fig_stress_ts]
1864
  tables = [stress_stats, stress_days]
1865
 
1866
  pdf_buffer = create_report_pdf(figs, tables, "گزارش تنش‌ها")
1867
 
1868
+ # دانلود PDF
1869
  st.download_button(
1870
  label="دانلود گزارش (PDF)",
1871
  data=pdf_buffer,
 
1873
  mime="application/pdf"
1874
  )
1875
 
1876
+ # دانلود Excel
1877
  excel_buffer = io.BytesIO()
1878
  stress_df.to_excel(excel_buffer, index=False)
1879
  excel_buffer.seek(0)
 
1888
  elif report_type == "گزارش پیش‌بینی رشد":
1889
  st.subheader("گزارش پیش‌بینی رشد")
1890
 
1891
+ # ایجاد مدل و داده‌های پیش‌بینی
1892
+ model, fig_model, fig_ts, time_df, y_test, y_pred = create_prediction_model(merged_data)
1893
 
1894
+ # فیلتر داده‌ها برای مزارع انتخاب شده
1895
  filtered_time_df = time_df[time_df['farm_id'].isin(selected_farms)]
1896
 
1897
+ # آمار رشد
1898
  growth_stats = filtered_time_df.groupby('farm_id').agg({
1899
  'height': ['first', 'last', lambda x: x.iloc[-1] - x.iloc[0]]
1900
  })
 
1914
  hide_index=True
1915
  )
1916
 
1917
+ # نمودار مقایسه‌ای ر��د
1918
  fig_growth = px.bar(
1919
  growth_stats,
1920
  x='farm_id',
 
1933
 
1934
  st.plotly_chart(fig_growth, use_container_width=True)
1935
 
1936
+ # نمودار سری زمانی رشد
1937
  st.subheader("سری زمانی رشد")
1938
 
1939
+ # انتخاب مزرعه برای نمایش سری زمانی
1940
  selected_farm_name = st.selectbox(
1941
  "انتخاب مزرعه",
1942
  options=selected_farms,
1943
  key="farm_select_growth_report"
1944
  )
1945
 
1946
+ # فیلتر داده‌ها برای مزرعه انتخاب شده
1947
  farm_growth = filtered_time_df[filtered_time_df['farm_id'] == selected_farm_name]
1948
 
1949
+ # نمودار سری زمانی
1950
  fig_growth_ts = px.line(
1951
  farm_growth,
1952
  x='date',
 
1963
 
1964
  st.plotly_chart(fig_growth_ts, use_container_width=True)
1965
 
1966
+ # دانلود گزارش
1967
  st.subheader("دانلود گزارش")
1968
 
1969
+ # ایجاد فایل PDF
1970
  figs = [fig_growth, fig_growth_ts]
1971
  tables = [growth_stats]
1972
 
1973
  pdf_buffer = create_report_pdf(figs, tables, "گزارش پیش‌بینی رشد")
1974
 
1975
+ # دانلود PDF
1976
  st.download_button(
1977
  label="دانلود گزارش (PDF)",
1978
  data=pdf_buffer,
 
1980
  mime="application/pdf"
1981
  )
1982
 
1983
+ # دانلود Excel
1984
  excel_buffer = io.BytesIO()
1985
  filtered_time_df.to_excel(excel_buffer, index=False)
1986
  excel_buffer.seek(0)
 
1992
  mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1993
  )
1994
 
1995
+ # تب تنظیمات
1996
  with tabs[5]:
1997
  st.header("تنظیمات")
1998
 
 
2001
  with settings_tabs[0]:
2002
  st.subheader("تنظیمات عمومی")
2003
 
2004
+ # تنظیمات ظاهری
2005
  st.write("### تنظیمات ظاهری")
2006
 
2007
  col1, col2 = st.columns(2)
 
2028
  ["Viridis (پیش‌فرض)", "Plasma", "Inferno", "Magma", "Cividis"]
2029
  )
2030
 
2031
+ # تنظیمات زبان
2032
  st.write("### تنظیمات زبان")
2033
 
2034
  language = st.radio(
 
2036
  ["فارسی (پیش‌فرض)", "انگلیسی"]
2037
  )
2038
 
2039
+ # تنظیمات واحدها
2040
  st.write("### تنظیمات واحدها")
2041
 
2042
  col1, col2 = st.columns(2)
 
2063
  ["1,234.56 (پیش‌فرض)", "1.234,56"]
2064
  )
2065
 
2066
+ # دکمه ذخیره تنظیمات
2067
  if st.button("ذخیره تنظیمات"):
2068
  st.success("تنظیمات با موفقیت ذخیره شد.")
2069
 
2070
  with settings_tabs[1]:
2071
  st.subheader("اتصال به Google Earth Engine")
2072
 
2073
+ # توضیحات
2074
  st.write("""
2075
  برای اتصال به Google Earth Engine، از حساب سرویس زیر استفاده می‌شود:
2076
 
 
2078
  - پروژه: `ee-esmaeilkiani13877`
2079
  """)
2080
 
2081
+ # نمایش وضعیت اتصال
2082
  ee_connected = initialize_earth_engine()
2083
 
2084
  if ee_connected:
2085
  st.success("اتصال به Google Earth Engine برقرار است.")
2086
 
2087
+ # دکمه تست اتصال
2088
  if st.button("تست اتصال"):
2089
  with st.spinner("در حال تست اتصال..."):
2090
+ # شبیه‌سازی تست اتصال
2091
  import time
2092
  time.sleep(2)
2093
  st.success("اتصال با موفقیت برقرار شد.")
2094
  else:
2095
  st.error("اتصال به Google Earth Engine برقرار نشد. لطفاً تنظیمات را بررسی کنید.")
2096
 
2097
+ # تنظیمات پیشرفته
2098
  st.write("### تنظیمات پیشرفته")
2099
 
2100
  col1, col2 = st.columns(2)
 
2112
  with settings_tabs[2]:
2113
  st.subheader("مدیریت کاربران")
2114
 
2115
+ # ایجاد داده‌های نمونه برای کاربران
2116
  users_data = {
2117
  'user_id': list(range(1, 6)),
2118
  'username': ['admin', 'user1', 'user2', 'user3', 'user4'],
 
2129
 
2130
  users_df = pd.DataFrame(users_data)
2131
 
2132
+ # نمایش لیست کاربران
2133
  st.write("### لیست کاربران")
2134
 
2135
  st.dataframe(
 
2144
  hide_index=True
2145
  )
2146
 
2147
+ # افزودن کاربر جدید
2148
  st.write("### افزودن کاربر جدید")
2149
 
2150
  col1, col2 = st.columns(2)
 
2163
  else:
2164
  st.error("لطفاً تمام فیلدها را پر کنید.")
2165
 
2166
+ # ویرایش دسترسی‌ها
2167
  st.write("### مدیریت دسترسی‌ها")
2168
 
2169
+ # جدول دسترسی‌ها
2170
  access_data = {
2171
  'role': ['مدیر', 'کارشناس', 'کاربر'],
2172
  'dashboard': ['خواندن/نوشتن', 'خواندن/نوشتن', 'خواندن'],
 
2193
  hide_index=True
2194
  )
2195
 
2196
+ # دکمه ویرایش دسترسی‌ها
2197
  if st.button("ویرایش دسترسی‌ها"):
2198
  st.info("برای ویرایش دسترسی‌ها، لطفاً با مدیر سیستم تماس بگیرید.")
2199
 
2200
+ # نمایش اطلاعات نسخه
2201
+ st.sidebar.markdown("---")
2202
+ st.sidebar.info("نسخه 1.0.0")
2203
+ st.sidebar.info("توسعه داده شده با Streamlit")
2204
  st.sidebar.markdown("---")
2205
  st.sidebar.info("نسخه 1.0.0")
2206
  st.sidebar.info("توسعه داده شده با Streamlit")