', unsafe_allow_html=True)
+ else:
+ st.warning("دادههای مختصات در دسترس نیست.")
+
+ with tab3:
+ st.markdown("### نمودار رشد هفتگی")
+
+ # Create filters for variety and age
+ col1, col2 = st.columns(2)
+ with col1:
+ selected_variety = st.selectbox(
+ "انتخاب واریته",
+ ["all"] + list(farm_df['واریته'].unique()),
+ format_func=lambda x: "همه واریتهها" if x == "all" else x
+ )
+
+ with col2:
+ selected_age = st.selectbox(
+ "انتخاب سن",
+ ["all"] + list(farm_df['سن'].unique()),
+ format_func=lambda x: "همه سنین" if x == "all" else x
+ )
+
+ # Generate mock growth data
+ growth_data = generate_mock_growth_data(farm_df, selected_variety, selected_age)
+
+ # Create tabs for average and individual growth charts
+ chart_tab1, chart_tab2 = st.tabs(["میانگین رشد", "رشد مزارع فردی"])
+
+ with chart_tab1:
+ # Create average growth chart
+ avg_data = growth_data['average']
+ fig = go.Figure()
+ fig.add_trace(go.Scatter(
+ x=avg_data['weeks'],
+ y=avg_data['heights'],
+ mode='lines+markers',
+ name='میانگین رشد',
+ line=dict(color='#1a8754', width=3),
+ marker=dict(size=8, color='#1a8754')
+ ))
+
+ fig.update_layout(
+ title='میانگین رشد هفتگی',
+ xaxis_title='هفته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family='Vazirmatn', size=14),
+ hovermode='x unified',
+ template='plotly_white',
+ height=500
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ with chart_tab2:
+ # Create individual growth chart
+ if growth_data['individual']:
+ fig = go.Figure()
+
+ # Only show up to 5 farms to avoid clutter
+ colors = ['#1a8754', '#1976d2', '#e65100', '#9c27b0', '#d32f2f']
+ for i, farm_data in enumerate(growth_data['individual'][:5]):
+ fig.add_trace(go.Scatter(
+ x=farm_data['weeks'],
+ y=farm_data['heights'],
+ mode='lines+markers',
+ name=f"مزرعه {farm_data['farm_id']}",
+ line=dict(color=colors[i % len(colors)], width=2),
+ marker=dict(size=6, color=colors[i % len(colors)])
+ ))
+
+ fig.update_layout(
+ title='رشد هفتگی مزارع فردی',
+ xaxis_title='هفته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family='Vazirmatn', size=14),
+ hovermode='x unified',
+ template='plotly_white',
+ height=500
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.warning("دادهای برای نمایش وجود ندارد.")
+
+ with tab4:
+ st.markdown("### دادههای مزارع")
+
+ # Create a search box
+ search_term = st.text_input("جستجو در دادهها", placeholder="نام مزرعه، واریته، سن و...")
+
+ # Filter data based on search term
+ if search_term:
+ filtered_df = farm_df[
+ farm_df['مزرعه'].astype(str).str.contains(search_term) |
+ farm_df['واریته'].astype(str).str.contains(search_term) |
+ farm_df['سن'].astype(str).str.contains(search_term) |
+ farm_df['کانال'].astype(str).str.contains(search_term)
+ ]
+ else:
+ filtered_df = farm_df
+
+ # Display data table with pagination
+ if not filtered_df.empty:
+ # Add a download button
+ csv = filtered_df.to_csv(index=False).encode('utf-8')
+ st.download_button(
+ label="دانلود دادهها (CSV)",
+ data=csv,
+ file_name="farm_data.csv",
+ mime="text/csv",
+ )
+
+ # Display the data table
+ st.dataframe(
+ filtered_df,
+ use_container_width=True,
+ height=400,
+ hide_index=True
+ )
+
+ st.info(f"نمایش {len(filtered_df)} مزرعه از {len(farm_df)} مزرعه")
+ else:
+ st.warning("هیچ دادهای یافت نشد.")
+
+# Map Page
+elif selected == "نقشه مزارع":
+ st.markdown("## نقشه مزارع با شاخصهای ماهوارهای")
+
+ # Create a layout with sidebar for controls
+ col1, col2 = st.columns([1, 3])
+
+ with col1:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown("### تنظیمات نقشه")
+
+ # Farm selection
+ selected_farm = st.selectbox(
+ "انتخاب مزرعه",
+ options=coordinates_df['نام'].tolist(),
+ index=0,
+ format_func=lambda x: f"مزرعه {x}"
+ )
+
+ # Date selection
+ selected_date = st.date_input(
+ "انتخاب تاریخ",
+ value=datetime.now(),
+ format="YYYY-MM-DD"
+ )
+
+ # Layer type selection
+ selected_layer = st.selectbox(
+ "انتخاب شاخص",
+ options=["NDVI", "NDMI", "EVI", "NDWI"],
+ format_func=lambda x: {
+ "NDVI": "شاخص پوشش گیاهی (NDVI)",
+ "NDMI": "شاخص رطوبت (NDMI)",
+ "EVI": "شاخص پیشرفته گیاهی (EVI)",
+ "NDWI": "شاخص آب (NDWI)"
+ }[x]
+ )
+
+ # Generate map button
+ generate_map = st.button(
+ "تولید نقشه",
+ type="primary",
+ use_container_width=True
+ )
+
+ # Add a separator
+ st.markdown('', unsafe_allow_html=True)
+
+ # Add index descriptions
+ st.markdown("### راهنمای شاخصها")
+
+ with st.expander("شاخص پوشش گیاهی (NDVI)", expanded=selected_layer == "NDVI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده پوشش گیاهی (NDVI)** معیاری برای سنجش سلامت و تراکم پوشش گیاهی است.
+
+ - **مقادیر بالا (0.6 تا 1.0)**: پوشش گیاهی متراکم و سالم
+ - **مقادیر متوسط (0.2 تا 0.6)**: پوشش گیاهی متوسط
+ - **مقادیر پایین (-1.0 تا 0.2)**: پوشش گیاهی کم یا خاک لخت
+
+ فرمول: NDVI = (NIR - RED) / (NIR + RED)
+ """)
+
+ with st.expander("شاخص رطوبت (NDMI)", expanded=selected_layer == "NDMI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده رطوبت (NDMI)** برای ارزیابی محتوای رطوبت گیاهان استفاده میشود.
+
+ - **مقادیر بالا (0.4 تا 1.0)**: محتوای رطوبت بالا
+ - **مقادیر متوسط (0.0 تا 0.4)**: محتوای رطوبت متوسط
+ - **مقادیر پایین (-1.0 تا 0.0)**: محتوای رطوبت کم
+
+ فرمول: NDMI = (NIR - SWIR) / (NIR + SWIR)
+ """)
+
+ with st.expander("شاخص پیشرفته گیاهی (EVI)", expanded=selected_layer == "EVI"):
+ st.markdown("""
+ **شاخص پیشرفته پوشش گیاهی (EVI)** نسخه بهبودیافته NDVI است که حساسیت کمتری به اثرات خاک و اتمسفر دارد.
+
+ - **مقادیر بالا (0.4 تا 1.0)**: پوشش گیاهی متراکم و سالم
+ - **مقادیر متوسط (0.2 تا 0.4)**: پوشش گیاهی متوسط
+ - **مقادیر پایین (0.0 تا 0.2)**: پوشش گیاهی کم
+
+ فرمول: EVI = 2.5 * ((NIR - RED) / (NIR + 6*RED - 7.5*BLUE + 1))
+ """)
+
+ with st.expander("شاخص آب (NDWI)", expanded=selected_layer == "NDWI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده آب (NDWI)** برای شناسایی پهنههای آبی و ارزیابی محتوای آب در گیاهان استفاده میشود.
+
+ - **مقادیر بالا (0.3 تا 1.0)**: پهنههای آبی
+ - **مقادیر متوسط (0.0 تا 0.3)**: محتوای آب متوسط
+ - **مقادیر پایین (-1.0 تا 0.0)**: محتوای آب کم یا خاک خشک
+
+ فرمول: NDWI = (GREEN - NIR) / (GREEN + NIR)
+ """)
+
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col2:
+ # Create tabs for map and statistics
+ map_tab, stats_tab = st.tabs(["نقشه", "آمار و تحلیل"])
+
+ with map_tab:
+ st.markdown('
', unsafe_allow_html=True)
+
+ if generate_map or 'last_map' not in st.session_state:
+ with st.spinner('در حال تولید نقشه...'):
+ # Create the map
+ m = create_ee_map(
+ selected_farm,
+ selected_date.strftime('%Y-%m-%d'),
+ selected_layer
+ )
+
+ if m:
+ st.session_state.last_map = m
+ folium_static(m, width=800, height=600)
+
+ # Add a success message
+ st.success(f"نقشه {selected_layer} برای مزرعه {selected_farm} با موفقیت تولید شد.")
+ else:
+ st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.")
+ elif 'last_map' in st.session_state:
+ folium_static(st.session_state.last_map, width=800, height=600)
+
+ st.markdown('
', unsafe_allow_html=True)
+
+ # Add a note about the map
+ st.info("""
+ **نکته:** این نقشه بر اساس تصاویر ماهوارهای Sentinel-2 تولید شده است.
+ برای دقت بیشتر، تاریخی را انتخاب کنید که ابرناکی کمتری داشته باشد.
+ """)
+
+ with stats_tab:
+ if 'last_map' in st.session_state:
+ # Calculate statistics for the selected farm and layer
+ stats = calculate_farm_stats(selected_farm, selected_layer)
+
+ # Display statistics in cards
+ col1, col2, col3, col4 = st.columns(4)
+
+ with col1:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["mean"]}
', unsafe_allow_html=True)
+ st.markdown(f'
میانگین {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col2:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["max"]}
', unsafe_allow_html=True)
+ st.markdown(f'
حداکثر {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col3:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["min"]}
', unsafe_allow_html=True)
+ st.markdown(f'
حداقل {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col4:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["std_dev"]}
', unsafe_allow_html=True)
+ st.markdown(f'
انحراف معیار
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ # Create a histogram of values
+ fig = px.histogram(
+ x=stats["histogram_data"],
+ nbins=20,
+ title=f"توزیع مقادیر {selected_layer} در مزرعه {selected_farm}",
+ labels={"x": f"مقدار {selected_layer}", "y": "فراوانی"},
+ color_discrete_sequence=["#1a8754"]
+ )
+
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ bargap=0.1
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ # Add a time series analysis
+ st.markdown("### تحلیل زمانی")
+
+ # Generate mock time series data
+ dates = pd.date_range(end=selected_date, periods=30, freq='D')
+ values = np.random.normal(stats["mean"], stats["std_dev"] / 2, 30)
+ values = np.clip(values, stats["min"], stats["max"])
+
+ # Create a time series chart
+ fig = px.line(
+ x=dates,
+ y=values,
+ title=f"روند تغییرات {selected_layer} در 30 روز گذشته",
+ labels={"x": "تاریخ", "y": f"مقدار {selected_layer}"},
+ markers=True
+ )
+
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ hovermode="x unified"
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ # Add a comparison with other farms
+ st.markdown("### مقایسه با سایر مزارع")
+
+ # Generate mock comparison data
+ farm_names = coordinates مقایسه با سایر مزارع")
+
+ # Generate mock comparison data
+ farm_names = coordinates_df['نام'].tolist()[:5] # Get 5 farm names for comparison
+ comparison_values = [stats["mean"] + np.random.uniform(-0.2, 0.2) for _ in range(len(farm_names))]
+
+ # Create a comparison bar chart
+ fig = px.bar(
+ x=farm_names,
+ y=comparison_values,
+ title=f"مقایسه {selected_layer} بین مزارع",
+ labels={"x": "مزرعه", "y": f"مقدار {selected_layer}"},
+ color=comparison_values,
+ color_continuous_scale="Viridis"
+ )
+
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ coloraxis_showscale=False
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.warning("لطفاً ابتدا یک نقشه تولید کنید.")
+
+# Data Entry Page
+elif selected == "ورود اطلاعات":
+ st.markdown("## ورود اطلاعات روزانه مزارع")
+
+ # Create tabs for manual entry and file upload
+ tab1, tab2 = st.tabs(["ورود دستی", "آپلود فایل"])
+
+ with tab1:
+ # Create filters for week and day
+ col1, col2 = st.columns(2)
+
+ with col1:
+ selected_week = st.selectbox(
+ "انتخاب هفته",
+ options=[str(i) for i in range(1, 23)],
+ format_func=lambda x: f"هفته {x}"
+ )
+
+ with col2:
+ selected_day = st.selectbox(
+ "انتخاب روز",
+ options=["شنبه", "یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه"]
+ )
+
+ # Filter farms by selected day
+ filtered_farms = farm_df[farm_df['روز'] == selected_day]
+
+ if filtered_farms.empty:
+ st.warning(f"هیچ مزرعهای برای روز {selected_day} در پایگاه داده وجود ندارد.")
+ else:
+ # Create a data editor
+ st.markdown("### ورود دادههای مزارع")
+
+ # Initialize data if not already in session state
+ data_key = f"data_{selected_week}_{selected_day}"
+ if data_key not in st.session_state:
+ st.session_state[data_key] = pd.DataFrame({
+ 'مزرعه': filtered_farms['مزرعه'],
+ 'ایستگاه 1': [0] * len(filtered_farms),
+ 'ایستگاه 2': [0] * len(filtered_farms),
+ 'ایستگاه 3': [0] * len(filtered_farms),
+ 'ایستگاه 4': [0] * len(filtered_farms),
+ 'ایستگاه 5': [0] * len(filtered_farms),
+ 'چاهک 1': [0] * len(filtered_farms),
+ 'چاهک 2': [0] * len(filtered_farms),
+ 'رطوبت غلاف': [0] * len(filtered_farms),
+ 'نیتروژن': [0] * len(filtered_farms),
+ 'میانگین ارتفاع': [0] * len(filtered_farms)
+ })
+
+ # Create a data editor
+ edited_df = st.data_editor(
+ st.session_state[data_key],
+ use_container_width=True,
+ num_rows="fixed",
+ column_config={
+ "مزرعه": st.column_config.TextColumn("مزرعه", disabled=True),
+ "ایستگاه 1": st.column_config.NumberColumn("ایستگاه 1", min_value=0, max_value=300, step=1),
+ "ایستگاه 2": st.column_config.NumberColumn("ایستگاه 2", min_value=0, max_value=300, step=1),
+ "ایستگاه 3": st.column_config.NumberColumn("ایستگاه 3", min_value=0, max_value=300, step=1),
+ "ایستگاه 4": st.column_config.NumberColumn("ایستگاه 4", min_value=0, max_value=300, step=1),
+ "ایستگاه 5": st.column_config.NumberColumn("ایستگاه 5", min_value=0, max_value=300, step=1),
+ "چاهک 1": st.column_config.NumberColumn("چاهک 1", min_value=0, max_value=300, step=1),
+ "چاهک 2": st.column_config.NumberColumn("چاهک 2", min_value=0, max_value=300, step=1),
+ "رطوبت غلاف": st.column_config.NumberColumn("رطوبت غلاف", min_value=0, max_value=100, step=1),
+ "نیتروژن": st.column_config.NumberColumn("نیتروژن", min_value=0, max_value=100, step=1),
+ "میانگین ارتفاع": st.column_config.NumberColumn("میانگین ارتفاع", disabled=True),
+ },
+ hide_index=True
+ )
+
+ # Calculate average height
+ for i in range(len(edited_df)):
+ stations = [
+ edited_df.iloc[i]['ایستگاه 1'],
+ edited_df.iloc[i]['ایستگاه 2'],
+ edited_df.iloc[i]['ایستگاه 3'],
+ edited_df.iloc[i]['ایستگاه 4'],
+ edited_df.iloc[i]['ایستگاه 5']
+ ]
+ valid_stations = [s for s in stations if s > 0]
+ if valid_stations:
+ edited_df.iloc[i, edited_df.columns.get_loc('میانگین ارتفاع')] = round(sum(valid_stations) / len(valid_stations), 1)
+
+ # Update session state
+ st.session_state[data_key] = edited_df
+
+ # Save button
+ if st.button("ذخیره اطلاعات", type="primary", use_container_width=True):
+ # This would normally save to a database
+ # For demo purposes, we'll just show a success message
+
+ # Add data to heights_df
+ new_data = edited_df.copy()
+ new_data['Farm_ID'] = new_data['مزرعه']
+ new_data['Week'] = int(selected_week)
+ new_data['Measurement_Date'] = (datetime.now() - timedelta(weeks=(22 - int(selected_week)))).strftime('%Y-%m-%d')
+ new_data['Height'] = new_data['میانگین ارتفاع']
+ new_data['Station1'] = new_data['ایستگاه 1']
+ new_data['Station2'] = new_data['ایستگاه 2']
+ new_data['Station3'] = new_data['ایستگاه 3']
+ new_data['Station4'] = new_data['ایستگاه 4']
+ new_data['Station5'] = new_data['ایستگاه 5']
+ new_data['Groundwater1'] = new_data['چاهک 1']
+ new_data['Groundwater2'] = new_data['چاهک 2']
+ new_data['Sheath_Moisture'] = new_data['رطوبت غلاف']
+ new_data['Nitrogen'] = new_data['نیتروژن']
+
+ # Merge with farm_df to get additional info
+ new_data = new_data.merge(
+ farm_df[['مزرعه', 'واریته', 'سن', 'مساحت', 'کانال', 'اداره']],
+ left_on='Farm_ID',
+ right_on='مزرعه',
+ how='left'
+ )
+
+ # Rename columns
+ new_data = new_data.rename(columns={
+ 'واریته': 'Variety',
+ 'سن': 'Age',
+ 'مساحت': 'Area',
+ 'کانال': 'Channel',
+ 'اداره': 'Administration'
+ })
+
+ # Add to heights_df
+ st.session_state.heights_df = pd.concat([st.session_state.heights_df, new_data], ignore_index=True)
+
+ # Show success message
+ st.success(f"دادههای هفته {selected_week} بر��ی روز {selected_day} با موفقیت ذخیره شدند.")
+ st.balloons()
+
+ with tab2:
+ st.markdown("### آپلود فایل اکسل")
+
+ # Create a file uploader
+ uploaded_file = st.file_uploader("فایل اکسل خود را آپلود کنید", type=["xlsx", "xls", "csv"])
+
+ if uploaded_file is not None:
+ try:
+ # Read the file
+ if uploaded_file.name.endswith('.csv'):
+ df = pd.read_csv(uploaded_file)
+ else:
+ df = pd.read_excel(uploaded_file)
+
+ # Display the data
+ st.dataframe(df, use_container_width=True)
+
+ # Save button
+ if st.button("ذخیره فایل", type="primary"):
+ # This would normally save to a database
+ # For demo purposes, we'll just show a success message
+ st.success("فایل با موفقیت ذخیره شد.")
+ st.balloons()
+ except Exception as e:
+ st.error(f"خطا در خواندن فایل: {e}")
+
+ # Add instructions
+ st.markdown("### راهنمای فرمت فایل")
+ st.markdown("""
+ فایل اکسل باید شامل ستونهای زیر باشد:
+
+ - مزرعه
+ - ایستگاه 1 تا 5
+ - چاهک 1 و 2
+ - رطوبت غلاف
+ - نیتروژن
+
+ میتوانید از [این فایل نمونه](https://example.com/sample.xlsx) به عنوان الگو استفاده کنید.
+ """)
+
+ # Add a drag and drop area
+ st.markdown("""
+
+
+
فایل خود را اینجا رها کنید یا روی دکمه بالا کلیک کنید
', unsafe_allow_html=True)
+ else:
+ st.warning("دادههای مختصات در دسترس نیست.")
+
+ with tab3:
+ st.markdown("### نمودار رشد هفتگی")
+
+ # Create filters for variety and age
+ col1, col2 = st.columns(2)
+ with col1:
+ selected_variety = st.selectbox(
+ "انتخاب واریته",
+ ["all"] + list(farm_df['واریته'].unique()),
+ format_func=lambda x: "همه واریتهها" if x == "all" else x
+ )
+
+ with col2:
+ selected_age = st.selectbox(
+ "انتخاب سن",
+ ["all"] + list(farm_df['سن'].unique()),
+ format_func=lambda x: "همه سنین" if x == "all" else x
+ )
+
+ # Generate mock growth data
+ growth_data = generate_mock_growth_data(farm_df, selected_variety, selected_age)
+
+ # Create tabs for average and individual growth charts
+ chart_tab1, chart_tab2 = st.tabs(["میانگین رشد", "رشد مزارع فردی"])
+
+ with chart_tab1:
+ # Create average growth chart
+ avg_data = growth_data['average']
+ fig = go.Figure()
+ fig.add_trace(go.Scatter(
+ x=avg_data['weeks'],
+ y=avg_data['heights'],
+ mode='lines+markers',
+ name='میانگین رشد',
+ line=dict(color='#1a8754', width=3),
+ marker=dict(size=8, color='#1a8754')
+ ))
+
+ fig.update_layout(
+ title='میانگین رشد هفتگی',
+ xaxis_title='هفته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family='Vazirmatn', size=14),
+ hovermode='x unified',
+ template='plotly_white',
+ height=500
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ with chart_tab2:
+ # Create individual growth chart
+ if growth_data['individual']:
+ fig = go.Figure()
+
+ # Only show up to 5 farms to avoid clutter
+ colors = ['#1a8754', '#1976d2', '#e65100', '#9c27b0', '#d32f2f']
+ for i, farm_data in enumerate(growth_data['individual'][:5]):
+ fig.add_trace(go.Scatter(
+ x=farm_data['weeks'],
+ y=farm_data['heights'],
+ mode='lines+markers',
+ name=f"مزرعه {farm_data['farm_id']}",
+ line=dict(color=colors[i % len(colors)], width=2),
+ marker=dict(size=6, color=colors[i % len(colors)])
+ ))
+
+ fig.update_layout(
+ title='رشد هفتگی مزارع فردی',
+ xaxis_title='هفته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family='Vazirmatn', size=14),
+ hovermode='x unified',
+ template='plotly_white',
+ height=500
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.warning("دادهای برای نمایش وجود ندارد.")
+
+ with tab4:
+ st.markdown("### دادههای مزارع")
+
+ # Create a search box
+ search_term = st.text_input("جستجو در دادهها", placeholder="نام مزرعه، واریته، سن و...")
+
+ # Filter data based on search term
+ if search_term:
+ filtered_df = farm_df[
+ farm_df['مزرعه'].astype(str).str.contains(search_term) |
+ farm_df['واریته'].astype(str).str.contains(search_term) |
+ farm_df['سن'].astype(str).str.contains(search_term) |
+ farm_df['کانال'].astype(str).str.contains(search_term)
+ ]
+ else:
+ filtered_df = farm_df
+
+ # Display data table with pagination
+ if not filtered_df.empty:
+ # Add a download button
+ csv = filtered_df.to_csv(index=False).encode('utf-8')
+ st.download_button(
+ label="دانلود دادهها (CSV)",
+ data=csv,
+ file_name="farm_data.csv",
+ mime="text/csv",
+ )
+
+ # Display the data table
+ st.dataframe(
+ filtered_df,
+ use_container_width=True,
+ height=400,
+ hide_index=True
+ )
+
+ st.info(f"نمایش {len(filtered_df)} مزرعه از {len(farm_df)} مزرعه")
+ else:
+ st.warning("هیچ دادهای یافت نشد.")
+
+# Map Page
+elif selected == "نقشه مزارع":
+ st.markdown("## نقشه مزارع با شاخصهای ماهوارهای")
+
+ # Create a layout with sidebar for controls
+ col1, col2 = st.columns([1, 3])
+
+ with col1:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown("### تنظیمات نقشه")
+
+ # Farm selection
+ selected_farm = st.selectbox(
+ "انتخاب مزرعه",
+ options=coordinates_df['نام'].tolist(),
+ index=0,
+ format_func=lambda x: f"مزرعه {x}"
+ )
+
+ # Date selection
+ selected_date = st.date_input(
+ "انتخاب تاریخ",
+ value=datetime.now(),
+ format="YYYY-MM-DD"
+ )
+
+ # Layer type selection
+ selected_layer = st.selectbox(
+ "انتخاب شاخص",
+ options=["NDVI", "NDMI", "EVI", "NDWI"],
+ format_func=lambda x: {
+ "NDVI": "شاخص پوشش گیاهی (NDVI)",
+ "NDMI": "شاخص رطوبت (NDMI)",
+ "EVI": "شاخص پیشرفته گیاهی (EVI)",
+ "NDWI": "شاخص آب (NDWI)"
+ }[x]
+ )
+
+ # Generate map button
+ generate_map = st.button(
+ "تولید نقشه",
+ type="primary",
+ use_container_width=True
+ )
+
+ # Add a separator
+ st.markdown('', unsafe_allow_html=True)
+
+ # Add index descriptions
+ st.markdown("### راهنمای شاخصها")
+
+ with st.expander("شاخص پوشش گیاهی (NDVI)", expanded=selected_layer == "NDVI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده پوشش گیاهی (NDVI)** معیاری برای سنجش سلامت و تراکم پوشش گیاهی است.
+
+ - **مقادیر بالا (0.6 تا 1.0)**: پوشش گیاهی متراکم و سالم
+ - **مقادیر متوسط (0.2 تا 0.6)**: پوشش گیاهی متوسط
+ - **مقادیر پایین (-1.0 تا 0.2)**: پوشش گیاهی کم یا خاک لخت
+
+ فرمول: NDVI = (NIR - RED) / (NIR + RED)
+ """)
+
+ with st.expander("شاخص رطوبت (NDMI)", expanded=selected_layer == "NDMI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده رطوبت (NDMI)** برای ارزیابی محتوای رطوبت گیاهان استفاده میشود.
+
+ - **مقادیر بالا (0.4 تا 1.0)**: محتوای رطوبت بالا
+ - **مقادیر متوسط (0.0 تا 0.4)**: محتوای رطوبت متوسط
+ - **مقادیر پایین (-1.0 تا 0.0)**: محتوای رطوبت کم
+
+ فرمول: NDMI = (NIR - SWIR) / (NIR + SWIR)
+ """)
+
+ with st.expander("شاخص پیشرفته گیاهی (EVI)", expanded=selected_layer == "EVI"):
+ st.markdown("""
+ **شاخص پیشرفته پوشش گیاهی (EVI)** نسخه بهبودیافته NDVI است که حساسیت کمتری به اثرات خاک و اتمسفر دارد.
+
+ - **مقادیر بالا (0.4 تا 1.0)**: پوشش گیاهی متراکم و سالم
+ - **مقادیر متوسط (0.2 تا 0.4)**: پوشش گیاهی متوسط
+ - **مقادیر پایین (0.0 تا 0.2)**: پوشش گیاهی کم
+
+ فرمول: EVI = 2.5 * ((NIR - RED) / (NIR + 6*RED - 7.5*BLUE + 1))
+ """)
+
+ with st.expander("شاخص آب (NDWI)", expanded=selected_layer == "NDWI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده آب (NDWI)** برای شناسایی پهنههای آبی و ارزیابی محتوای آب در گیاهان استفاده میشود.
+
+ - **مقادیر بالا (0.3 تا 1.0)**: پهنههای آبی
+ - **مقادیر متوسط (0.0 تا 0.3)**: محتوای آب متوسط
+ - **مقادیر پایین (-1.0 تا 0.0)**: محتوای آب کم یا خاک خشک
+
+ فرمول: NDWI = (GREEN - NIR) / (GREEN + NIR)
+ """)
+
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col2:
+ # Create tabs for map and statistics
+ map_tab, stats_tab = st.tabs(["نقشه", "آمار و تحلیل"])
+
+ with map_tab:
+ st.markdown('
', unsafe_allow_html=True)
+
+ if generate_map or 'last_map' not in st.session_state:
+ with st.spinner('در حال تولید نقشه...'):
+ # Create the map
+ m = create_ee_map(
+ selected_farm,
+ selected_date.strftime('%Y-%m-%d'),
+ selected_layer
+ )
+
+ if m:
+ st.session_state.last_map = m
+ folium_static(m, width=800, height=600)
+
+ # Add a success message
+ st.success(f"نقشه {selected_layer} برای مزرعه {selected_farm} با موفقیت تولید شد.")
+ else:
+ st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.")
+ elif 'last_map' in st.session_state:
+ folium_static(st.session_state.last_map, width=800, height=600)
+
+ st.markdown('
', unsafe_allow_html=True)
+
+ # Add a note about the map
+ st.info("""
+ **نکته:** این نقشه بر اساس تصاویر ماهوارهای Sentinel-2 تولید شده است.
+ برای دقت بیشتر، تاریخی را انتخاب کنید که ابرناکی کمتری داشته باشد.
+ """)
+
+ with stats_tab:
+ if 'last_map' in st.session_state:
+ # Calculate statistics for the selected farm and layer
+ stats = calculate_farm_stats(selected_farm, selected_layer)
+
+ # Display statistics in cards
+ col1, col2, col3, col4 = st.columns(4)
+
+ with col1:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["mean"]}
', unsafe_allow_html=True)
+ st.markdown(f'
میانگین {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col2:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["max"]}
', unsafe_allow_html=True)
+ st.markdown(f'
حداکثر {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col3:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["min"]}
', unsafe_allow_html=True)
+ st.markdown(f'
حداقل {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col4:
+ st.markdown('
', unsafe_allow_html=True)
+ st.markdown(f'
{stats["std_dev"]}
', unsafe_allow_html=True)
+ st.markdown(f'
انحراف معیار
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ # Create a histogram of values
+ fig = px.histogram(
+ x=stats["histogram_data"],
+ nbins=20,
+ title=f"توزیع مقادیر {selected_layer} در مزرعه {selected_farm}",
+ labels={"x": f"مقدار {selected_layer}", "y": "فراوانی"},
+ color_discrete_sequence=["#1a8754"]
+ )
+
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ bargap=0.1
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ # Add a time series analysis
+ st.markdown("### تحلیل زمانی")
+
+ # Generate mock time series data
+ dates = pd.date_range(end=selected_date, periods=30, freq='D')
+ values = np.random.normal(stats["mean"], stats["std_dev"] / 2, 30)
+ values = np.clip(values, stats["min"], stats["max"])
+
+ # Create a time series chart
+ fig = px.line(
+ x=dates,
+ y=values,
+ title=f"روند تغییرات {selected_layer} در 30 روز گذشته",
+ labels={"x": "تاریخ", "y": f"مقدار {selected_layer}"},
+ markers=True
+ )
+
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ hovermode="x unified"
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ # Add a comparison with other farms
+ st.markdown("### مقایسه با سایر مزارع")
+
+ # Generate mock comparison data
+ farm_names = coordinates مقایسه با سایر مزارع")
+
+ # Generate mock comparison data
+ farm_names = coordinates_df['نام'].tolist()[:5] # Get 5 farm names for comparison
+ comparison_values = [stats["mean"] + np.random.uniform(-0.2, 0.2) for _ in range(len(farm_names))]
+
+ # Create a comparison bar chart
+ fig = px.bar(
+ x=farm_names,
+ y=comparison_values,
+ title=f"مقایسه {selected_layer} بین مزارع",
+ labels={"x": "مزرعه", "y": f"مقدار {selected_layer}"},
+ color=comparison_values,
+ color_continuous_scale="Viridis"
+ )
+
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ coloraxis_showscale=False
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.warning("لطفاً ابتدا یک نقشه تولید کنید.")
+
+# Data Entry Page
+elif selected == "ورود اطلاعات":
+ st.markdown("## ورود اطلاعات روزانه مزارع")
+
+ # Create tabs for manual entry and file upload
+ tab1, tab2 = st.tabs(["ورود دستی", "آپلود فایل"])
+
+ with tab1:
+ # Create filters for week and day
+ col1, col2 = st.columns(2)
+
+ with col1:
+ selected_week = st.selectbox(
+ "انتخاب هفته",
+ options=[str(i) for i in range(1, 23)],
+ format_func=lambda x: f"هفته {x}"
+ )
+
+ with col2:
+ selected_day = st.selectbox(
+ "انتخاب روز",
+ options=["شنبه", "یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه"]
+ )
+
+ # Filter farms by selected day
+ filtered_farms = farm_df[farm_df['روز'] == selected_day]
+
+ if filtered_farms.empty:
+ st.warning(f"هیچ مزرعهای برای روز {selected_day} در پایگاه داده وجود ندارد.")
+ else:
+ # Create a data editor
+ st.markdown("### ورود دادههای مزارع")
+
+ # Initialize data if not already in session state
+ data_key = f"data_{selected_week}_{selected_day}"
+ if data_key not in st.session_state:
+ st.session_state[data_key] = pd.DataFrame({
+ 'مزرعه': filtered_farms['مزرعه'],
+ 'ایستگاه 1': [0] * len(filtered_farms),
+ 'ایستگاه 2': [0] * len(filtered_farms),
+ 'ایستگاه 3': [0] * len(filtered_farms),
+ 'ایستگاه 4': [0] * len(filtered_farms),
+ 'ایستگاه 5': [0] * len(filtered_farms),
+ 'چاهک 1': [0] * len(filtered_farms),
+ 'چاهک 2': [0] * len(filtered_farms),
+ 'رطوبت غلاف': [0] * len(filtered_farms),
+ 'نیتروژن': [0] * len(filtered_farms),
+ 'میانگین ارتفاع': [0] * len(filtered_farms)
+ })
+
+ # Create a data editor
+ edited_df = st.data_editor(
+ st.session_state[data_key],
+ use_container_width=True,
+ num_rows="fixed",
+ column_config={
+ "مزرعه": st.column_config.TextColumn("مزرعه", disabled=True),
+ "ایستگاه 1": st.column_config.NumberColumn("ایستگاه 1", min_value=0, max_value=300, step=1),
+ "ایستگاه 2": st.column_config.NumberColumn("ایستگاه 2", min_value=0, max_value=300, step=1),
+ "ایستگاه 3": st.column_config.NumberColumn("ایستگاه 3", min_value=0, max_value=300, step=1),
+ "ایستگاه 4": st.column_config.NumberColumn("ایستگاه 4", min_value=0, max_value=300, step=1),
+ "ایستگاه 5": st.column_config.NumberColumn("ایستگاه 5", min_value=0, max_value=300, step=1),
+ "چاهک 1": st.column_config.NumberColumn("چاهک 1", min_value=0, max_value=300, step=1),
+ "چاهک 2": st.column_config.NumberColumn("چاهک 2", min_value=0, max_value=300, step=1),
+ "رطوبت غلاف": st.column_config.NumberColumn("رطوبت غلاف", min_value=0, max_value=100, step=1),
+ "نیتروژن": st.column_config.NumberColumn("نیتروژن", min_value=0, max_value=100, step=1),
+ "میانگین ارتفاع": st.column_config.NumberColumn("میانگین ارتفاع", disabled=True),
+ },
+ hide_index=True
+ )
+
+ # Calculate average height
+ for i in range(len(edited_df)):
+ stations = [
+ edited_df.iloc[i]['ایستگاه 1'],
+ edited_df.iloc[i]['ایستگاه 2'],
+ edited_df.iloc[i]['ایستگاه 3'],
+ edited_df.iloc[i]['ایستگاه 4'],
+ edited_df.iloc[i]['ایستگاه 5']
+ ]
+ valid_stations = [s for s in stations if s > 0]
+ if valid_stations:
+ edited_df.iloc[i, edited_df.columns.get_loc('میانگین ارتفاع')] = round(sum(valid_stations) / len(valid_stations), 1)
+
+ # Update session state
+ st.session_state[data_key] = edited_df
+
+ # Save button
+ if st.button("ذخیره اطلاعات", type="primary", use_container_width=True):
+ # This would normally save to a database
+ # For demo purposes, we'll just show a success message
+
+ # Add data to heights_df
+ new_data = edited_df.copy()
+ new_data['Farm_ID'] = new_data['مزرعه']
+ new_data['Week'] = int(selected_week)
+ new_data['Measurement_Date'] = (datetime.now() - timedelta(weeks=(22 - int(selected_week)))).strftime('%Y-%m-%d')
+ new_data['Height'] = new_data['میانگین ارتفاع']
+ new_data['Station1'] = new_data['ایستگاه 1']
+ new_data['Station2'] = new_data['ایستگاه 2']
+ new_data['Station3'] = new_data['ایستگاه 3']
+ new_data['Station4'] = new_data['ایستگاه 4']
+ new_data['Station5'] = new_data['ایستگاه 5']
+ new_data['Groundwater1'] = new_data['چاهک 1']
+ new_data['Groundwater2'] = new_data['چاهک 2']
+ new_data['Sheath_Moisture'] = new_data['رطوبت غلاف']
+ new_data['Nitrogen'] = new_data['نیتروژن']
+
+ # Merge with farm_df to get additional info
+ new_data = new_data.merge(
+ farm_df[['مزرعه', 'واریته', 'سن', 'مساحت', 'کانال', 'اداره']],
+ left_on='Farm_ID',
+ right_on='مزرعه',
+ how='left'
+ )
+
+ # Rename columns
+ new_data = new_data.rename(columns={
+ 'واریته': 'Variety',
+ 'سن': 'Age',
+ 'مساحت': 'Area',
+ 'کانال': 'Channel',
+ 'اداره': 'Administration'
+ })
+
+ # Add to heights_df
+ st.session_state.heights_df = pd.concat([st.session_state.heights_df, new_data], ignore_index=True)
+
+ # Show success message
+ st.success(f"دادههای هفته {selected_week} برای روز {selected_day} با موفقیت ذخیره شدند.")
+ st.balloons()
+
+ with tab2:
+ st.markdown("### آپلود فایل اکسل")
+
+ # Create a file uploader
+ uploaded_file = st.file_uploader("فایل اکسل خود را آپلود کنید", type=["xlsx", "xls", "csv"])
+
+ if uploaded_file is not None:
+ try:
+ # Read the file
+ if uploaded_file.name.endswith('.csv'):
+ df = pd.read_csv(uploaded_file)
+ else:
+ df = pd.read_excel(uploaded_file)
+
+ # Display the data
+ st.dataframe(df, use_container_width=True)
+
+ # Save button
+ if st.button("ذخیره فایل", type="primary"):
+ # This would normally save to a database
+ # For demo purposes, we'll just show a success message
+ st.success("فایل با موفقیت ذخیره شد.")
+ st.balloons()
+ except Exception as e:
+ st.error(f"خطا در خواندن فایل: {e}")
+
+ # Add instructions
+ st.markdown("### راهنمای فرمت فایل")
+ st.markdown("""
+ فایل اکسل باید شامل ستونهای زیر باشد:
+
+ - مزرعه
+ - ایستگاه 1 تا 5
+ - چاهک 1 و 2
+ - رطوبت غلاف
+ - نیتروژن
+
+ میتوانید از [این فایل نمونه](https://example.com/sample.xlsx) به عنوان الگو استفاده کنید.
+ """)
+
+ # Add a drag and drop area
+ st.markdown("""
+
+
+
فایل خود را اینجا رها کنید یا روی دکمه بالا کلیک کنید