Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -18,7 +18,7 @@ st.set_page_config(
|
|
18 |
initial_sidebar_state="expanded"
|
19 |
)
|
20 |
|
21 |
-
# CSS برای
|
22 |
st.markdown("""
|
23 |
<style>
|
24 |
@font-face {
|
@@ -27,73 +27,144 @@ st.markdown("""
|
|
27 |
}
|
28 |
|
29 |
* {
|
30 |
-
font-family: 'IRANSans',
|
|
|
|
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
.main {
|
34 |
direction: rtl;
|
35 |
text-align: right;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
}
|
37 |
|
38 |
.stButton button {
|
39 |
-
background
|
40 |
color: white;
|
41 |
-
border
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
44 |
}
|
45 |
|
46 |
.stButton button:hover {
|
47 |
-
background
|
48 |
-
transform: translateY(-
|
49 |
-
box-shadow: 0
|
|
|
|
|
|
|
|
|
|
|
50 |
}
|
51 |
|
52 |
h1, h2, h3 {
|
53 |
color: #1e6b45;
|
|
|
54 |
}
|
55 |
|
56 |
.card {
|
57 |
-
background
|
58 |
-
border-radius:
|
59 |
-
padding:
|
60 |
-
box-shadow: 0
|
61 |
-
margin-bottom:
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
}
|
63 |
|
64 |
.metric-card {
|
|
|
|
|
65 |
padding: 20px;
|
66 |
-
border-radius: 10px;
|
67 |
text-align: center;
|
68 |
-
box-shadow: 0
|
|
|
69 |
}
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
}
|
75 |
|
76 |
-
.
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
}
|
79 |
|
80 |
-
.dataframe
|
81 |
-
|
|
|
|
|
82 |
}
|
83 |
|
84 |
.map-container {
|
85 |
height: 500px;
|
86 |
width: 100%;
|
87 |
-
border-radius:
|
88 |
-
box-shadow: 0
|
89 |
overflow: hidden;
|
90 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
</style>
|
92 |
""", unsafe_allow_html=True)
|
93 |
|
94 |
# خواندن فایلهای پایگاه داده
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
97 |
|
98 |
# تنظیم Earth Engine
|
99 |
@st.cache_resource
|
@@ -128,6 +199,93 @@ def initialize_earth_engine():
|
|
128 |
|
129 |
earth_engine_initialized = initialize_earth_engine()
|
130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
# مدیریت وضعیت برنامه
|
132 |
if 'selected_tab' not in st.session_state:
|
133 |
st.session_state.selected_tab = "ورود اطلاعات"
|
@@ -144,7 +302,7 @@ if 'ndvi_map' not in st.session_state:
|
|
144 |
def calculate_average_height(row):
|
145 |
stations = [row[f'ایستگاه {i}'] for i in range(1, 6) if f'ایستگاه {i}' in row and row[f'ایستگاه {i}'] is not None]
|
146 |
valid_stations = [s for s in stations if s > 0]
|
147 |
-
return
|
148 |
|
149 |
# تابع برای ایجاد نقشه NDVI با مختصات دقیق
|
150 |
def create_ndvi_map(farm_id, date=None):
|
@@ -152,14 +310,10 @@ def create_ndvi_map(farm_id, date=None):
|
|
152 |
st.warning("اتصال به Earth Engine برقرار نشد. نقشه NDVI نمایش داده نمیشود.")
|
153 |
return None
|
154 |
try:
|
155 |
-
# دریافت مختصات مزرعه از فایل coordinates_df
|
156 |
farm_coords = coordinates_df[coordinates_df['نام'] == farm_id].iloc[0]
|
157 |
lat = farm_coords['عرض جغرافیایی']
|
158 |
lon = farm_coords['طول جغرافیایی']
|
159 |
-
|
160 |
-
# ایجاد نقشه با مختصات دقیق
|
161 |
m = folium.Map(location=[lat, lon], zoom_start=12)
|
162 |
-
|
163 |
if date:
|
164 |
date_obj = datetime.strptime(date, '%Y-%m-%d')
|
165 |
start_date = date_obj - timedelta(days=5)
|
@@ -169,7 +323,6 @@ def create_ndvi_map(farm_id, date=None):
|
|
169 |
else:
|
170 |
start_date_str = '2023-01-01'
|
171 |
end_date_str = '2023-12-31'
|
172 |
-
|
173 |
region = ee.Geometry.Point([lon, lat]).buffer(1000)
|
174 |
s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
|
175 |
.filterDate(start_date_str, end_date_str) \
|
@@ -208,30 +361,80 @@ with st.sidebar:
|
|
208 |
st.subheader("شرکت کشت و صنعت نیشکر دهخدا")
|
209 |
menu = st.selectbox(
|
210 |
"انتخاب صفحه",
|
211 |
-
["ورود اطلاعات", "
|
212 |
)
|
213 |
st.session_state.selected_tab = menu
|
214 |
st.markdown("---")
|
215 |
-
st.info("نسخه
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
|
217 |
-
#
|
218 |
-
|
219 |
-
st.title("ورود اطلاعات روزانه")
|
|
|
220 |
|
221 |
-
# انتخاب هفته
|
222 |
weeks = [str(i) for i in range(1, 23)]
|
223 |
selected_week = st.selectbox("انتخاب هفته", weeks, index=weeks.index(st.session_state.selected_week))
|
224 |
st.session_state.selected_week = selected_week
|
225 |
|
226 |
-
# انتخاب روز هفته
|
227 |
days_of_week = ["شنبه", "یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه"]
|
228 |
selected_day = st.selectbox("انتخاب روز", days_of_week, index=days_of_week.index(st.session_state.selected_day))
|
229 |
st.session_state.selected_day = selected_day
|
230 |
|
231 |
-
# فیلتر مزارع بر اساس روز انتخابشده
|
232 |
filtered_farms = farms_df[farms_df['روز'] == selected_day].copy()
|
233 |
-
|
234 |
-
# تعریف ستونهای جدول
|
235 |
columns = {
|
236 |
'مزرعه': filtered_farms['مزرعه'],
|
237 |
'ایستگاه 1': [0] * len(filtered_farms),
|
@@ -247,7 +450,6 @@ if st.session_state.selected_tab == "ورود اطلاعات":
|
|
247 |
}
|
248 |
data_df = pd.DataFrame(columns)
|
249 |
|
250 |
-
# بارگذاری دادههای قبلی (اگر وجود داشته باشد)
|
251 |
week_day_key = f"week_{selected_week}_day_{selected_day}"
|
252 |
if week_day_key in st.session_state.farm_data:
|
253 |
for idx, farm in filtered_farms.iterrows():
|
@@ -259,7 +461,6 @@ if st.session_state.selected_tab == "ورود اطلاعات":
|
|
259 |
data_df.at[idx, col] = saved_data[col]
|
260 |
data_df.at[idx, 'میانگین ارتفاع'] = calculate_average_height(data_df.iloc[idx])
|
261 |
|
262 |
-
# نمایش جدول ورود دادهها
|
263 |
st.subheader(f"ورود دادههای هفته {selected_week} - روز {selected_day}")
|
264 |
edited_df = st.data_editor(
|
265 |
data_df,
|
@@ -282,29 +483,25 @@ if st.session_state.selected_tab == "ورود اطلاعات":
|
|
282 |
use_container_width=True
|
283 |
)
|
284 |
|
285 |
-
# محاسبه داینامیک میانگین ارتفاع
|
286 |
for idx, row in edited_df.iterrows():
|
287 |
edited_df.at[idx, 'میانگین ارتفاع'] = calculate_average_height(row)
|
288 |
|
289 |
-
|
290 |
-
st.markdown("---")
|
291 |
-
st.subheader("خلاصه وضعیت دادههای واردشده")
|
292 |
col1, col2, col3, col4 = st.columns(4)
|
293 |
with col1:
|
294 |
total_avg = edited_df['میانگین ارتفاع'].mean()
|
295 |
-
st.
|
296 |
with col2:
|
297 |
farms_entered = len(edited_df[edited_df['میانگین ارتفاع'] > 0])
|
298 |
-
st.
|
299 |
with col3:
|
300 |
avg_moisture = edited_df['رطوبت غلاف'].mean()
|
301 |
-
st.
|
302 |
with col4:
|
303 |
avg_nitrogen = edited_df['نیتروژن'].mean()
|
304 |
-
st.
|
305 |
|
306 |
-
|
307 |
-
if st.button("ذخیره اطلاعات"):
|
308 |
if week_day_key not in st.session_state.farm_data:
|
309 |
st.session_state.farm_data[week_day_key] = {}
|
310 |
for idx, row in edited_df.iterrows():
|
@@ -321,26 +518,37 @@ if st.session_state.selected_tab == "ورود اطلاعات":
|
|
321 |
'نیتروژن': row['نیتروژن'],
|
322 |
'میانگین ارتفاع': row['میانگین ارتفاع']
|
323 |
}
|
324 |
-
st.success("دادهها
|
|
|
325 |
|
326 |
-
#
|
327 |
-
elif st.session_state.selected_tab == "
|
328 |
-
st.title("
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
initial_sidebar_state="expanded"
|
19 |
)
|
20 |
|
21 |
+
# CSS پیشرفته برای تحول در ظاهر
|
22 |
st.markdown("""
|
23 |
<style>
|
24 |
@font-face {
|
|
|
27 |
}
|
28 |
|
29 |
* {
|
30 |
+
font-family: 'IRANSans', sans-serif !important;
|
31 |
+
}
|
32 |
+
|
33 |
+
body {
|
34 |
+
background: linear-gradient(135deg, #e8f5e9 0%, #f1f8e9 100%);
|
35 |
+
color: #2e2e2e;
|
36 |
}
|
37 |
|
38 |
.main {
|
39 |
direction: rtl;
|
40 |
text-align: right;
|
41 |
+
padding: 20px;
|
42 |
+
}
|
43 |
+
|
44 |
+
.sidebar .sidebar-content {
|
45 |
+
background: linear-gradient(180deg, #1e6b45 0%, #2a8c5c 100%);
|
46 |
+
color: white;
|
47 |
+
border-radius: 15px;
|
48 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
49 |
+
padding: 20px;
|
50 |
+
transition: all 0.3s ease;
|
51 |
+
}
|
52 |
+
|
53 |
+
.sidebar .sidebar-content:hover {
|
54 |
+
transform: translateY(-5px);
|
55 |
}
|
56 |
|
57 |
.stButton button {
|
58 |
+
background: linear-gradient(90deg, #1e6b45, #2a8c5c);
|
59 |
color: white;
|
60 |
+
border: none;
|
61 |
+
border-radius: 25px;
|
62 |
+
padding: 12px 30px;
|
63 |
+
font-size: 16px;
|
64 |
+
font-weight: bold;
|
65 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
66 |
+
transition: all 0.3s ease;
|
67 |
}
|
68 |
|
69 |
.stButton button:hover {
|
70 |
+
background: linear-gradient(90deg, #2a8c5c, #3aa674);
|
71 |
+
transform: translateY(-3px);
|
72 |
+
box-shadow: 0 6px 18px rgba(0,0,0,0.3);
|
73 |
+
}
|
74 |
+
|
75 |
+
.stButton button:active {
|
76 |
+
transform: translateY(1px);
|
77 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
78 |
}
|
79 |
|
80 |
h1, h2, h3 {
|
81 |
color: #1e6b45;
|
82 |
+
text-shadow: 1px 1px 3px rgba(0,0,0,0.1);
|
83 |
}
|
84 |
|
85 |
.card {
|
86 |
+
background: white;
|
87 |
+
border-radius: 15px;
|
88 |
+
padding: 25px;
|
89 |
+
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
|
90 |
+
margin-bottom: 30px;
|
91 |
+
transition: all 0.3s ease;
|
92 |
+
}
|
93 |
+
|
94 |
+
.card:hover {
|
95 |
+
transform: translateY(-5px);
|
96 |
+
box-shadow: 0 12px 25px rgba(0,0,0,0.15);
|
97 |
}
|
98 |
|
99 |
.metric-card {
|
100 |
+
background: white;
|
101 |
+
border-radius: 15px;
|
102 |
padding: 20px;
|
|
|
103 |
text-align: center;
|
104 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
105 |
+
transition: all 0.3s ease;
|
106 |
}
|
107 |
|
108 |
+
.metric-card:hover {
|
109 |
+
transform: scale(1.05);
|
110 |
+
box-shadow: 0 8px 20px rgba(0,0,0,0.15);
|
111 |
}
|
112 |
|
113 |
+
.metric-green {
|
114 |
+
border-left: 6px solid #00c853;
|
115 |
+
}
|
116 |
+
|
117 |
+
.metric-yellow {
|
118 |
+
border-left: 6px solid #ffd600;
|
119 |
+
}
|
120 |
+
|
121 |
+
.metric-red {
|
122 |
+
border-left: 6px solid #ff3d00;
|
123 |
+
}
|
124 |
+
|
125 |
+
.metric-blue {
|
126 |
+
border-left: 6px solid #2196f3;
|
127 |
+
}
|
128 |
+
|
129 |
+
.stSelectbox select {
|
130 |
+
background: white;
|
131 |
+
border-radius: 10px;
|
132 |
+
padding: 10px;
|
133 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
134 |
}
|
135 |
|
136 |
+
.dataframe {
|
137 |
+
border-radius: 10px;
|
138 |
+
overflow: hidden;
|
139 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
140 |
}
|
141 |
|
142 |
.map-container {
|
143 |
height: 500px;
|
144 |
width: 100%;
|
145 |
+
border-radius: 15px;
|
146 |
+
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
|
147 |
overflow: hidden;
|
148 |
}
|
149 |
+
|
150 |
+
.highlight {
|
151 |
+
animation: glow 1.5s infinite alternate;
|
152 |
+
}
|
153 |
+
|
154 |
+
@keyframes glow {
|
155 |
+
0% { box-shadow: 0 0 5px #1e6b45; }
|
156 |
+
100% { box-shadow: 0 0 15px #2a8c5c; }
|
157 |
+
}
|
158 |
</style>
|
159 |
""", unsafe_allow_html=True)
|
160 |
|
161 |
# خواندن فایلهای پایگاه داده
|
162 |
+
try:
|
163 |
+
farms_df = pd.read_csv("پایگاه داده (1).csv")
|
164 |
+
coordinates_df = pd.read_csv("farm_coordinates.csv")
|
165 |
+
except FileNotFoundError as e:
|
166 |
+
st.error(f"فایل موردنظر یافت نشد: {e}")
|
167 |
+
st.stop()
|
168 |
|
169 |
# تنظیم Earth Engine
|
170 |
@st.cache_resource
|
|
|
199 |
|
200 |
earth_engine_initialized = initialize_earth_engine()
|
201 |
|
202 |
+
# نمونه داده (برای داشبورد و گزارشها)
|
203 |
+
@st.cache_data
|
204 |
+
def generate_sample_data():
|
205 |
+
farm_data = {
|
206 |
+
'Farm_ID': farms_df['مزرعه'].tolist(),
|
207 |
+
'Farm_Name': farms_df['مزرعه'].tolist(),
|
208 |
+
'Channel_ID': farms_df['کانال'].tolist(),
|
209 |
+
'Administration_ID': farms_df['اداره'].tolist(),
|
210 |
+
'Administration_Name': [f'اداره {i}' for i in farms_df['اداره']],
|
211 |
+
'Production_Section': [1 if i <= 2 else 2 for i in farms_df['اداره']],
|
212 |
+
'Area': [np.random.randint(50, 200) for _ in range(len(farms_df))],
|
213 |
+
'Variety': farms_df['واریته'].tolist(),
|
214 |
+
'Crop_Age': [int(age.split('/')[0]) for age in farms_df['سن']]
|
215 |
+
}
|
216 |
+
farms_sample_df = pd.DataFrame(farm_data)
|
217 |
+
|
218 |
+
height_data = []
|
219 |
+
today = datetime.now()
|
220 |
+
for week in range(1, 23):
|
221 |
+
date = today - timedelta(days=(22-week)*7)
|
222 |
+
for farm_id in farms_sample_df['Farm_ID']:
|
223 |
+
stations = [np.random.randint(150, 220) for _ in range(5)]
|
224 |
+
avg_height = int(np.mean(stations))
|
225 |
+
groundwater = [np.random.randint(50, 100) for _ in range(2)]
|
226 |
+
sheath_moisture = np.random.randint(60, 90)
|
227 |
+
nitrogen = np.random.randint(20, 40)
|
228 |
+
height_data.append({
|
229 |
+
'Measurement_ID': f"{farm_id}-W{week}",
|
230 |
+
'Farm_ID': farm_id,
|
231 |
+
'Week': week,
|
232 |
+
'Measurement_Date': date.strftime('%Y-%m-%d'),
|
233 |
+
'Height': avg_height,
|
234 |
+
'Station1': stations[0],
|
235 |
+
'Station2': stations[1],
|
236 |
+
'Station3': stations[2],
|
237 |
+
'Station4': stations[3],
|
238 |
+
'Station5': stations[4],
|
239 |
+
'Groundwater1': groundwater[0],
|
240 |
+
'Groundwater2': groundwater[1],
|
241 |
+
'Sheath_Moisture': sheath_moisture,
|
242 |
+
'Nitrogen': nitrogen
|
243 |
+
})
|
244 |
+
heights_df = pd.DataFrame(height_data)
|
245 |
+
|
246 |
+
weekly_report_data = []
|
247 |
+
for farm_id in farms_sample_df['Farm_ID']:
|
248 |
+
farm_heights = heights_df[heights_df['Farm_ID'] == farm_id].sort_values('Week')
|
249 |
+
for week in range(1, 23):
|
250 |
+
current_week_data = farm_heights[farm_heights['Week'] == week]
|
251 |
+
if current_week_data.empty:
|
252 |
+
continue
|
253 |
+
current_height = current_week_data['Height'].values[0]
|
254 |
+
if week > 1:
|
255 |
+
prev_week_data = farm_heights[farm_heights['Week'] == week-1]
|
256 |
+
if not prev_week_data.empty:
|
257 |
+
prev_height = prev_week_data['Height'].values[0]
|
258 |
+
growth_change = current_height - prev_height
|
259 |
+
else:
|
260 |
+
growth_change = 0
|
261 |
+
else:
|
262 |
+
growth_change = 0
|
263 |
+
all_farms_this_week = heights_df[heights_df['Week'] == week]
|
264 |
+
avg_height_all_farms = all_farms_this_week['Height'].mean()
|
265 |
+
if current_height > avg_height_all_farms + 5:
|
266 |
+
growth_status = 'خوب'
|
267 |
+
elif current_height < avg_height_all_farms - 5:
|
268 |
+
growth_status = 'ضعیف'
|
269 |
+
else:
|
270 |
+
growth_status = 'متوسط'
|
271 |
+
weekly_report_data.append({
|
272 |
+
'Report_ID': f"{farm_id}-R{week}",
|
273 |
+
'Farm_ID': farm_id,
|
274 |
+
'Week': week,
|
275 |
+
'Average_Height': current_height,
|
276 |
+
'Growth_Change': growth_change,
|
277 |
+
'Growth_Status': growth_status,
|
278 |
+
'Regional_Average': int(avg_height_all_farms)
|
279 |
+
})
|
280 |
+
weekly_report_df = pd.DataFrame(weekly_report_data)
|
281 |
+
|
282 |
+
return farms_sample_df, heights_df, weekly_report_df
|
283 |
+
|
284 |
+
farms_sample_df, heights_df, weekly_report_df = generate_sample_data()
|
285 |
+
report_with_details = pd.merge(weekly_report_df, farms_sample_df, on='Farm_ID')
|
286 |
+
latest_week = heights_df['Week'].max()
|
287 |
+
latest_reports = report_with_details[report_with_details['Week'] == latest_week]
|
288 |
+
|
289 |
# مدیریت وضعیت برنامه
|
290 |
if 'selected_tab' not in st.session_state:
|
291 |
st.session_state.selected_tab = "ورود اطلاعات"
|
|
|
302 |
def calculate_average_height(row):
|
303 |
stations = [row[f'ایستگاه {i}'] for i in range(1, 6) if f'ایستگاه {i}' in row and row[f'ایستگاه {i}'] is not None]
|
304 |
valid_stations = [s for s in stations if s > 0]
|
305 |
+
return(sum(valid_stations) / len(valid_stations)) if valid_stations else 0
|
306 |
|
307 |
# تابع برای ایجاد نقشه NDVI با مختصات دقیق
|
308 |
def create_ndvi_map(farm_id, date=None):
|
|
|
310 |
st.warning("اتصال به Earth Engine برقرار نشد. نقشه NDVI نمایش داده نمیشود.")
|
311 |
return None
|
312 |
try:
|
|
|
313 |
farm_coords = coordinates_df[coordinates_df['نام'] == farm_id].iloc[0]
|
314 |
lat = farm_coords['عرض جغرافیایی']
|
315 |
lon = farm_coords['طول جغرافیایی']
|
|
|
|
|
316 |
m = folium.Map(location=[lat, lon], zoom_start=12)
|
|
|
317 |
if date:
|
318 |
date_obj = datetime.strptime(date, '%Y-%m-%d')
|
319 |
start_date = date_obj - timedelta(days=5)
|
|
|
323 |
else:
|
324 |
start_date_str = '2023-01-01'
|
325 |
end_date_str = '2023-12-31'
|
|
|
326 |
region = ee.Geometry.Point([lon, lat]).buffer(1000)
|
327 |
s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
|
328 |
.filterDate(start_date_str, end_date_str) \
|
|
|
361 |
st.subheader("شرکت کشت و صنعت نیشکر دهخدا")
|
362 |
menu = st.selectbox(
|
363 |
"انتخاب صفحه",
|
364 |
+
["داشبورد", "ورود اطلاعات", "گزارشگیری", "تحلیل دادهها", "تنظیمات"]
|
365 |
)
|
366 |
st.session_state.selected_tab = menu
|
367 |
st.markdown("---")
|
368 |
+
st.info("نسخه حرفهای 2.0")
|
369 |
+
|
370 |
+
# داشبورد
|
371 |
+
if st.session_state.selected_tab == "داشبورد":
|
372 |
+
st.title("📊 داشبورد پایش مزارع نیشکر")
|
373 |
+
st.markdown('<div class="card">', unsafe_allow_html=True)
|
374 |
+
st.subheader("وضعیت کلی مزارع")
|
375 |
+
status_counts = latest_reports['Growth_Status'].value_counts()
|
376 |
+
good_count = status_counts.get('خوب', 0)
|
377 |
+
medium_count = status_counts.get('متوسط', 0)
|
378 |
+
bad_count = status_counts.get('ضعیف', 0)
|
379 |
+
col1, col2, col3, col4 = st.columns(4)
|
380 |
+
with col1:
|
381 |
+
st.markdown('<div class="metric-card metric-green">'f'<h2>{good_count}</h2>''<p>مزارع با وضعیت خوب</p>''</div>', unsafe_allow_html=True)
|
382 |
+
with col2:
|
383 |
+
st.markdown('<div class="metric-card metric-yellow">'f'<h2>{medium_count}</h2>''<p>مزارع با وضعیت متوسط</p>''</div>', unsafe_allow_html=True)
|
384 |
+
with col3:
|
385 |
+
st.markdown('<div class="metric-card metric-red">'f'<h2>{bad_count}</h2>''<p>مزارع با وضعیت ضعیف</p>''</div>', unsafe_allow_html=True)
|
386 |
+
with col4:
|
387 |
+
avg_height = int(latest_reports['Average_Height'].mean())
|
388 |
+
st.markdown('<div class="metric-card metric-blue">'f'<h2>{avg_height} سانتیمتر</h2>''<p>میانگین ارتفاع هفته جاری</p>''</div>', unsafe_allow_html=True)
|
389 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
390 |
+
|
391 |
+
st.markdown('<div class="card">', unsafe_allow_html=True)
|
392 |
+
col1, col2 = st.columns(2)
|
393 |
+
with col1:
|
394 |
+
st.subheader("📈 میانگین ارتفاع به تفکیک اداره")
|
395 |
+
admin_heights = latest_reports.groupby('Administration_Name')['Average_Height'].mean().reset_index()
|
396 |
+
admin_heights['Average_Height'] = admin_heights['Average_Height'].astype(int)
|
397 |
+
fig = px.bar(
|
398 |
+
admin_heights,
|
399 |
+
x='Administration_Name',
|
400 |
+
y='Average_Height',
|
401 |
+
color='Average_Height',
|
402 |
+
color_continuous_scale=[(0, "red"), (0.5, "yellow"), (1, "green")],
|
403 |
+
labels={'Administration_Name': 'اداره', 'Average_Height': 'میانگین ارتفاع (سانتیمتر)'}
|
404 |
+
)
|
405 |
+
fig.update_layout(height=400, xaxis_title="اداره", yaxis_title="میانگین ارتفاع (سانتیمتر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
|
406 |
+
st.plotly_chart(fig, use_container_width=True)
|
407 |
+
with col2:
|
408 |
+
st.subheader("📊 مقایسه واریتهها")
|
409 |
+
variety_heights = latest_reports.groupby('Variety')['Average_Height'].mean().reset_index()
|
410 |
+
variety_heights['Average_Height'] = variety_heights['Average_Height'].astype(int)
|
411 |
+
fig = px.bar(
|
412 |
+
variety_heights,
|
413 |
+
x='Variety',
|
414 |
+
y='Average_Height',
|
415 |
+
color='Variety',
|
416 |
+
color_discrete_sequence=["#00c853", "#2196f3"],
|
417 |
+
labels={'Variety': 'واریته', 'Average_Height': 'میانگین ارتفاع (سانتیمتر)'}
|
418 |
+
)
|
419 |
+
fig.update_layout(height=400, xaxis_title="واریته", yaxis_title="میانگین ارتفاع (سانتیمتر)", font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
|
420 |
+
st.plotly_chart(fig, use_container_width=True)
|
421 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
422 |
|
423 |
+
# ورود اطلاعات
|
424 |
+
elif st.session_state.selected_tab == "ورود اطلاعات":
|
425 |
+
st.title("📋 ورود اطلاعات روزانه")
|
426 |
+
st.markdown('<div class="card">', unsafe_allow_html=True)
|
427 |
|
|
|
428 |
weeks = [str(i) for i in range(1, 23)]
|
429 |
selected_week = st.selectbox("انتخاب هفته", weeks, index=weeks.index(st.session_state.selected_week))
|
430 |
st.session_state.selected_week = selected_week
|
431 |
|
|
|
432 |
days_of_week = ["شنبه", "یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه"]
|
433 |
selected_day = st.selectbox("انتخاب روز", days_of_week, index=days_of_week.index(st.session_state.selected_day))
|
434 |
st.session_state.selected_day = selected_day
|
435 |
|
|
|
436 |
filtered_farms = farms_df[farms_df['روز'] == selected_day].copy()
|
437 |
+
|
|
|
438 |
columns = {
|
439 |
'مزرعه': filtered_farms['مزرعه'],
|
440 |
'ایستگاه 1': [0] * len(filtered_farms),
|
|
|
450 |
}
|
451 |
data_df = pd.DataFrame(columns)
|
452 |
|
|
|
453 |
week_day_key = f"week_{selected_week}_day_{selected_day}"
|
454 |
if week_day_key in st.session_state.farm_data:
|
455 |
for idx, farm in filtered_farms.iterrows():
|
|
|
461 |
data_df.at[idx, col] = saved_data[col]
|
462 |
data_df.at[idx, 'میانگین ارتفاع'] = calculate_average_height(data_df.iloc[idx])
|
463 |
|
|
|
464 |
st.subheader(f"ورود دادههای هفته {selected_week} - روز {selected_day}")
|
465 |
edited_df = st.data_editor(
|
466 |
data_df,
|
|
|
483 |
use_container_width=True
|
484 |
)
|
485 |
|
|
|
486 |
for idx, row in edited_df.iterrows():
|
487 |
edited_df.at[idx, 'میانگین ارتفاع'] = calculate_average_height(row)
|
488 |
|
489 |
+
st.subheader("خلاصه وضعیت دادهها")
|
|
|
|
|
490 |
col1, col2, col3, col4 = st.columns(4)
|
491 |
with col1:
|
492 |
total_avg = edited_df['میانگین ارتفاع'].mean()
|
493 |
+
st.markdown(f'<div class="metric-card metric-green"><h3>{total_avg:.1f} سانتیمتر</h3><p>میانگین کل ارتفاع</p></div>', unsafe_allow_html=True)
|
494 |
with col2:
|
495 |
farms_entered = len(edited_df[edited_df['میانگین ارتفاع'] > 0])
|
496 |
+
st.markdown(f'<div class="metric-card metric-blue"><h3>{farms_entered}/{len(filtered_farms)}</h3><p>مزارع واردشده</p></div>', unsafe_allow_html=True)
|
497 |
with col3:
|
498 |
avg_moisture = edited_df['رطوبت غلاف'].mean()
|
499 |
+
st.markdown(f'<div class="metric-card metric-yellow"><h3>{avg_moisture:.1f}%</h3><p>میانگین رطوبت</p></div>', unsafe_allow_html=True)
|
500 |
with col4:
|
501 |
avg_nitrogen = edited_df['نیتروژن'].mean()
|
502 |
+
st.markdown(f'<div class="metric-card metric-red"><h3>{avg_nitrogen:.1f}%</h3><p>میانگین نیتروژن</p></div>', unsafe_allow_html=True)
|
503 |
|
504 |
+
if st.button("💾 ذخیره اطلاعات"):
|
|
|
505 |
if week_day_key not in st.session_state.farm_data:
|
506 |
st.session_state.farm_data[week_day_key] = {}
|
507 |
for idx, row in edited_df.iterrows():
|
|
|
518 |
'نیتروژن': row['نیتروژن'],
|
519 |
'میانگین ارتفاع': row['میانگین ارتفاع']
|
520 |
}
|
521 |
+
st.success("دادهها ذخیره شدند!")
|
522 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
523 |
|
524 |
+
# گزارشگیری
|
525 |
+
elif st.session_state.selected_tab == "گزارشگیری":
|
526 |
+
st.title("📑 گزارشگیری")
|
527 |
+
st.markdown('<div class="card">', unsafe_allow_html=True)
|
528 |
+
report_type = st.radio("نوع گزارش", ["گزارش مزرعه", "گزارش اداره"])
|
529 |
+
if report_type == "گزارش مزرعه":
|
530 |
+
st.subheader("گزارش به تفکیک مزرعه")
|
531 |
+
selected_farm = st.selectbox("انتخاب مزرعه", farms_sample_df['Farm_ID'].tolist())
|
532 |
+
farm_reports = weekly_report_df[weekly_report_df['Farm_ID'] == selected_farm].sort_values('Week')
|
533 |
+
if not farm_reports.empty:
|
534 |
+
fig = px.line(farm_reports, x='Week', y='Average_Height', title="روند رشد مزرعه", markers=True)
|
535 |
+
fig.update_layout(font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
|
536 |
+
st.plotly_chart(fig, use_container_width=True)
|
537 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
538 |
+
|
539 |
+
# تحلیل دادهها
|
540 |
+
elif st.session_state.selected_tab == "تحلیل دادهها":
|
541 |
+
st.title("🔍 تحلیل دادهها")
|
542 |
+
st.markdown('<div class="card">', unsafe_allow_html=True)
|
543 |
+
variety_weekly = report_with_details.groupby(['Variety', 'Week'])['Average_Height'].mean().reset_index()
|
544 |
+
fig = px.line(variety_weekly, x='Week', y='Average_Height', color='Variety', title="تحلیل واریتهها", markers=True)
|
545 |
+
fig.update_layout(font=dict(family="IRANSans"), plot_bgcolor='rgba(0,0,0,0)')
|
546 |
+
st.plotly_chart(fig, use_container_width=True)
|
547 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
548 |
+
|
549 |
+
# تنظیمات
|
550 |
+
elif st.session_state.selected_tab == "تنظیمات":
|
551 |
+
st.title("⚙️ تنظیمات")
|
552 |
+
st.markdown('<div class="card">', unsafe_allow_html=True)
|
553 |
+
st.write("در حال توسعه...")
|
554 |
+
st.markdown('</div>', unsafe_allow_html=True)
|