Esmaeilkianii commited on
Commit
14a7f80
·
verified ·
1 Parent(s): 09c0794

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +243 -70
app.py CHANGED
@@ -29,7 +29,7 @@ import pydeck as pdk
29
  import math
30
  from sklearn.linear_model import LinearRegression
31
 
32
- # Page configuration with custom theme
33
  st.set_page_config(
34
  page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا",
35
  page_icon="🌿",
@@ -37,7 +37,7 @@ st.set_page_config(
37
  initial_sidebar_state="expanded"
38
  )
39
 
40
- # Custom CSS with modern design and animations
41
  st.markdown("""
42
  <style>
43
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100;200;300;400;500;600;700;800;900&display=swap');
@@ -48,39 +48,38 @@ st.markdown("""
48
 
49
  /* Main container styling */
50
  .main {
51
- background: linear-gradient(135deg, #f5f7fa 0%, #e4e9f2 100%);
52
  }
53
 
54
  /* Header styling */
55
  .main-header {
56
  background: linear-gradient(90deg, #2ecc71 0%, #27ae60 100%);
57
- padding: 1.5rem;
58
- border-radius: 12px;
59
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
60
  margin-bottom: 2rem;
61
  position: relative;
62
  overflow: hidden;
63
- animation: header-glow 3s infinite alternate;
64
  }
65
 
66
- @keyframes header-glow {
67
- 0% { box-shadow: 0 8px 32px rgba(46, 204, 113, 0.1); }
68
- 100% { box-shadow: 0 8px 32px rgba(46, 204, 113, 0.3); }
 
69
  }
70
 
71
  .main-header h1 {
72
  color: white;
73
  font-weight: 700;
74
  margin: 0;
75
- position: relative;
76
- z-index: 1;
77
  }
78
 
79
  .main-header p {
80
- color: rgba(255, 255, 255, 0.8);
81
  margin: 0;
82
- position: relative;
83
- z-index: 1;
84
  }
85
 
86
  /* Metric card styling */
@@ -88,29 +87,66 @@ st.markdown("""
88
  display: flex;
89
  justify-content: space-around;
90
  flex-wrap: wrap;
91
- gap: 20px;
92
  padding: 20px;
93
  }
94
 
95
  .metric-card {
96
  background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
97
- border-radius: 15px;
98
- padding: 20px;
99
- width: 220px;
100
  text-align: center;
101
  color: white;
102
- box-shadow: 0 10px 20px rgba(0,0,0,0.2);
103
- transition: transform 0.3s ease, box-shadow 0.3s ease;
 
 
104
  }
105
 
106
  .metric-card:hover {
107
- transform: translateY(-10px);
108
- box-shadow: 0 15px 30px rgba(0,0,0,0.3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
 
111
- .metric-icon { font-size: 2.5rem; margin-bottom: 10px; }
112
- .metric-value { font-size: 2rem; font-weight: 700; }
113
- .metric-label { font-size: 1rem; opacity: 0.9; }
 
 
 
 
 
 
 
 
 
114
 
115
  /* Navigation menu styling */
116
  .st-emotion-cache-1lcbz7b {
@@ -119,38 +155,59 @@ st.markdown("""
119
  margin-bottom: 20px !important;
120
  }
121
 
122
- .st-emotion-cache-1lcbz7b .st-emotion-cache-1j7d69d {
123
  --hover-color: #e9f7ef !important;
124
- border-radius: 10px !important;
125
  font-size: 16px !important;
126
  text-align: center !important;
127
  margin: 0 !important;
 
128
  }
129
 
130
- .st-emotion-cache-1lcbz7b .st-emotion-cache-1j7d69d:hover {
131
  background-color: #e9f7ef !important;
 
132
  }
133
 
134
- .st-emotion-cache-1lcbz7b .st-emotion-cache-1j7d69d[data-selected="true"] {
135
  background-color: #2ecc71 !important;
136
  color: white !important;
137
  font-weight: 600 !important;
 
138
  }
139
 
140
  /* Button styling */
141
  .stButton>button {
142
  border-radius: 50px;
143
- padding: 0.5rem 1.5rem;
144
  font-weight: 600;
145
- transition: all 0.3s ease;
146
- border: none;
147
  background: linear-gradient(90deg, #2ecc71 0%, #27ae60 100%);
148
  color: white;
 
 
149
  }
150
 
151
  .stButton>button:hover {
152
- transform: translateY(-2px);
153
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  }
155
 
156
  /* Footer styling */
@@ -159,10 +216,11 @@ st.markdown("""
159
  left: 0;
160
  bottom: 0;
161
  width: 100%;
162
- background-color: #2ecc71;
163
  color: white;
164
  text-align: center;
165
- padding: 10px 0;
 
166
  }
167
  </style>
168
  """, unsafe_allow_html=True)
@@ -186,7 +244,6 @@ def load_farm_data():
186
  'رطوبت استاندارد قبلی': 'PreviousStandardMoisture', 'چاهک 1': 'Well1', 'تاریخ قرائت': 'Well1Date',
187
  'چاهک 2': 'Well2', 'تاریخ قرائت.1': 'Well2Date'
188
  }, inplace=True)
189
- # Convert numeric columns to float and handle NaN
190
  numeric_cols = ['Area', 'CurrentHeight', 'PreviousHeight', 'CurrentGrowth', 'PreviousGrowth',
191
  'CurrentNitrogen', 'PreviousNitrogen', 'CurrentMoisture', 'PreviousMoisture',
192
  'Station1', 'Station2', 'Station3', 'Station4', 'Station5', 'Well1', 'Well2']
@@ -278,6 +335,15 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"):
278
  elif layer_type == "NDMI":
279
  index = s2.normalizedDifference(['B8', 'B11']).rename('NDMI')
280
  viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#8b0000', '#ff8c00', '#00ced1', '#00b7eb', '#00008b']}
 
 
 
 
 
 
 
 
 
281
  map_id_dict = ee.Image(index).getMapId(viz_params)
282
  folium.TileLayer(
283
  tiles=map_id_dict['tile_fetcher'].url_format,
@@ -301,9 +367,30 @@ def generate_real_growth_data(selected_variety="all", selected_age="all"):
301
  if selected_age != "all":
302
  filtered_farms = filtered_farms[filtered_farms['Age'] == selected_age]
303
 
 
304
  weeks = filtered_farms['Week'].unique()
305
- avg_heights = [filtered_farms[filtered_farms['Week'] == week]['CurrentHeight'].mean() for week in weeks]
306
- return {'weeks': weeks, 'heights': avg_heights}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
 
308
  # Initialize Earth Engine and load data
309
  ee_initialized = initialize_earth_engine()
@@ -323,7 +410,7 @@ if 'heights_df' not in st.session_state:
323
  # Main header
324
  st.markdown('<div class="main-header">', unsafe_allow_html=True)
325
  st.markdown('<h1>سامانه هوشمند پایش مزارع نیشکر دهخدا</h1>', unsafe_allow_html=True)
326
- st.markdown('<p>پلتفرم جامع مدیریت، پایش و تحلیل داده‌های مزارع نیشکر</p>', unsafe_allow_html=True)
327
  st.markdown('</div>', unsafe_allow_html=True)
328
 
329
  # Navigation menu
@@ -337,7 +424,7 @@ selected = option_menu(
337
  styles={
338
  "container": {"padding": "0!important", "background-color": "transparent", "margin-bottom": "20px"},
339
  "icon": {"color": "#2ecc71", "font-size": "18px"},
340
- "nav-link": {"font-size": "16px", "text-align": "center", "margin":"0px", "--hover-color": "#e9f7ef", "border-radius": "10px"},
341
  "nav-link-selected": {"background-color": "#2ecc71", "color": "white", "font-weight": "600"},
342
  }
343
  )
@@ -380,25 +467,61 @@ if selected == "داشبورد":
380
 
381
  st.markdown('</div>', unsafe_allow_html=True)
382
 
383
- st.markdown("### نمودار رشد هفتگی")
384
- growth_data = generate_real_growth_data()
385
- fig = px.line(x=growth_data['weeks'], y=growth_data['heights'], title="رشد هفتگی", labels={'x': 'هفته', 'y': 'ارتفاع (سانتی‌متر)'})
386
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
 
388
  # Map Page
389
  elif selected == "نقشه مزارع":
390
  st.markdown("## نقشه مزارع با شاخص‌های ماهواره‌ای")
391
- farm_id = st.selectbox("انتخاب مزرعه", coordinates_df['Farm_ID'].tolist())
392
- date = st.date_input("انتخاب تاریخ", datetime.now())
393
- layer_type = st.selectbox("انتخاب شاخص", ["NDVI", "NDMI"])
394
- if st.button("تولید نقشه"):
395
- with st.spinner('در حال تولید نقشه...'):
396
- m = create_ee_map(farm_id, date.strftime('%Y-%m-%d'), layer_type)
397
- if m:
398
- folium_static(m, width=800, height=600)
399
- st.success(f"نقشه {layer_type} برای مزرعه {farm_id} تولید شد.")
400
- else:
401
- st.error("خطا در تولید نقشه.")
 
 
 
402
 
403
  # Data Entry Page
404
  elif selected == "ورود اطلاعات":
@@ -406,14 +529,22 @@ elif selected == "ورود اطلاعات":
406
  tab1, tab2 = st.tabs(["ورود دستی", "آپلود فایل"])
407
 
408
  with tab1:
409
- week = st.selectbox("انتخاب هفته", [str(i) for i in range(1, 23)])
410
- day = st.selectbox("انتخاب روز", day_df['Day'].unique())
 
 
 
411
  filtered_farms = farm_df[farm_df['Week'] == int(week)]
412
  if not filtered_farms.empty:
413
  data_key = f"data_{week}_{day}"
414
  if data_key not in st.session_state:
415
  st.session_state[data_key] = pd.DataFrame({
416
  'Farm_ID': filtered_farms['Farm_ID'],
 
 
 
 
 
417
  'CurrentHeight': [0.0] * len(filtered_farms),
418
  'CurrentMoisture': [0.0] * len(filtered_farms)
419
  })
@@ -427,7 +558,7 @@ elif selected == "ورود اطلاعات":
427
  if uploaded_file:
428
  try:
429
  df = pd.read_csv(uploaded_file) if uploaded_file.name.endswith('.csv') else pd.read_excel(uploaded_file)
430
- numeric_cols = ['CurrentHeight', 'CurrentMoisture']
431
  for col in numeric_cols:
432
  if col in df.columns:
433
  df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
@@ -441,17 +572,48 @@ elif selected == "ورود اطلاعات":
441
  # Data Analysis Page
442
  elif selected == "تحلیل داده‌ها":
443
  st.markdown("## تحلیل هوشمند داده‌ها")
444
- growth_data = generate_real_growth_data()
445
- fig = go.Figure()
446
- fig.add_trace(go.Scatter(x=growth_data['weeks'], y=growth_data['heights'], mode='lines+markers', name='رشد'))
447
- fig.update_layout(title='رشد هفتگی', xaxis_title='هفته', yaxis_title='ارتفاع (سانتی‌متر)')
448
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
 
450
  # Report Generation Page
451
  elif selected == "گزارش‌گیری":
452
  st.markdown("## گزارش‌گیری")
453
- report_week = st.selectbox("انتخاب هفته", [str(i) for i in range(1, 23)])
454
- report_day = st.selectbox("انتخاب روز", day_df['Day'].unique())
455
  report_df = st.session_state.heights_df[
456
  (st.session_state.heights_df['Week'] == int(report_week)) &
457
  (st.session_state.heights_df['Farm_ID'].isin(day_df[day_df['Day'] == report_day]['Farm_ID']))
@@ -459,9 +621,10 @@ elif selected == "گزارش‌گیری":
459
  if not report_df.empty:
460
  st.dataframe(report_df)
461
  csv = report_df.to_csv(index=False).encode('utf-8')
462
- st.download_button(label="دانلود گزارش", data=csv, file_name=f"report_week_{report_week}.csv")
463
  else:
464
- st.warning(f"داده‌ای برای هفته {report_week} یافت نشد.")
 
465
 
466
  # Settings Page
467
  elif selected == "تنظیمات":
@@ -469,10 +632,20 @@ elif selected == "تنظیمات":
469
  if st.button("بارگذاری مجدد داده‌ها"):
470
  st.session_state.heights_df = load_farm_data()
471
  st.success("داده‌ها به‌روزرسانی شدند.")
 
 
 
 
 
 
 
 
 
 
472
 
473
  # Footer
474
  st.markdown("""
475
  <footer>
476
- <p>&copy; 2025 سامانه هوشمند پایش مزارع نیشکر دهخدا. تمامی حقوق محفوظ است.</p>
477
  </footer>
478
  """, unsafe_allow_html=True)
 
29
  import math
30
  from sklearn.linear_model import LinearRegression
31
 
32
+ # Page configuration
33
  st.set_page_config(
34
  page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا",
35
  page_icon="🌿",
 
37
  initial_sidebar_state="expanded"
38
  )
39
 
40
+ # Custom CSS with cascading panels and eye-catching reflexes
41
  st.markdown("""
42
  <style>
43
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100;200;300;400;500;600;700;800;900&display=swap');
 
48
 
49
  /* Main container styling */
50
  .main {
51
+ background: linear-gradient(135deg, #f0f4f8 0%, #d9e2ec 100%);
52
  }
53
 
54
  /* Header styling */
55
  .main-header {
56
  background: linear-gradient(90deg, #2ecc71 0%, #27ae60 100%);
57
+ padding: 2rem;
58
+ border-radius: 15px;
59
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
60
  margin-bottom: 2rem;
61
  position: relative;
62
  overflow: hidden;
63
+ animation: headerPulse 3s infinite ease-in-out;
64
  }
65
 
66
+ @keyframes headerPulse {
67
+ 0% { box-shadow: 0 10px 30px rgba(46, 204, 113, 0.2); }
68
+ 50% { box-shadow: 0 15px 40px rgba(46, 204, 113, 0.4); }
69
+ 100% { box-shadow: 0 10px 30px rgba(46, 204, 113, 0.2); }
70
  }
71
 
72
  .main-header h1 {
73
  color: white;
74
  font-weight: 700;
75
  margin: 0;
76
+ text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
 
77
  }
78
 
79
  .main-header p {
80
+ color: rgba(255, 255, 255, 0.9);
81
  margin: 0;
82
+ font-size: 1.1rem;
 
83
  }
84
 
85
  /* Metric card styling */
 
87
  display: flex;
88
  justify-content: space-around;
89
  flex-wrap: wrap;
90
+ gap: 25px;
91
  padding: 20px;
92
  }
93
 
94
  .metric-card {
95
  background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
96
+ border-radius: 20px;
97
+ padding: 25px;
98
+ width: 240px;
99
  text-align: center;
100
  color: white;
101
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
102
+ transition: all 0.4s ease;
103
+ position: relative;
104
+ overflow: hidden;
105
  }
106
 
107
  .metric-card:hover {
108
+ transform: translateY(-10px) scale(1.05);
109
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.25);
110
+ }
111
+
112
+ .metric-card::before {
113
+ content: '';
114
+ position: absolute;
115
+ top: -50%;
116
+ left: -50%;
117
+ width: 200%;
118
+ height: 200%;
119
+ background: rgba(255, 255, 255, 0.1);
120
+ transform: rotate(30deg);
121
+ transition: all 0.4s ease;
122
+ }
123
+
124
+ .metric-card:hover::before {
125
+ top: 100%;
126
+ left: 100%;
127
+ }
128
+
129
+ .metric-icon { font-size: 2.8rem; margin-bottom: 15px; animation: iconBounce 2s infinite; }
130
+ .metric-value { font-size: 2.2rem; font-weight: 700; text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2); }
131
+ .metric-label { font-size: 1.1rem; opacity: 0.9; }
132
+
133
+ @keyframes iconBounce {
134
+ 0%, 100% { transform: translateY(0); }
135
+ 50% { transform: translateY(-10px); }
136
  }
137
 
138
+ /* Dropdown menu styling */
139
+ .stSelectbox {
140
+ background: white;
141
+ border-radius: 12px;
142
+ padding: 10px;
143
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
144
+ transition: all 0.3s ease;
145
+ }
146
+
147
+ .stSelectbox:hover {
148
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
149
+ }
150
 
151
  /* Navigation menu styling */
152
  .st-emotion-cache-1lcbz7b {
 
155
  margin-bottom: 20px !important;
156
  }
157
 
158
+ .st-emotion-cache-1j7d69d {
159
  --hover-color: #e9f7ef !important;
160
+ border-radius: 12px !important;
161
  font-size: 16px !important;
162
  text-align: center !important;
163
  margin: 0 !important;
164
+ transition: all 0.3s ease;
165
  }
166
 
167
+ .st-emotion-cache-1j7d69d:hover {
168
  background-color: #e9f7ef !important;
169
+ transform: translateY(-2px);
170
  }
171
 
172
+ .st-emotion-cache-1j7d69d[data-selected="true"] {
173
  background-color: #2ecc71 !important;
174
  color: white !important;
175
  font-weight: 600 !important;
176
+ box-shadow: 0 5px 15px rgba(46, 204, 113, 0.3);
177
  }
178
 
179
  /* Button styling */
180
  .stButton>button {
181
  border-radius: 50px;
182
+ padding: 0.7rem 2rem;
183
  font-weight: 600;
 
 
184
  background: linear-gradient(90deg, #2ecc71 0%, #27ae60 100%);
185
  color: white;
186
+ border: none;
187
+ transition: all 0.3s ease;
188
  }
189
 
190
  .stButton>button:hover {
191
+ transform: translateY(-3px);
192
+ box-shadow: 0 8px 20px rgba(46, 204, 113, 0.3);
193
+ }
194
+
195
+ /* Tabs styling */
196
+ .stTabs [data-baseweb="tab-list"] {
197
+ gap: 10px;
198
+ }
199
+
200
+ .stTabs [data-baseweb="tab"] {
201
+ border-radius: 8px 8px 0 0;
202
+ padding: 12px 20px;
203
+ background-color: #f8f9fa;
204
+ transition: all 0.3s ease;
205
+ }
206
+
207
+ .stTabs [aria-selected="true"] {
208
+ background-color: #2ecc71 !important;
209
+ color: white !important;
210
+ box-shadow: 0 5px 15px rgba(46, 204, 113, 0.2);
211
  }
212
 
213
  /* Footer styling */
 
216
  left: 0;
217
  bottom: 0;
218
  width: 100%;
219
+ background: linear-gradient(90deg, #2ecc71 0%, #27ae60 100%);
220
  color: white;
221
  text-align: center;
222
+ padding: 15px 0;
223
+ box-shadow: 0 -5px 15px rgba(0, 0, 0, 0.1);
224
  }
225
  </style>
226
  """, unsafe_allow_html=True)
 
244
  'رطوبت استاندارد قبلی': 'PreviousStandardMoisture', 'چاهک 1': 'Well1', 'تاریخ قرائت': 'Well1Date',
245
  'چاهک 2': 'Well2', 'تاریخ قرائت.1': 'Well2Date'
246
  }, inplace=True)
 
247
  numeric_cols = ['Area', 'CurrentHeight', 'PreviousHeight', 'CurrentGrowth', 'PreviousGrowth',
248
  'CurrentNitrogen', 'PreviousNitrogen', 'CurrentMoisture', 'PreviousMoisture',
249
  'Station1', 'Station2', 'Station3', 'Station4', 'Station5', 'Well1', 'Well2']
 
335
  elif layer_type == "NDMI":
336
  index = s2.normalizedDifference(['B8', 'B11']).rename('NDMI')
337
  viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#8b0000', '#ff8c00', '#00ced1', '#00b7eb', '#00008b']}
338
+ elif layer_type == "EVI":
339
+ nir = s2.select('B8')
340
+ red = s2.select('B4')
341
+ blue = s2.select('B2')
342
+ index = nir.subtract(red).multiply(2.5).divide(nir.add(red.multiply(6)).subtract(blue.multiply(7.5)).add(1)).rename('EVI')
343
+ viz_params = {'min': 0, 'max': 1, 'palette': ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#4caf50']}
344
+ elif layer_type == "NDWI":
345
+ index = s2.normalizedDifference(['B3', 'B8']).rename('NDWI')
346
+ viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#00008b', '#00b7eb', '#add8e6', '#fdae61', '#d73027']}
347
  map_id_dict = ee.Image(index).getMapId(viz_params)
348
  folium.TileLayer(
349
  tiles=map_id_dict['tile_fetcher'].url_format,
 
367
  if selected_age != "all":
368
  filtered_farms = filtered_farms[filtered_farms['Age'] == selected_age]
369
 
370
+ farm_growth_data = []
371
  weeks = filtered_farms['Week'].unique()
372
+ for farm_id in filtered_farms['Farm_ID'].unique():
373
+ farm_data = filtered_farms[filtered_farms['Farm_ID'] == farm_id]
374
+ growth_data = {
375
+ 'farm_id': farm_id,
376
+ 'variety': farm_data['Variety'].iloc[0] if not farm_data.empty else 'Unknown',
377
+ 'age': farm_data['Age'].iloc[0] if not farm_data.empty else 'Unknown',
378
+ 'weeks': weeks,
379
+ 'heights': [farm_data[farm_data['Week'] == week]['CurrentHeight'].mean() if not farm_data[farm_data['Week'] == week].empty else 0 for week in weeks]
380
+ }
381
+ farm_growth_data.append(growth_data)
382
+
383
+ if farm_growth_data:
384
+ avg_heights = []
385
+ for week in weeks:
386
+ week_heights = [farm['heights'][list(weeks).index(week)] for farm in farm_growth_data if farm['heights'][list(weeks).index(week)] > 0]
387
+ avg_heights.append(round(sum(week_heights) / len(week_heights)) if week_heights else 0)
388
+ avg_growth_data = {'farm_id': 'میانگین', 'variety': 'همه', 'age': 'همه', 'weeks': weeks, 'heights': avg_heights}
389
+ return {'individual': farm_growth_data, 'average': avg_growth_data}
390
+ return {
391
+ 'individual': [],
392
+ 'average': {'farm_id': 'میانگین', 'variety': 'همه', 'age': 'همه', 'weeks': weeks, 'heights': [0] * len(weeks)}
393
+ }
394
 
395
  # Initialize Earth Engine and load data
396
  ee_initialized = initialize_earth_engine()
 
410
  # Main header
411
  st.markdown('<div class="main-header">', unsafe_allow_html=True)
412
  st.markdown('<h1>سامانه هوشمند پایش مزارع نیشکر دهخدا</h1>', unsafe_allow_html=True)
413
+ st.markdown('<p>پلتفرم جامع مدیریت، پایش و تحلیل داده‌های مزارع نیشکر با فناوری پیشرفته</p>', unsafe_allow_html=True)
414
  st.markdown('</div>', unsafe_allow_html=True)
415
 
416
  # Navigation menu
 
424
  styles={
425
  "container": {"padding": "0!important", "background-color": "transparent", "margin-bottom": "20px"},
426
  "icon": {"color": "#2ecc71", "font-size": "18px"},
427
+ "nav-link": {"font-size": "16px", "text-align": "center", "margin":"0px", "--hover-color": "#e9f7ef", "border-radius": "12px"},
428
  "nav-link-selected": {"background-color": "#2ecc71", "color": "white", "font-weight": "600"},
429
  }
430
  )
 
467
 
468
  st.markdown('</div>', unsafe_allow_html=True)
469
 
470
+ tab1, tab2, tab3, tab4 = st.tabs(["نمای کلی", "نقشه مزارع", "نمودارها", "داده‌ها"])
471
+
472
+ with tab1:
473
+ st.subheader("توزیع واریته‌ها و سن محصول")
474
+ col1, col2 = st.columns(2)
475
+ with col1:
476
+ fig = px.pie(farm_df['Variety'].value_counts().reset_index(), values='count', names='Variety', title='توزیع واریته‌ها')
477
+ st.plotly_chart(fig, use_container_width=True)
478
+ with col2:
479
+ fig = px.pie(farm_df['Age'].value_counts().reset_index(), values='count', names='Age', title='توزیع سن محصول')
480
+ st.plotly_chart(fig, use_container_width=True)
481
+ st_lottie(lottie_farm, height=200, key="farm_animation")
482
+
483
+ with tab2:
484
+ if not coordinates_df.empty:
485
+ m = folium.Map(location=[31.45, 48.72], zoom_start=12)
486
+ for _, farm in coordinates_df.iterrows():
487
+ folium.Marker([farm['Latitude'], farm['Longitude']], popup=f'مزرعه {farm["Farm_ID"]}').add_to(m)
488
+ folium_static(m, width=1000, height=600)
489
+
490
+ with tab3:
491
+ st.subheader("نمودار رشد")
492
+ col1, col2 = st.columns(2)
493
+ with col1:
494
+ variety = st.selectbox("انتخاب واریته", ["all"] + list(farm_df['Variety'].unique()), key="variety_chart")
495
+ with col2:
496
+ age = st.selectbox("انتخاب سن", ["all"] + list(farm_df['Age'].unique()), key="age_chart")
497
+ growth_data = generate_real_growth_data(variety, age)
498
+ fig = go.Figure()
499
+ for farm_data in growth_data['individual'][:5]:
500
+ fig.add_trace(go.Scatter(x=farm_data['weeks'], y=farm_data['heights'], mode='lines+markers', name=f"مزرعه {farm_data['farm_id']}"))
501
+ fig.update_layout(title='رشد هفتگی مزارع', xaxis_title='هفته', yaxis_title='ارتفاع (سانتی‌متر)')
502
+ st.plotly_chart(fig, use_container_width=True)
503
+
504
+ with tab4:
505
+ st.subheader("داده‌های مزارع")
506
+ st.dataframe(farm_df, use_container_width=True)
507
 
508
  # Map Page
509
  elif selected == "نقشه مزارع":
510
  st.markdown("## نقشه مزارع با شاخص‌های ماهواره‌ای")
511
+ col1, col2 = st.columns([1, 3])
512
+ with col1:
513
+ farm_id = st.selectbox("انتخاب مزرعه", coordinates_df['Farm_ID'].tolist())
514
+ date = st.date_input("انتخاب تاریخ", datetime.now())
515
+ layer_type = st.selectbox("انتخاب شاخص", ["NDVI", "NDMI", "EVI", "NDWI"])
516
+ if st.button("تولید نقشه"):
517
+ with st.spinner('در حال تولید نقشه...'):
518
+ m = create_ee_map(farm_id, date.strftime('%Y-%m-%d'), layer_type)
519
+ if m:
520
+ st.session_state['last_map'] = m
521
+ st.success(f"نقشه {layer_type} تولید شد.")
522
+ with col2:
523
+ if 'last_map' in st.session_state:
524
+ folium_static(st.session_state['last_map'], width=800, height=600)
525
 
526
  # Data Entry Page
527
  elif selected == "ورود اطلاعات":
 
529
  tab1, tab2 = st.tabs(["ورود دستی", "آپلود فایل"])
530
 
531
  with tab1:
532
+ col1, col2 = st.columns(2)
533
+ with col1:
534
+ week = st.selectbox("انتخاب هفته", [str(i) for i in range(1, 23)], key="week_entry")
535
+ with col2:
536
+ day = st.selectbox("انتخاب روز", day_df['Day'].unique(), key="day_entry")
537
  filtered_farms = farm_df[farm_df['Week'] == int(week)]
538
  if not filtered_farms.empty:
539
  data_key = f"data_{week}_{day}"
540
  if data_key not in st.session_state:
541
  st.session_state[data_key] = pd.DataFrame({
542
  'Farm_ID': filtered_farms['Farm_ID'],
543
+ 'Station1': [0] * len(filtered_farms),
544
+ 'Station2': [0] * len(filtered_farms),
545
+ 'Station3': [0] * len(filtered_farms),
546
+ 'Station4': [0] * len(filtered_farms),
547
+ 'Station5': [0] * len(filtered_farms),
548
  'CurrentHeight': [0.0] * len(filtered_farms),
549
  'CurrentMoisture': [0.0] * len(filtered_farms)
550
  })
 
558
  if uploaded_file:
559
  try:
560
  df = pd.read_csv(uploaded_file) if uploaded_file.name.endswith('.csv') else pd.read_excel(uploaded_file)
561
+ numeric_cols = ['CurrentHeight', 'CurrentMoisture', 'Station1', 'Station2', 'Station3', 'Station4', 'Station5']
562
  for col in numeric_cols:
563
  if col in df.columns:
564
  df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
 
572
  # Data Analysis Page
573
  elif selected == "تحلیل داده‌ها":
574
  st.markdown("## تحلیل هوشمند داده‌ها")
575
+ tab1, tab2, tab3, tab4 = st.tabs(["تحلیل رشد", "مقایسه واریته‌ها", "تحلیل رطوبت", "پیش‌بینی"])
576
+
577
+ with tab1:
578
+ col1, col2 = st.columns(2)
579
+ with col1:
580
+ variety = st.selectbox("انتخاب واریته", ["all"] + list(farm_df['Variety'].unique()), key="variety_analysis")
581
+ with col2:
582
+ age = st.selectbox("انتخاب سن", ["all"] + list(farm_df['Age'].unique()), key="age_analysis")
583
+ growth_data = generate_real_growth_data(variety, age)
584
+ fig = go.Figure()
585
+ for farm_data in growth_data['individual'][:5]:
586
+ fig.add_trace(go.Scatter(x=farm_data['weeks'], y=farm_data['heights'], mode='lines+markers', name=f"مزرعه {farm_data['farm_id']}"))
587
+ fig.update_layout(title='رشد هفتگی', xaxis_title='هفته', yaxis_title='ارتفاع (سانتی‌متر)')
588
+ st.plotly_chart(fig, use_container_width=True)
589
+
590
+ with tab2:
591
+ fig = px.box(farm_df, x='Variety', y='CurrentHeight', title='مقایسه ارتفاع بر اساس واریته')
592
+ st.plotly_chart(fig, use_container_width=True)
593
+
594
+ with tab3:
595
+ fig = px.scatter(farm_df, x='CurrentMoisture', y='CurrentHeight', color='Farm_ID', title='همبستگی رطوبت و ارتفاع')
596
+ st.plotly_chart(fig, use_container_width=True)
597
+
598
+ with tab4:
599
+ farm_id = st.selectbox("انتخاب مزرعه", farm_df['Farm_ID'].tolist(), key="predict_farm")
600
+ farm_data = farm_df[farm_df['Farm_ID'] == farm_id]
601
+ if len(farm_data) > 1:
602
+ model = LinearRegression()
603
+ model.fit(farm_data['Week'].values.reshape(-1, 1), farm_data['CurrentHeight'].values)
604
+ future_weeks = np.array(range(max(farm_data['Week']) + 1, 30)).reshape(-1, 1)
605
+ future_heights = model.predict(future_weeks)
606
+ fig = go.Figure()
607
+ fig.add_trace(go.Scatter(x=farm_data['Week'], y=farm_data['CurrentHeight'], mode='lines+markers', name='داده‌های واقعی'))
608
+ fig.add_trace(go.Scatter(x=future_weeks.flatten(), y=future_heights, mode='lines', name='پیش‌بینی'))
609
+ fig.update_layout(title=f'پیش‌بینی رشد مزرعه {farm_id}', xaxis_title='هفته', yaxis_title='ارتفاع (سانتی‌متر)')
610
+ st.plotly_chart(fig, use_container_width=True)
611
 
612
  # Report Generation Page
613
  elif selected == "گزارش‌گیری":
614
  st.markdown("## گزارش‌گیری")
615
+ report_week = st.selectbox("انتخاب هفته", [str(i) for i in range(1, 23)], key="report_week")
616
+ report_day = st.selectbox("انتخاب روز", day_df['Day'].unique(), key="report_day")
617
  report_df = st.session_state.heights_df[
618
  (st.session_state.heights_df['Week'] == int(report_week)) &
619
  (st.session_state.heights_df['Farm_ID'].isin(day_df[day_df['Day'] == report_day]['Farm_ID']))
 
621
  if not report_df.empty:
622
  st.dataframe(report_df)
623
  csv = report_df.to_csv(index=False).encode('utf-8')
624
+ st.download_button(label="دانلود گزارش", data=csv, file_name=f"report_week_{report_week}_day_{report_day}.csv")
625
  else:
626
+ st.warning(f"داده‌ای برای هفته {report_week} و روز {report_day} یافت نشد.")
627
+ st_lottie(lottie_report, height=200, key="report_animation")
628
 
629
  # Settings Page
630
  elif selected == "تنظیمات":
 
632
  if st.button("بارگذاری مجدد داده‌ها"):
633
  st.session_state.heights_df = load_farm_data()
634
  st.success("داده‌ها به‌روزرسانی شدند.")
635
+ theme = st.selectbox("انتخاب تم", ["سبز (پیش‌فرض)", "آبی"], key="theme_select")
636
+ if theme == "آبی":
637
+ st.markdown("""
638
+ <style>
639
+ .main-header {background: linear-gradient(90deg, #3498db 0%, #2980b9 100%);}
640
+ .metric-card {background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);}
641
+ .stButton>button {background: linear-gradient(90deg, #3498db 0%, #2980b9 100%);}
642
+ footer {background: linear-gradient(90deg, #3498db 0%, #2980b9 100%);}
643
+ </style>
644
+ """, unsafe_allow_html=True)
645
 
646
  # Footer
647
  st.markdown("""
648
  <footer>
649
+ <p 2025 سامانه هوشمند پایش مزارع نیشکر دهخدا. تمامی حقوق محفوظ است.</p>
650
  </footer>
651
  """, unsafe_allow_html=True)