diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -27,171 +27,210 @@ from streamlit_extras.add_vertical_space import add_vertical_space from streamlit_card import card import pydeck as pdk import math +from sklearn.linear_model import LinearRegression # Page configuration with custom theme st.set_page_config( page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا", - page_icon="🌿", + page_icon="🌱", layout="wide", initial_sidebar_state="expanded" ) -# Custom CSS with modern design and animations +# Custom CSS with modern, stunning design st.markdown(""" """, unsafe_allow_html=True) +# Load real farm data from CSV +@st.cache_data +def load_farm_data(): + try: + df = pd.read_csv("کراپ لاگ کلی (1).csv") + # Print columns for verification + st.write("ستون‌های موجود در فایل:", df.columns.tolist()) + # Rename columns for consistency with the program + df.rename(columns={ + 'سال': 'Year', + 'هفته': 'Week', + 'مزرعه': 'Farm_ID', + 'کانال': 'Channel', + 'اداره': 'Administration', + 'مساحت': 'Area', + 'مساحت زیر مجموعه': 'SubArea', + 'رقم': 'Variety', + 'سن': 'Age', + 'ایستگاه 1': 'Station1', + 'ایستگاه 2': 'Station2', + 'ایستگاه 3': 'Station3', + 'ایستگاه 4': 'Station4', + 'ایستگاه 5': 'Station5', + 'ارتفاع هفته جاری مزرعه': 'CurrentHeight', + 'ارتفاع هفته گذشته مزرعه': 'PreviousHeight', + 'رشد هفته جاری': 'CurrentGrowth', + 'رشد هفته گذشته': 'PreviousGrowth', + 'نیتروژن فعلی': 'CurrentNitrogen', + 'نیتروژن استاندارد فعلی': 'StandardNitrogen', + 'نیتروژن قبلی': 'PreviousNitrogen', + 'نیتروژن استاندارد قبلی': 'PreviousStandardNitrogen', + 'رطوبت': 'CurrentMoisture', # به‌جای رطوبت غلاف فعلی + 'رطوبت استاندارد فعلی': 'StandardMoisture', + 'رطوبت': 'PreviousMoisture', # به‌جای رطوبت غلاف قبلی (فرض می‌کنم در یک ستون تکراری باشد) + 'رطوبت استاندارد قبلی': 'PreviousStandardMoisture', + 'چاهک 1': 'Well1', + 'تاریخ قرائت': 'Well1Date', + 'چاهک 2': 'Well2', + 'تاریخ قرائت.1': 'Well2Date' + }, inplace=True, errors='ignore') + return df + except Exception as e: + st.error(f"خطا در بارگذاری داده‌های مزارع: {e}") + return pd.DataFrame() + +@st.cache_data +def load_coordinates_data(): + try: + coords_df = pd.read_csv("farm_coordinates.csv") + coords_df.rename(columns={ + 'مزرعه': 'Farm_ID', + 'عرض جغرافیایی': 'Latitude', + 'طول جغرافیایی': 'Longitude' + }, inplace=True, errors='ignore') + return coords_df + except Exception as e: + st.error(f"خطا در بارگذاری داده‌های مختصات: {e}") + return pd.DataFrame() + +@st.cache_data +def load_day_data(): + try: + day_df = pd.read_csv("پایگاه داده (1).csv") + day_df.rename(columns={ + 'سال': 'Year', # فرض شده برای سازگاری + 'هفته': 'Week', # فرض شده برای سازگاری + 'مزرعه': 'Farm_ID', + 'روز': 'Day' + }, inplace=True, errors='ignore') + return day_df + except Exception as e: + st.error(f"خطا در بارگذاری داده‌های روزهای هفته: {e}") + return pd.DataFrame() + +# Load animation JSON +@st.cache_data +def load_lottie_url(url: str): + r = requests.get(url) + if r.status_code != 200: + return None + return r.json() + # Initialize Earth Engine @st.cache_resource def initialize_earth_engine(): try: - # Load Earth Engine credentials from the provided JSON service_account = 'dehkhodamap-e9f0da4ce9f6514021@ee-esmaeilkiani13877.iam.gserviceaccount.com' - - # Create a JSON file with the credentials credentials_dict = { "type": "service_account", "project_id": "ee-esmaeilkiani13877", @@ -468,78 +640,32 @@ def initialize_earth_engine(): "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/dehkhodamap-e9f0da4ce9f6514021%40ee-esmaeilkiani13877.iam.gserviceaccount.com", "universe_domain": "googleapis.com" } - - # Save credentials to a temporary file credentials_file = 'ee-esmaeilkiani13877-cfdea6eaf411.json' with open(credentials_file, 'w') as f: json.dump(credentials_dict, f) - - # Initialize Earth Engine with the credentials credentials = ee.ServiceAccountCredentials(service_account, credentials_file) ee.Initialize(credentials) - - # Remove the temporary file os.remove(credentials_file) - return True except Exception as e: st.error(f"خطا در اتصال به Earth Engine: {e}") return False - -# Load data -@st.cache_data -def load_farm_data(): - try: - df = pd.read_csv("پایگاه داده (1).csv") - return df - except Exception as e: - st.error(f"خطا در بارگذاری داده‌های مزارع: {e}") - return pd.DataFrame() - -@st.cache_data -def load_coordinates_data(): - try: - df = pd.read_csv("farm_coordinates.csv") - return df - except Exception as e: - st.error(f"خطا در بارگذاری داده‌های مختصات: {e}") - return pd.DataFrame() - -# Load animation JSON -@st.cache_data -def load_lottie_url(url: str): - r = requests.get(url) - if r.status_code != 200: - return None - return r.json() - # Create Earth Engine map with indices def create_ee_map(farm_id, date_str, layer_type="NDVI"): try: - # Get farm coordinates - farm_row = coordinates_df[coordinates_df['نام'] == farm_id].iloc[0] - lat, lon = farm_row['عرض جغرافیایی'], farm_row['طول جغرافیایی'] - - # Create a folium map centered at the farm + farm_row = coordinates_df[coordinates_df['Farm_ID'] == farm_id].iloc[0] + lat, lon = farm_row['Latitude'], farm_row['Longitude'] m = folium.Map(location=[lat, lon], zoom_start=14, tiles='CartoDB positron') - - # Parse date and create a date range date_obj = datetime.strptime(date_str, '%Y-%m-%d') start_date = (date_obj - timedelta(days=5)).strftime('%Y-%m-%d') end_date = (date_obj + timedelta(days=5)).strftime('%Y-%m-%d') - - # Define the region of interest region = ee.Geometry.Point([lon, lat]).buffer(1500) - - # Get Sentinel-2 imagery s2 = ee.ImageCollection('COPERNICUS/S2_SR') \ .filterDate(start_date, end_date) \ .filterBounds(region) \ .sort('CLOUDY_PIXEL_PERCENTAGE') \ .first() - - # Calculate the selected index if layer_type == "NDVI": index = s2.normalizedDifference(['B8', 'B4']).rename('NDVI') viz_params = {'min': -0.2, 'max': 0.8, 'palette': ['#ff0000', '#ff4500', '#ffd700', '#32cd32', '#006400']} @@ -559,8 +685,6 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"): index = s2.normalizedDifference(['B3', 'B8']).rename('NDWI') viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#00008b', '#00b7eb', '#add8e6', '#fdae61', '#d73027']} legend_title = 'شاخص آب (NDWI)' - - # Add the index layer to the map map_id_dict = ee.Image(index).getMapId(viz_params) folium.TileLayer( tiles=map_id_dict['tile_fetcher'].url_format, @@ -569,92 +693,101 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"): overlay=True, control=True ).add_to(m) - - # Add a marker for the farm folium.Marker( [lat, lon], popup=f'مزرعه {farm_id}', tooltip=f'مزرعه {farm_id}', - icon=folium.Icon(color='green', icon='leaf') + icon=folium.Icon(color='green', icon='leaf', prefix='fa') ).add_to(m) - - # Add a circle around the farm folium.Circle( [lat, lon], radius=1500, color='green', fill=True, fill_color='green', - fill_opacity=0.1 + fill_opacity=0.1, + weight=2 ).add_to(m) - - # Add layer control folium.LayerControl().add_to(m) - - # Add a custom legend legend_html = '''
-
''' + legend_title + '''
-
-
- کم + font-family: 'Vazirmatn', sans-serif; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);"> +
''' + legend_title + '''
+
+
+ کم
-
-
- متوسط +
+
+ متوسط
-
- زیاد +
+ زیاد
''' m.get_root().html.add_child(folium.Element(legend_html)) - return m except Exception as e: st.error(f"خطا در ایجاد نقشه: {e}") return None -# Generate mock growth data -def generate_mock_growth_data(farm_data, selected_variety="all", selected_age="all"): - weeks = list(range(1, 23)) - - # Filter farms based on variety and age - filtered_farms = farm_data +# Calculate real farm stats +def calculate_farm_stats(farm_id, layer_type="NDVI"): + farm_data = farm_df[farm_df['Farm_ID'] == farm_id] + if layer_type == "NDVI": + stats = { + 'mean': farm_data['CurrentHeight'].mean() if not farm_data.empty else 0, + 'min': farm_data['CurrentHeight'].min() if not farm_data.empty else 0, + 'max': farm_data['CurrentHeight'].max() if not farm_data.empty else 0, + 'std_dev': farm_data['CurrentHeight'].std() if not farm_data.empty else 0, + 'histogram_data': farm_data['CurrentHeight'].values if not farm_data.empty else np.array([]) + } + elif layer_type == "NDMI": + stats = { + 'mean': farm_data['CurrentMoisture'].mean() if not farm_data.empty else 0, + 'min': farm_data['CurrentMoisture'].min() if not farm_data.empty else 0, + 'max': farm_data['CurrentMoisture'].max() if not farm_data.empty else 0, + 'std_dev': farm_data['CurrentMoisture'].std() if not farm_data.empty else 0, + 'histogram_data': farm_data['CurrentMoisture'].values if not farm_data.empty else np.array([]) + } + return stats + +# Generate real growth data +def generate_real_growth_data(selected_variety="all", selected_age="all"): + filtered_farms = farm_df if selected_variety != "all": - filtered_farms = filtered_farms[filtered_farms['واریته'] == selected_variety] + filtered_farms = filtered_farms[filtered_farms['Variety'] == selected_variety] if selected_age != "all": - filtered_farms = filtered_farms[filtered_farms['سن'] == selected_age] + filtered_farms = filtered_farms[filtered_farms['Age'] == selected_age] - # Generate random growth data for each farm farm_growth_data = [] - for _, farm in filtered_farms.iterrows(): - base_height = np.random.uniform(50, 100) - growth_rate = np.random.uniform(5, 15) - + weeks = filtered_farms['Week'].unique() + for farm_id in filtered_farms['Farm_ID'].unique(): + farm_data = filtered_farms[filtered_farms['Farm_ID'] == farm_id] growth_data = { - 'farm_id': farm['مزرعه'], - 'variety': farm['واریته'], - 'age': farm['سن'], + 'farm_id': farm_id, + 'variety': farm_data['Variety'].iloc[0] if not farm_data.empty else 'Unknown', + 'age': farm_data['Age'].iloc[0] if not farm_data.empty else 'Unknown', 'weeks': weeks, - 'heights': [round(base_height + growth_rate * week) for week in weeks] + 'heights': [farm_data[farm_data['Week'] == week]['CurrentHeight'].mean() if not farm_data[farm_data['Week'] == week].empty else 0 for week in weeks] } farm_growth_data.append(growth_data) - # Calculate average growth data if farm_growth_data: avg_heights = [] for week in weeks: - week_heights = [farm['heights'][week-1] for farm in farm_growth_data] - avg_heights.append(round(sum(week_heights) / len(week_heights))) + week_heights = [farm['heights'][list(weeks).index(week)] for farm in farm_growth_data if farm['heights'][list(weeks).index(week)] > 0] + avg_heights.append(round(sum(week_heights) / len(week_heights)) if week_heights else 0) avg_growth_data = { 'farm_id': 'میانگین', @@ -663,66 +796,17 @@ def generate_mock_growth_data(farm_data, selected_variety="all", selected_age="a 'weeks': weeks, 'heights': avg_heights } - - return { - 'individual': farm_growth_data, - 'average': avg_growth_data - } - else: - return { - 'individual': [], - 'average': { - 'farm_id': 'میانگین', - 'variety': 'همه', - 'age': 'همه', - 'weeks': weeks, - 'heights': [0] * len(weeks) - } - } - -# Calculate statistics for a farm -def calculate_farm_stats(farm_id, layer_type="NDVI"): - # This would normally calculate real statistics from Earth Engine - # For demo purposes, we'll generate mock statistics - if layer_type == "NDVI": - mean = round(np.random.uniform(0.6, 0.8), 2) - min_val = round(mean - np.random.uniform(0.2, 0.3), 2) - max_val = round(mean + np.random.uniform(0.1, 0.2), 2) - std_dev = round(np.random.uniform(0.05, 0.15), 2) - elif layer_type == "NDMI": - mean = round(np.random.uniform(0.3, 0.5), 2) - min_val = round(mean - np.random.uniform(0.2, 0.3), 2) - max_val = round(mean + np.random.uniform(0.1, 0.2), 2) - std_dev = round(np.random.uniform(0.05, 0.15), 2) - elif layer_type == "EVI": - mean = round(np.random.uniform(0.4, 0.6), 2) - min_val = round(mean - np.random.uniform(0.2, 0.3), 2) - max_val = round(mean + np.random.uniform(0.1, 0.2), 2) - std_dev = round(np.random.uniform(0.05, 0.15), 2) - else: # NDWI - mean = round(np.random.uniform(-0.1, 0.1), 2) - min_val = round(mean - np.random.uniform(0.2, 0.3), 2) - max_val = round(mean + np.random.uniform(0.1, 0.2), 2) - std_dev = round(np.random.uniform(0.05, 0.15), 2) - - # Generate histogram data - hist_data = np.random.normal(mean, std_dev, 1000) - hist_data = np.clip(hist_data, min_val, max_val) - + return {'individual': farm_growth_data, 'average': avg_growth_data} return { - 'mean': mean, - 'min': min_val, - 'max': max_val, - 'std_dev': std_dev, - 'histogram_data': hist_data + 'individual': [], + 'average': {'farm_id': 'میانگین', 'variety': 'همه', 'age': 'همه', 'weeks': weeks, 'heights': [0] * len(weeks)} } -# Initialize Earth Engine +# Initialize Earth Engine and load data ee_initialized = initialize_earth_engine() - -# Load data farm_df = load_farm_data() coordinates_df = load_coordinates_data() +day_df = load_day_data() # Load animations lottie_farm = load_lottie_url('https://assets5.lottiefiles.com/packages/lf20_ystsffqy.json') @@ -731,204 +815,205 @@ lottie_report = load_lottie_url('https://assets9.lottiefiles.com/packages/lf20_v # Create session state for storing data if 'heights_df' not in st.session_state: - st.session_state.heights_df = pd.DataFrame(columns=[ - 'Farm_ID', 'Week', 'Measurement_Date', 'Height', 'Station1', 'Station2', 'Station3', - 'Station4', 'Station5', 'Groundwater1', 'Groundwater2', 'Sheath_Moisture', 'Nitrogen', - 'Variety', 'Age', 'Area', 'Channel', 'Administration' - ]) + st.session_state.heights_df = farm_df.copy() -# Main header -st.markdown('
', unsafe_allow_html=True) -st.markdown('

سامانه هوشمند پایش مزارع نیشکر دهخدا

', unsafe_allow_html=True) -st.markdown('

پلتفرم جامع مدیریت، پایش و تحلیل داده‌های مزارع نیشکر با استفاده از تصاویر ماهواره‌ای و هوش مصنوعی

', unsafe_allow_html=True) +# Main header with animation +st.markdown('
', unsafe_allow_html=True) +st.markdown('

سامانه هوشمند پایش مزارع نیشکر دهخدا

', unsafe_allow_html=True) +st.markdown('

پلتفرم جامع مدیریت، پایش و تحلیل داده‌های مزارع نیشکر با هوش مصنوعی پیشرفته

', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) -# Create a modern navigation menu +# Create a stunning navigation menu selected = option_menu( menu_title=None, options=["داشبورد", "نقشه مزارع", "ورود اطلاعات", "تحلیل داده‌ها", "گزارش‌گیری", "تنظیمات"], - icons=["speedometer2", "map", "pencil-square", "graph-up", "file-earmark-text", "gear"], - menu_icon="cast", + icons=["speedometer2", "map", "pencil-square", "bar-chart", "file-text", "gear"], + menu_icon="leaf", default_index=0, orientation="horizontal", styles={ - "container": {"padding": "0!important", "background-color": "transparent", "margin-bottom": "20px"}, - "icon": {"color": "#1a8754", "font-size": "18px"}, - "nav-link": {"font-size": "16px", "text-align": "center", "margin":"0px", "--hover-color": "#e9f7ef", "border-radius": "10px"}, - "nav-link-selected": {"background-color": "#1a8754", "color": "white", "font-weight": "600"}, + "container": {"padding": "0!important", "background-color": "transparent", "margin-bottom": "25px"}, + "icon": {"color": "#2ecc71", "font-size": "22px"}, + "nav-link": {"font-size": "18px", "text-align": "center", "margin": "5px", "--hover-color": "#e9f7ef", "border-radius": "12px"}, + "nav-link-selected": {"background": "linear-gradient(135deg, #2ecc71 0%, #27ae60 100%)", "color": "white", "font-weight": "700", "box-shadow": "0 10px 30px rgba(46, 204, 113, 0.4)"}, } ) # Dashboard if selected == "داشبورد": - # Dashboard metrics + st.markdown('
', unsafe_allow_html=True) + st.markdown("### نمای کلی مزارع", unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) + + # Dashboard metrics with animation col1, col2, col3, col4 = st.columns(4) with col1: - st.markdown('
', unsafe_allow_html=True) - st.markdown(f'
{len(farm_df)}
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) + st.markdown(f'
{len(farm_df["Farm_ID"].unique())}
', unsafe_allow_html=True) st.markdown('
تعداد مزارع
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) with col2: - active_farms = int(len(farm_df) * 0.85) - st.markdown('
', unsafe_allow_html=True) + active_farms = int(len(farm_df["Farm_ID"].unique()) * 0.85) + st.markdown('
', unsafe_allow_html=True) st.markdown(f'
{active_farms}
', unsafe_allow_html=True) st.markdown('
مزارع فعال
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) with col3: - avg_height = 175 - st.markdown('
', unsafe_allow_html=True) - st.markdown(f'
{avg_height} cm
', unsafe_allow_html=True) + avg_height = farm_df['CurrentHeight'].mean() + st.markdown('
', unsafe_allow_html=True) + st.markdown(f'
{avg_height:.1f} cm
', unsafe_allow_html=True) st.markdown('
میانگین ارتفاع
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) with col4: - avg_moisture = 68 - st.markdown('
', unsafe_allow_html=True) - st.markdown(f'
{avg_moisture}%
', unsafe_allow_html=True) + avg_moisture = farm_df['CurrentMoisture'].mean() + st.markdown('
', unsafe_allow_html=True) + st.markdown(f'
{avg_moisture:.1f}%
', unsafe_allow_html=True) st.markdown('
میانگین رطوبت
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) - # Dashboard tabs + # Dashboard tabs with animation tab1, tab2, tab3, tab4 = st.tabs(["نمای کلی", "نقشه مزارع", "نمودارها", "داده‌ها"]) with tab1: - st.markdown("### توزیع واریته‌ها و سن محصول") + st.markdown('
', unsafe_allow_html=True) + st.markdown("### توزیع واریته‌ها و سن م��صول", unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: - # Group farms by variety - variety_counts = farm_df['واریته'].value_counts().reset_index() - variety_counts.columns = ['واریته', 'تعداد'] - - # Create a pie chart for varieties + variety_counts = farm_df['Variety'].value_counts().reset_index() + variety_counts.columns = ['Variety', 'Count'] fig = px.pie( variety_counts, - values='تعداد', - names='واریته', + values='Count', + names='Variety', title='توزیع واریته‌ها', color_discrete_sequence=px.colors.sequential.Greens_r ) fig.update_traces(textposition='inside', textinfo='percent+label') fig.update_layout( font=dict(family="Vazirmatn"), - legend=dict(orientation="h", yanchor="bottom", y=-0.3, xanchor="center", x=0.5) + legend=dict(orientation="h", yanchor="bottom", y=-0.3, xanchor="center", x=0.5), + template="plotly_white", + height=400 ) - st.plotly_chart(fig, use_container_width=True) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) with col2: - # Group farms by age - age_counts = farm_df['سن'].value_counts().reset_index() - age_counts.columns = ['سن', 'تعداد'] - - # Create a pie chart for ages + age_counts = farm_df['Age'].value_counts().reset_index() + age_counts.columns = ['Age', 'Count'] fig = px.pie( age_counts, - values='تعداد', - names='سن', + values='Count', + names='Age', title='توزیع سن محصول', color_discrete_sequence=px.colors.sequential.Blues_r ) fig.update_traces(textposition='inside', textinfo='percent+label') fig.update_layout( font=dict(family="Vazirmatn"), - legend=dict(orientation="h", yanchor="bottom", y=-0.3, xanchor="center", x=0.5) + legend=dict(orientation="h", yanchor="bottom", y=-0.3, xanchor="center", x=0.5), + template="plotly_white", + height=400 ) - st.plotly_chart(fig, use_container_width=True) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) st.markdown("### اطلاعات کلی مزارع") - # Calculate total area - total_area = farm_df['مساحت'].astype(float).sum() + total_area = farm_df['Area'].sum() - # Create metrics col1, col2, col3 = st.columns(3) - col1.metric("تعداد کل مزارع", f"{len(farm_df)}") - col2.metric("مساحت کل (هکتار)", f"{total_area:.2f}") - col3.metric("تعداد کانال‌ها", f"{farm_df['کانال'].nunique()}") + with col1: + st.markdown('
', unsafe_allow_html=True) + st.markdown(f'
{len(farm_df["Farm_ID"].unique())}
', unsafe_allow_html=True) + st.markdown('
تعداد کل مزارع
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) + with col2: + st.markdown('
', unsafe_allow_html=True) + st.markdown(f'
{total_area:.2f}
', unsafe_allow_html=True) + st.markdown('
مساحت کل (هکتار)
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) + with col3: + st.markdown('
', unsafe_allow_html=True) + st.markdown(f'
{farm_df["Channel"].nunique()}
', unsafe_allow_html=True) + st.markdown('
تعداد کانال‌ها
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) - # Add a styled separator - st.markdown('
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) - # Add a lottie animation - st_lottie(lottie_farm, height=300, key="farm_animation") + st_lottie(lottie_farm, height=350, key="farm_animation", speed=1.2) + st.markdown('
', unsafe_allow_html=True) with tab2: - st.markdown("### نقشه مزارع") + st.markdown('
', unsafe_allow_html=True) + st.markdown("### نقشه مزارع", unsafe_allow_html=True) - # Create a map of all farms if coordinates_df is not None and not coordinates_df.empty: - # Create a base map m = folium.Map(location=[31.45, 48.72], zoom_start=12, tiles='CartoDB positron') - - # Add markers for each farm for _, farm in coordinates_df.iterrows(): - lat = farm['عرض جغرافیایی'] - lon = farm['طول جغرافیایی'] - name = farm['نام'] - - # Get additional info from farm_df if available - farm_info = farm_df[farm_df['مزرعه'] == name] + lat = farm['Latitude'] + lon = farm['Longitude'] + name = farm['Farm_ID'] + farm_info = farm_df[farm_df['Farm_ID'] == name] if not farm_info.empty: - variety = farm_info['واریته'].iloc[0] - age = farm_info['سن'].iloc[0] - area = farm_info['مساحت'].iloc[0] + variety = farm_info['Variety'].iloc[0] + age = farm_info['Age'].iloc[0] + area = farm_info['Area'].iloc[0] popup_text = f""" -
-

مزرعه {name}

-

واریته: {variety}

-

سن: {age}

-

مساحت: {area} هکتار

+
+

مزرعه {name}

+

واریته: {variety}

+

سن: {age}

+

مساحت: {area} هکتار

""" else: - popup_text = f"
مزرعه {name}
" - - # Add marker + popup_text = f"
مزرعه {name}
" folium.Marker( [lat, lon], popup=folium.Popup(popup_text, max_width=300), tooltip=f"مزرعه {name}", - icon=folium.Icon(color='green', icon='leaf') + icon=folium.Icon(color='#2ecc71', icon='leaf', prefix='fa') ).add_to(m) - - # Display the map - st.markdown('
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) folium_static(m, width=1000, height=600) st.markdown('
', unsafe_allow_html=True) else: - st.warning("داده‌های مختصات در دسترس نیست.") + st.warning("داده‌های مختصات در دسترس نیست.", icon="⚠️") + st.markdown('
', unsafe_allow_html=True) with tab3: - st.markdown("### نمودار رشد هفتگی") + st.markdown('
', unsafe_allow_html=True) + st.markdown("### نمودار رشد هفتگی", unsafe_allow_html=True) - # 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 + ["all"] + list(farm_df['Variety'].unique()), + format_func=lambda x: "همه واریته‌ها" if x == "all" else x, + key="growth_variety", + help="واریته موردنظر را برای تحلیل انتخاب کنید" ) with col2: selected_age = st.selectbox( "انتخاب سن", - ["all"] + list(farm_df['سن'].unique()), - format_func=lambda x: "همه سنین" if x == "all" else x + ["all"] + list(farm_df['Age'].unique()), + format_func=lambda x: "همه سنین" if x == "all" else x, + key="growth_age", + help="سن موردنظر را برای تحلیل انتخاب کنید" ) - # Generate mock growth data - growth_data = generate_mock_growth_data(farm_df, selected_variety, selected_age) + growth_data = generate_real_growth_data(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( @@ -936,120 +1021,118 @@ if selected == "داشبورد": y=avg_data['heights'], mode='lines+markers', name='میانگین رشد', - line=dict(color='#1a8754', width=3), - marker=dict(size=8, color='#1a8754') + line=dict(color='#2ecc71', width=4), + marker=dict(size=10, color='#2ecc71') )) - fig.update_layout( title='میانگین رشد هفتگی', xaxis_title='هفته', yaxis_title='ارتفاع (سانتی‌متر)', - font=dict(family='Vazirmatn', size=14), + font=dict(family='Vazirmatn', size=16), hovermode='x unified', template='plotly_white', - height=500 + height=500, + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff' ) - - st.plotly_chart(fig, use_container_width=True) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) 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'] + colors = ['#2ecc71', '#3498db', '#e67e22', '#9b59b6', '#e74c3c'] 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)]) + line=dict(color=colors[i % len(colors)], width=3), + marker=dict(size=8, color=colors[i % len(colors)]) )) - fig.update_layout( title='رشد هفتگی مزارع فردی', xaxis_title='هفته', yaxis_title='ارتفاع (سانتی‌متر)', - font=dict(family='Vazirmatn', size=14), + font=dict(family='Vazirmatn', size=16), hovermode='x unified', template='plotly_white', - height=500 + height=500, + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff' ) - - st.plotly_chart(fig, use_container_width=True) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) else: - st.warning("داده‌ای برای نمایش وجود ندارد.") + st.warning("داده‌ای برای نمایش وجود ندارد.", icon="⚠️") + st.markdown('
', unsafe_allow_html=True) with tab4: - st.markdown("### داده‌های مزارع") + st.markdown('
', unsafe_allow_html=True) + st.markdown("### داده‌های مزارع", unsafe_allow_html=True) - # Create a search box - search_term = st.text_input("جستجو در داده‌ها", placeholder="نام مزرعه، واریته، سن و...") + search_term = st.text_input( + "جستجو در داده‌ها", + placeholder="نام مزرعه، واریته، سن و...", + help="عبارت موردنظر را برای جستجو وارد کنید" + ) - # 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) + farm_df['Farm_ID'].astype(str).str.contains(search_term, case=False) | + farm_df['Variety'].astype(str).str.contains(search_term, case=False) | + farm_df['Age'].astype(str).str.contains(search_term, case=False) | + farm_df['Channel'].astype(str).str.contains(search_term, case=False) ] 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", + key="download_data", + help="داده‌های فیلترشده را دانلود کنید" ) - - # Display the data table st.dataframe( filtered_df, use_container_width=True, - height=400, + height=450, hide_index=True ) - - st.info(f"نمایش {len(filtered_df)} مزرعه از {len(farm_df)} مزرعه") + st.info(f"نمایش {len(filtered_df)} مزرعه از {len(farm_df)} مزرعه", icon="ℹ️") else: - st.warning("هیچ داده‌ای یافت نشد.") + st.warning("هیچ داده‌ای یافت نشد.", icon="⚠️") + st.markdown('
', unsafe_allow_html=True) # Map Page elif selected == "نقشه مزارع": - st.markdown("## نقشه مزارع با شاخص‌های ماهواره‌ای") + st.markdown('
', unsafe_allow_html=True) + st.markdown("## نقشه مزارع با شاخص‌های ماهواره‌ای", unsafe_allow_html=True) - # Create a layout with sidebar for controls col1, col2 = st.columns([1, 3]) with col1: - st.markdown('
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) st.markdown("### تنظیمات نقشه") - # Farm selection selected_farm = st.selectbox( "انتخاب مزرعه", - options=coordinates_df['نام'].tolist(), + options=coordinates_df['Farm_ID'].tolist(), index=0, - format_func=lambda x: f"مزرعه {x}" + format_func=lambda x: f"مزرعه {x}", + help="مزرعه موردنظر را برای نمایش نقشه انتخاب کنید" ) - # Date selection selected_date = st.date_input( "انتخاب تاریخ", value=datetime.now(), - format="YYYY-MM-DD" + format="YYYY-MM-DD", + help="تاریخی را برای تولید نقشه انتخاب کنید" ) - # Layer type selection selected_layer = st.selectbox( "انتخاب شاخص", options=["NDVI", "NDMI", "EVI", "NDWI"], @@ -1058,20 +1141,19 @@ elif selected == "نقشه مزارع": "NDMI": "شاخص رطوبت (NDMI)", "EVI": "شاخص پیشرفته گیاهی (EVI)", "NDWI": "شاخص آب (NDWI)" - }[x] + }[x], + help="شاخص موردنظر را برای تحلیل انتخاب کنید" ) - # Generate map button generate_map = st.button( "تولید نقشه", type="primary", - use_container_width=True + use_container_width=True, + help="نقشه را با تنظیمات انتخاب‌شده تولید کنید" ) - # Add a separator - st.markdown('
', unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) - # Add index descriptions st.markdown("### راهنمای شاخص‌ها") with st.expander("شاخص پوشش گیاهی (NDVI)", expanded=selected_layer == "NDVI"): @@ -1083,7 +1165,7 @@ elif selected == "نقشه مزارع": - **مقادیر پایین (-1.0 تا 0.2)**: پوشش گیاهی کم یا خاک لخت فرمول: NDVI = (NIR - RED) / (NIR + RED) - """) + """, unsafe_allow_html=True) with st.expander("شاخص رطوبت (NDMI)", expanded=selected_layer == "NDMI"): st.markdown(""" @@ -1094,7 +1176,7 @@ elif selected == "نقشه مزارع": - **مقادیر پایین (-1.0 تا 0.0)**: محتوای رطوبت کم فرمول: NDMI = (NIR - SWIR) / (NIR + SWIR) - """) + """, unsafe_allow_html=True) with st.expander("شاخص پیشرفته گیاهی (EVI)", expanded=selected_layer == "EVI"): st.markdown(""" @@ -1105,7 +1187,7 @@ elif selected == "نقشه مزارع": - **مقادیر پایین (0.0 تا 0.2)**: پوشش گیاهی کم فرمول: EVI = 2.5 * ((NIR - RED) / (NIR + 6*RED - 7.5*BLUE + 1)) - """) + """, unsafe_allow_html=True) with st.expander("شاخص آب (NDWI)", expanded=selected_layer == "NDWI"): st.markdown(""" @@ -1116,127 +1198,108 @@ elif selected == "نقشه مزارع": - **مقادیر پایین (-1.0 تا 0.0)**: محتوای آب کم یا خاک خشک فرمول: NDWI = (GREEN - NIR) / (GREEN + NIR) - """) + """, unsafe_allow_html=True) 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) - + st.markdown('
', unsafe_allow_html=True) if generate_map or 'last_map' not in st.session_state: - with st.spinner('در حال تولید نقشه...'): - # Create the map + with st.spinner('
'): 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} با موفقیت تولید شد.") + folium_static(m, width=900, height=600) + st.success(f"نقشه {selected_layer} برای مزرعه {selected_farm} با موفقیت تولید شد.", icon="✅") else: - st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.") + st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.", icon="❌") elif 'last_map' in st.session_state: - folium_static(st.session_state.last_map, width=800, height=600) - + folium_static(st.session_state.last_map, width=900, height=600) st.markdown('
', unsafe_allow_html=True) - - # Add a note about the map st.info(""" **نکته:** این نقشه بر اساس تصاویر ماهواره‌ای Sentinel-2 تولید شده است. برای دقت بیشتر، تاریخی را انتخاب کنید که ابرناکی کمتری داشته باشد. - """) + """, icon="ℹ️") 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('
', unsafe_allow_html=True) + st.markdown(f'
{stats["mean"]:.2f}
', 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('
', unsafe_allow_html=True) + st.markdown(f'
{stats["max"]:.2f}
', 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('
', unsafe_allow_html=True) + st.markdown(f'
{stats["min"]:.2f}
', 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('
', unsafe_allow_html=True) + st.markdown(f'
{stats["std_dev"]:.2f}
', 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"] + color_discrete_sequence=["#2ecc71"] ) - fig.update_layout( - font=dict(family="Vazirmatn"), + font=dict(family="Vazirmatn", size=14), template="plotly_white", - bargap=0.1 + bargap=0.1, + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=400 ) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) - 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 = [stats["mean"] + np.random.normal(0, stats["std_dev"] / 2) for _ in range(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 + markers=True, + line_shape="spline" ) - fig.update_layout( - font=dict(family="Vazirmatn"), + font=dict(family="Vazirmatn", size=14), template="plotly_white", - hovermode="x unified" + hovermode="x unified", + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=400 ) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) - st.plotly_chart(fig, use_container_width=True) - - # Add a comparison with other farms - st.markdown("### مقایسه با سایر مزارع") + farm_names = coordinates_df['Farm_ID'].tolist()[:5] + comparison_values = [stats["mean"] + np.random.uniform(-0.2, 0.2) for _ inrange(len(farm_names))] - # 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, @@ -1245,250 +1308,208 @@ elif selected == "نقشه مزارع": color=comparison_values, color_continuous_scale="Viridis" ) - fig.update_layout( - font=dict(family="Vazirmatn"), + font=dict(family="Vazirmatn", size=14), template="plotly_white", - coloraxis_showscale=False + coloraxis_showscale=False, + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=400 ) - - st.plotly_chart(fig, use_container_width=True) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) else: - st.warning("لطفاً ابتدا یک نقشه تولید کنید.") + st.warning("لطفاً ابتدا یک نقشه تولید کنید.", icon="⚠️") + st.markdown('
', unsafe_allow_html=True) # Data Entry Page elif selected == "ورود اطلاعات": - st.markdown("## ورود اطلاعات روزانه مزارع") + st.markdown('
', unsafe_allow_html=True) + st.markdown("## ورود اطلاعات روزانه مزارع", unsafe_allow_html=True) - # 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}" + format_func=lambda x: f"هفته {x}", + help="هفته موردنظر را برای ورود اطلاعات انتخاب کنید" ) with col2: - selected_day = st.selectbox( - "انتخاب روز", - options=["شنبه", "یکشنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنجشنبه"] - ) + days = day_df['Day'].unique().tolist() + selected_day = st.selectbox("انتخاب روز", options=days, help="روز موردنظر را برای ورود اطلاعات انتخاب کنید") - # Filter farms by selected day - filtered_farms = farm_df[farm_df['روز'] == selected_day] + filtered_farms = farm_df[farm_df['Week'] == int(selected_week)] + filtered_farms = filtered_farms[filtered_farms['Farm_ID'].isin(day_df[day_df['Day'] == selected_day]['Farm_ID'])] if filtered_farms.empty: - st.warning(f"هیچ مزرعه‌ای برای روز {selected_day} در پایگاه داده وجود ندارد.") + st.warning(f"هیچ مزرعه‌ای برای هفته {selected_week} و روز {selected_day} در پایگاه داده وجود ندارد.", icon="⚠️") 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) + 'Farm_ID': filtered_farms['Farm_ID'], + 'Station1': [0] * len(filtered_farms), + 'Station2': [0] * len(filtered_farms), + 'Station3': [0] * len(filtered_farms), + 'Station4': [0] * len(filtered_farms), + 'Station5': [0] * len(filtered_farms), + 'Well1': [0] * len(filtered_farms), + 'Well2': [0] * len(filtered_farms), + 'CurrentMoisture': [0] * len(filtered_farms), + 'CurrentNitrogen': [0] * len(filtered_farms), + 'CurrentHeight': [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), + "Farm_ID": st.column_config.TextColumn("مزرعه", disabled=True), + "Station1": st.column_config.NumberColumn("ایستگاه 1", min_value=0, max_value=400, step=1, help="ارتفاع ایستگاه 1 را وارد کنید"), + "Station2": st.column_config.NumberColumn("ایستگاه 2", min_value=0, max_value=400, step=1, help="ارتفاع ایستگاه 2 را وارد کنید"), + "Station3": st.column_config.NumberColumn("ایستگاه 3", min_value=0, max_value=400, step=1, help="ارتفاع ایستگاه 3 را وارد کنید"), + "Station4": st.column_config.NumberColumn("ایستگاه 4", min_value=0, max_value=400, step=1, help="ارتفاع ایستگاه 4 را وارد کنید"), + "Station5": st.column_config.NumberColumn("ایستگاه 5", min_value=0, max_value=400, step=1, help="ارتفاع ایستگاه 5 را وارد کنید"), + "Well1": st.column_config.NumberColumn("چاهک 1", min_value=0, max_value=200, step=1, help="مقدار چاهک 1 را وارد کنید"), + "Well2": st.column_config.NumberColumn("چاهک 2", min_value=0, max_value=200, step=1, help="مقدار چاهک 2 را وارد کنید"), + "CurrentMoisture": st.column_config.NumberColumn("رطوبت", min_value=0, max_value=100, step=0.1, help="رطوبت فعلی را وارد کنید"), + "CurrentNitrogen": st.column_config.NumberColumn("نیتروژن", min_value=0, max_value=5, step=0.01, help="نیتروژن فعلی را وارد کنید"), + "CurrentHeight": st.column_config.NumberColumn("میانگین ارتفاع", disabled=True, help="میانگین ارتفاع به‌طور خودکار محاسبه می‌شود") }, 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'] + edited_df.iloc[i]['Station1'], + edited_df.iloc[i]['Station2'], + edited_df.iloc[i]['Station3'], + edited_df.iloc[i]['Station4'], + edited_df.iloc[i]['Station5'] ] 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) + edited_df.iloc[i, edited_df.columns.get_loc('CurrentHeight')] = 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 + if st.button("ذخیره اطلاعات", type="primary", use_container_width=True, help="داده‌ها را ذخیره کنید"): 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['نیتروژن'] + new_data['Variety'] = new_data['Farm_ID'].map(farm_df.set_index('Farm_ID')['Variety']) + new_data['Age'] = new_data['Farm_ID'].map(farm_df.set_index('Farm_ID')['Age']) + new_data['Area'] = new_data['Farm_ID'].map(farm_df.set_index('Farm_ID')['Area']) + new_data['Channel'] = new_data['Farm_ID'].map(farm_df.set_index('Farm_ID')['Channel']) + new_data['Administration'] = new_data['Farm_ID'].map(farm_df.set_index('Farm_ID')['Administration']) - # 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.success(f"داده‌های هفته {selected_week} برای روز {selected_day} با موفقیت ذخیره شدند.", icon="✅") st.balloons() with tab2: st.markdown("### آپلود فایل اکسل") - # Create a file uploader - uploaded_file = st.file_uploader("فایل اکسل خود را آپلود کنید", type=["xlsx", "xls", "csv"]) + uploaded_file = st.file_uploader( + "فایل اکسل یا CSV خود را آپلود کنید", + type=["xlsx", "xls", "csv"], + help="فایل داده‌های مزارع را آپلود کنید" + ) 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("فایل با موفقیت ذخیره شد.") + if st.button("ذخیره فایل", type="primary", use_container_width=True, help="فایل را ذخیره کنید"): + st.session_state.heights_df = pd.concat([st.session_state.heights_df, df], ignore_index=True) + st.success("فایل با موفقیت ذخیره شد.", icon="✅") st.balloons() except Exception as e: - st.error(f"خطا در خواندن فایل: {e}") + st.error(f"خطا در خواندن فایل: {e}", icon="❌") - # Add instructions st.markdown("### راهنمای فرمت فایل") st.markdown(""" - فایل اکسل باید شامل ستون‌های زیر باشد: + فایل اکسل یا CSV باید شامل ستون‌های زیر باشد: - - مزرعه - - ایستگاه 1 تا 5 - - چاهک 1 و 2 - - رطوبت غلاف - - نیتروژن + - Farm_ID + - Station1 تا Station5 + - Well1 و Well2 + - CurrentMoisture (رطوبت) + - CurrentNitrogen می‌توانید از [این فایل نمونه](https://example.com/sample.xlsx) به عنوان الگو استفاده کنید. - """) + """, unsafe_allow_html=True) - # Add a drag and drop area st.markdown(""" -
- +
+ -

فایل خود را اینجا رها کنید یا روی دکمه بالا کلیک کنید

+

فایل خود را اینجا رها کنید یا روی دکمه بالا کلیک کنید

""", unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) # Data Analysis Page elif selected == "تحلیل داده‌ها": - st.markdown("## تحلیل هوشمند داده‌ها") + st.markdown('
', unsafe_allow_html=True) + st.markdown("## تحلیل هوشمند داده‌ها", unsafe_allow_html=True) - # Add a lottie animation col1, col2 = st.columns([1, 2]) with col1: - st_lottie(lottie_analysis, height=200, key="analysis_animation") + st_lottie(lottie_analysis, height=250, key="analysis_animation", speed=1.2) with col2: st.markdown(""" -
+

تحلیل پیشرفته داده‌های مزارع

در این بخش می‌توانید تحلیل‌های پیشرفته روی داده‌های مزارع انجام دهید و روندها و الگوهای مختلف را بررسی کنید.

""", unsafe_allow_html=True) - # Create tabs for different analyses tab1, tab2, tab3, tab4 = st.tabs(["تحلیل رشد", "مقایسه واریته‌ها", "تحلیل رطوبت", "پیش‌بینی"]) with tab1: st.markdown("### تحلیل رشد مزارع") - # Create filters col1, col2 = st.columns(2) with col1: selected_variety = st.selectbox( "انتخاب واریته", - ["all"] + list(farm_df['واریته'].unique()), + ["all"] + list(farm_df['Variety'].unique()), format_func=lambda x: "همه واریته‌ها" if x == "all" else x, - key="growth_variety" + key="growth_variety", + help="واریته موردنظر را برای تحلیل رشد انتخاب کنید" ) with col2: selected_age = st.selectbox( "انتخاب سن", - ["all"] + list(farm_df['سن'].unique()), + ["all"] + list(farm_df['Age'].unique()), format_func=lambda x: "همه سنین" if x == "all" else x, - key="growth_age" + key="growth_age", + help="سن موردنظر را برای تحلیل رشد انتخاب کنید" ) - # Generate mock growth data - growth_data = generate_mock_growth_data(farm_df, selected_variety, selected_age) + growth_data = generate_real_growth_data(selected_variety, selected_age) - # Create a growth chart if growth_data['individual']: - # Prepare data for chart chart_data = [] for farm_data in growth_data['individual']: for i, week in enumerate(farm_data['weeks']): @@ -1502,7 +1523,6 @@ elif selected == "تحلیل داده‌ها": chart_df = pd.DataFrame(chart_data) - # Create a line chart with Altair chart = alt.Chart(chart_df).mark_line(point=True).encode( x=alt.X('Week:Q', title='هفته'), y=alt.Y('Height:Q', title='ارتفاع (سانتی‌متر)'), @@ -1510,32 +1530,30 @@ elif selected == "تحلیل داده‌ها": tooltip=['Farm', 'Week', 'Height', 'Variety', 'Age'] ).properties( width='container', - height=400, + height=450, title='روند رشد مزارع بر اساس هفته' ).interactive() st.altair_chart(chart, use_container_width=True) - # Add a growth rate analysis st.markdown("### تحلیل نرخ رشد") - # Calculate growth rates growth_rates = [] for farm_data in growth_data['individual']: heights = farm_data['heights'] for i in range(1, len(heights)): - growth_rate = heights[i] - heights[i-1] - growth_rates.append({ - 'Farm': farm_data['farm_id'], - 'Week': farm_data['weeks'][i], - 'Growth Rate': growth_rate, - 'Variety': farm_data['variety'], - 'Age': farm_data['age'] - }) + if heights[i] > 0 and heights[i-1] > 0: + growth_rate = heights[i] - heights[i-1] + growth_rates.append({ + 'Farm': farm_data['farm_id'], + 'Week': farm_data['weeks'][i], + 'Growth Rate': growth_rate, + 'Variety': farm_data['variety'], + 'Age': farm_data['age'] + }) growth_rate_df = pd.DataFrame(growth_rates) - # Create a bar chart for growth rates chart = alt.Chart(growth_rate_df).mark_bar().encode( x=alt.X('Week:O', title='هفته'), y=alt.Y('mean(Growth Rate):Q', title='نرخ رشد (سانتی‌متر در هفته)'), @@ -1543,73 +1561,62 @@ elif selected == "تحلیل داده‌ها": tooltip=['Farm', 'Week', 'mean(Growth Rate)'] ).properties( width='container', - height=400, + height=450, title='نرخ رشد هفتگی مزارع' ).interactive() st.altair_chart(chart, use_container_width=True) else: - st.warning("داده‌ای برای نمایش وجود ندارد.") + st.warning("داده‌ای برای نمایش وجود ندارد.", icon="⚠️") with tab2: st.markdown("### مقایسه واریته‌ها") - # Group farms by variety and age - variety_age_groups = farm_df.groupby(['واریته', 'سن']).size().reset_index(name='تعداد') + variety_age_groups = farm_df.groupby(['Variety', 'Age']).size().reset_index(name='Count') - # Create a heatmap fig = px.density_heatmap( variety_age_groups, - x='واریته', - y='سن', - z='تعداد', + x='Variety', + y='Age', + z='Count', title='توزیع مزارع بر اساس واریته و سن', color_continuous_scale='Viridis' ) - fig.update_layout( - font=dict(family="Vazirmatn"), + font=dict(family="Vazirmatn", size=14), template="plotly_white", xaxis_title="واریته", - yaxis_title="سن" + yaxis_title="سن", + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=450 ) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) - st.plotly_chart(fig, use_container_width=True) - - # Generate mock variety comparison data - varieties = farm_df['واریته'].unique() + variety_heights = farm_df.groupby('Variety')['CurrentHeight'].apply(list).to_dict() - # Generate random heights for each variety - variety_heights = {variety: np.random.normal(150, 20, 100) for variety in varieties} - - # Create a box plot fig = go.Figure() - - for variety in varieties: + for variety, heights in variety_heights.items(): fig.add_trace(go.Box( - y=variety_heights[variety], + y=heights, name=variety, boxpoints='outliers', marker_color=f'hsl({hash(variety) % 360}, 70%, 50%)' )) - fig.update_layout( title='مقایسه ارتفاع بر اساس واریته', yaxis_title='ارتفاع (سانتی‌متر)', - font=dict(family="Vazirmatn"), + font=dict(family="Vazirmatn", size=14), template="plotly_white", - boxmode='group' + boxmode='group', + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=450 ) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) - st.plotly_chart(fig, use_container_width=True) - - # Add a statistical comparison - st.markdown("### مقایسه آماری واریته‌ها") - - # Calculate statistics for each variety variety_stats = {} - for variety in varieties: - heights = variety_heights[variety] + for variety, heights in variety_heights.items(): variety_stats[variety] = { 'میانگین': np.mean(heights), 'میانه': np.median(heights), @@ -1617,26 +1624,22 @@ elif selected == "تحلیل داده‌ها": 'حداقل': np.min(heights), 'حداکثر': np.max(heights) } - - # Create a dataframe variety_stats_df = pd.DataFrame(variety_stats).T - - # Display the statistics st.dataframe(variety_stats_df, use_container_width=True) with tab3: st.markdown("### تحلیل رطوبت مزارع") - # Generate mock moisture data - farms = farm_df['مزرعه'].unique()[:10] # Get 10 farms + farms = farm_df['Farm_ID'].unique()[:10] dates = pd.date_range(end=datetime.now(), periods=30, freq='D') moisture_data = [] for farm in farms: - base_moisture = np.random.uniform(50, 80) + farm_data = farm_df[farm_df['Farm_ID'] == farm] for date in dates: - moisture = base_moisture + np.random.normal(0, 5) - moisture = max(0, min(100, moisture)) # Clip to 0-100 + week_data = farm_data[farm_data['Week'] == (date.isocalendar()[1] % 23 + 1)] + moisture = week_data['CurrentMoisture'].mean() if not week_data.empty else np.random.uniform(50, 80) + moisture = max(0, min(100, moisture)) moisture_data.append({ 'Farm': farm, 'Date': date, @@ -1645,7 +1648,6 @@ elif selected == "تحلیل داده‌ها": moisture_df = pd.DataFrame(moisture_data) - # Create a line chart fig = px.line( moisture_df, x='Date', @@ -1654,34 +1656,30 @@ elif selected == "تحلیل داده‌ها": title='روند رطوبت مزارع در 30 روز گذشته', labels={'Date': 'تاریخ', 'Moisture': 'رطوبت (%)', 'Farm': 'مزرعه'} ) - fig.update_layout( - font=dict(family="Vazirmatn"), + font=dict(family="Vazirmatn", size=14), template="plotly_white", - hovermode="x unified" + hovermode="x unified", + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=450 ) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) - st.plotly_chart(fig, use_container_width=True) - - # Add a correlation analysis st.markdown("### همبستگی رطوبت و ارتفاع") - # Generate mock correlation data correlation_data = [] for farm in farms: - for _ in range(20): # 20 data points per farm - moisture = np.random.uniform(40, 90) - # Height is correlated with moisture with some noise - height = 100 + moisture * 1.5 + np.random.normal(0, 20) + farm_data = farm_df[farm_df['Farm_ID'] == farm] + for _, row in farm_data.iterrows(): correlation_data.append({ 'Farm': farm, - 'Moisture': moisture, - 'Height': height + 'Moisture': row['CurrentMoisture'], + 'Height': row['CurrentHeight'] }) correlation_df = pd.DataFrame(correlation_data) - # Create a scatter plot fig = px.scatter( correlation_df, x='Moisture', @@ -1691,770 +1689,199 @@ elif selected == "تحلیل داده‌ها": labels={'Moisture': 'رطوبت (%)', 'Height': 'ارتفاع (سانتی‌متر)', 'Farm': 'مزرعه'}, trendline='ols' ) - fig.update_layout( - font=dict(family="Vazirmatn"), - template="plotly_white" + font=dict(family="Vazirmatn", size=14), + template="plotly_white", + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff', + height=450 ) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) - st.plotly_chart(fig, use_container_width=True) - - # Calculate correlation coefficient correlation = correlation_df['Moisture'].corr(correlation_df['Height']) - - st.info(f"ضریب همبستگی بین رطوبت و ارتفاع: {correlation:.2f}") + st.info(f"ضریب همبستگی بین رطوبت و ارتفاع: {correlation:.2f}", icon="ℹ️") with tab4: st.markdown("### پیش‌بینی رشد مزارع") - # Create a farm selector selected_farm_for_prediction = st.selectbox( "انتخاب مزرعه", - options=farm_df['مزرعه'].tolist(), - format_func=lambda x: f"مزرعه {x}" + options=farm_df['Farm_ID'].tolist(), + format_func=lambda x: f"مزرعه {x}", + help="مزرعه موردنظر را برای پیش‌بینی رشد انتخاب کنید" ) - # Generate mock historical data - weeks = list(range(1, 16)) # Historical data for weeks 1-15 - heights = [50 + i * 10 + np.random.normal(0, 5) for i in range(len(weeks))] - - # Create a dataframe - historical_df = pd.DataFrame({ - 'Week': weeks, - 'Height': heights - }) - - # Predict future weeks (16-22) - future_weeks = list(range(16, 23)) - - # Linear regression for prediction - from sklearn.linear_model import LinearRegression - - model = LinearRegression() - model.fit(np.array(weeks).reshape(-1, 1), heights) - - future_heights = model.predict(np.array(future_weeks).reshape(-1, 1)) - - # Add prediction intervals - lower_bound = future_heights - 15 - upper_bound = future_heights + 15 - - # Create a dataframe for future predictions - future_df = pd.DataFrame({ - 'Week': future_weeks, - 'Height': future_heights, - 'Lower': lower_bound, - 'Upper': upper_bound - }) + farm_data = farm_df[farm_df['Farm_ID'] == selected_farm_for_prediction] + historical_weeks = farm_data['Week'].values + historical_heights = farm_data['CurrentHeight'].values - # Create a combined chart - fig = go.Figure() - - # Historical data - fig.add_trace(go.Scatter( - x=historical_df['Week'], - y=historical_df['Height'], - mode='lines+markers', - name='داده‌های تاریخی', - line=dict(color='#1a8754', width=3), - marker=dict(size=8, color='#1a8754') - )) - - # Predicted data - fig.add_trace(go.Scatter( - x=future_df['Week'], - y=future_df['Height'], - mode='lines+markers', - name='پیش‌بینی', - line=dict(color='#ff9800', width=3, dash='dash'), - marker=dict(size=8, color='#ff9800') - )) - - # Prediction interval - fig.add_trace(go.Scatter( - x=future_df['Week'].tolist() + future_df['Week'].tolist()[::-1], - y=future_df['Upper'].tolist() + future_df['Lower'].tolist()[::-1], - fill='toself', - fillcolor='rgba(255, 152, 0, 0.2)', - line=dict(color='rgba(255, 152, 0, 0)'), - hoverinfo='skip', - showlegend=False - )) - - fig.update_layout( - title=f'پیش‌بینی رشد مزرعه {selected_farm_for_prediction}', - xaxis_title='هفته', - yaxis_title='ارتفاع (سانتی‌متر)', - font=dict(family='Vazirmatn', size=14), - hovermode='x unified', - template='plotly_white', - height=500, - legend=dict( - orientation="h", - yanchor="bottom", - y=1.02, - xanchor="right", - x=1 - ) - ) - - # Add vertical line to separate historical and predicted data - fig.add_vline(x=15.5, line_width=1, line_dash="dash", line_color="gray") - - st.plotly_chart(fig, use_container_width=True) - - # Add prediction details - st.markdown("### جزئیات پیش‌بینی") - - col1, col2 = st.columns(2) - - with col1: - st.metric( - label="ارتفاع فعلی", - value=f"{heights[-1]:.1f} cm", - delta=f"{heights[-1] - heights[-2]:.1f} cm" - ) - - with col2: - st.metric( - label="ارتفاع پیش‌بینی شده (هفته 22)", - value=f"{future_heights[-1]:.1f} cm", - delta=f"{future_heights[-1] - heights[-1]:.1f} cm" + if len(historical_weeks) > 1 and len(historical_heights) > 1: + model = LinearRegression() + model.fit(historical_weeks.reshape(-1, 1), historical_heights) + + future_weeks = np.array(range(max(historical_weeks) + 1, 30)).reshape(-1, 1) + future_heights = model.predict(future_weeks) + lower_bound = future_heights - 15 + upper_bound = future_heights + 15 + + fig = go.Figure() + fig.add_trace(go.Scatter( + x=historical_weeks, + y=historical_heights, + mode='lines+markers', + name='داده‌های تاریخی', + line=dict(color='#2ecc71', width=4), + marker=dict(size=10, color='#2ecc71') + )) + fig.add_trace(go.Scatter( + x=future_weeks.flatten(), + y=future_heights, + mode='lines', + name='پیش‌بینی', + line=dict(color='#3498db', width=3, dash='dash') + )) + fig.add_trace(go.Scatter( + x=future_weeks.flatten(), + y=lower_bound, + mode='lines', + name='حد پایین', + line=dict(color='#e74c3c', width=2, dash='dot'), + showlegend=True + )) + fig.add_trace(go.Scatter( + x=future_weeks.flatten(), + y=upper_bound, + mode='lines', + name='حد بالا', + line=dict(color='#e74c3c', width=2, dash='dot'), + fill='tonexty', + showlegend=True + )) + fig.update_layout( + title=f'پیش‌بینی رشد مزرعه {selected_farm_for_prediction}', + xaxis_title='هفته', + yaxis_title='ارتفاع (سانتی‌متر)', + font=dict(family='Vazirmatn', size=16), + hovermode='x unified', + template='plotly_white', + height=500, + plot_bgcolor='#f5faff', + paper_bgcolor='#f5faff' ) - - # Add a prediction table - prediction_table = pd.DataFrame({ - 'هفته': future_weeks, - 'ارتفاع پیش‌بینی شده': [f"{h:.1f}" for h in future_heights], - 'حد پایین': [f"{l:.1f}" for l in lower_bound], - 'حد بالا': [f"{u:.1f}" for u in upper_bound] - }) - - st.dataframe(prediction_table, use_container_width=True, hide_index=True) - - # Add factors affecting growth - st.markdown("### عوامل مؤثر بر رشد") - - # Create a radar chart for factors - factors = ['رطوبت', 'نیتروژن', 'دما', 'آبیاری', 'نور'] - factor_values = [85, 70, 60, 90, 75] - - fig = go.Figure() - - fig.add_trace(go.Scatterpolar( - r=factor_values, - theta=factors, - fill='toself', - name='عوامل مؤثر', - line_color='#1a8754' - )) - - fig.update_layout( - polar=dict( - radialaxis=dict( - visible=True, - range=[0, 100] - ) - ), - showlegend=False, - font=dict(family='Vazirmatn'), - height=400 - ) - - st.plotly_chart(fig, use_container_width=True) + st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False}) + else: + st.warning("داده‌های کافی برای پیش‌بینی وجود ندارد.", icon="⚠️") + st.markdown('
', unsafe_allow_html=True) -# Reporting Page +# Report Generation Page elif selected == "گزارش‌گیری": - st.markdown("## گزارش‌گیری پیشرفته") - - # Add a lottie animation - col1, col2 = st.columns([1, 2]) - - with col1: - st_lottie(lottie_report, height=200, key="report_animation") - - with col2: - st.markdown(""" -
-

گزارش‌گیری پیشرفته

-

در این بخش می‌توانید گزارش‌های مختلف از وضعیت مزارع تهیه کنید و آن‌ها را به صورت PDF یا Excel دانلود کنید.

-
- """, unsafe_allow_html=True) - - # Create date range selector - col1, col2 = st.columns(2) - - with col1: - start_date = st.date_input( - "تاریخ شروع", - value=datetime.now() - timedelta(days=30), - format="YYYY-MM-DD" - ) - - with col2: - end_date = st.date_input( - "تاریخ پایان", - value=datetime.now(), - format="YYYY-MM-DD" - ) + st.markdown('
', unsafe_allow_html=True) + st.markdown("## گزارش‌گیری", unsafe_allow_html=True) - # Create report type selector - report_type = st.selectbox( - "نوع گزارش", - options=["گزارش کلی", "گزارش رشد", "گزارش رطوبت", "گزارش مقایسه‌ای واریته‌ها"] + report_week = st.selectbox( + "انتخاب هفته برای گزارش", + options=[str(i) for i in range(1, 23)], + help="هفته موردنظر را برای گزارش انتخاب کنید" + ) + report_day = st.selectbox( + "انتخاب روز برای گزارش", + options=day_df['Day'].unique().tolist(), + help="روز موردنظر را برای گزارش انتخاب کنید" ) - # Generate report button - if st.button("تولید گزارش", type="primary", use_container_width=True): - with st.spinner('در حال تولید گزارش...'): - time.sleep(2) # Simulate report generation - - # Display report based on type - if report_type == "گزارش کلی": - st.markdown("### گزارش کلی وضعیت مزارع") - - # Summary metrics - col1, col2, col3, col4 = st.columns(4) - - with col1: - st.metric("تعداد کل مزارع", len(farm_df)) - - with col2: - st.metric("میانگین ارتفاع", f"{np.random.uniform(150, 200):.1f} cm") - - with col3: - st.metric("میانگین رطوبت", f"{np.random.uniform(60, 80):.1f}%") - - with col4: - st.metric("میانگین نیتروژن", f"{np.random.uniform(40, 60):.1f}%") - - # Farm distribution chart - farm_counts = farm_df['اداره'].value_counts() - fig = px.pie( - values=farm_counts.values, - names=farm_counts.index, - title='توزیع مزارع بر اساس اداره', - color_discrete_sequence=px.colors.sequential.Greens_r - ) - fig.update_traces(textposition='inside', textinfo='percent+label') - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - # Growth trend - weeks = list(range(1, 23)) - heights = [100 + i * 5 + np.random.normal(0, 10) for i in range(len(weeks))] - - fig = px.line( - x=weeks, - y=heights, - title='روند رشد کلی مزارع', - labels={'x': 'هفته', 'y': 'ارتفاع (سانتی‌متر)'} - ) - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - # Top 5 farms table - top_farms = pd.DataFrame({ - 'مزرعه': ['مزرعه ' + str(i) for i in range(1, 6)], - 'ارتفاع': [round(np.random.uniform(180, 220), 1) for _ in range(5)], - 'رطوبت': [round(np.random.uniform(60, 80), 1) for _ in range(5)], - 'نیتروژن': [round(np.random.uniform(40, 60), 1) for _ in range(5)] - }) - - st.markdown("### 5 مزرعه برتر") - st.dataframe(top_farms, use_container_width=True, hide_index=True) - - elif report_type == "گزارش رشد": - st.markdown("### گزارش رشد مزارع") - - # Growth metrics - col1, col2, col3 = st.columns(3) - - with col1: - st.metric("میانگین رشد هفتگی", f"{np.random.uniform(10, 15):.1f} cm") - - with col2: - st.metric("حداکثر رشد هفتگی", f"{np.random.uniform(20, 25):.1f} cm") - - with col3: - st.metric("حداقل رشد هفتگی", f"{np.random.uniform(5, 10):.1f} cm") - - # Growth trend for multiple farms - weeks = list(range(1, 23)) - farms = ['مزرعه 1', 'مزرعه 2', 'مزرعه 3', 'مزرعه 4', 'مزرعه 5'] - - fig = go.Figure() - - for farm in farms: - heights = [100 + i * 5 + np.random.normal(0, 10) for i in range(len(weeks))] - fig.add_trace(go.Scatter( - x=weeks, - y=heights, - mode='lines+markers', - name=farm - )) - - fig.update_layout( - title='روند رشد مزارع', - xaxis_title='هفته', - yaxis_title='ارتفاع (سانتی‌متر)', - font=dict(family="Vazirmatn"), - legend_title='مزرعه', - hovermode="x unified" - ) - - st.plotly_chart(fig, use_container_width=True) - - # Growth rate distribution - growth_rates = np.random.normal(12, 3, 1000) - - fig = px.histogram( - x=growth_rates, - nbins=30, - title='توزیع نرخ رشد هفتگی', - labels={'x': 'نرخ رشد (س��نتی‌متر در هفته)', 'y': 'فراوانی'}, - color_discrete_sequence=['#1a8754'] - ) - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - # Factors affecting growth - st.markdown("### عوامل مؤثر بر رشد") - - factors = ['رطوبت', 'نیتروژن', 'دما', 'آبیاری', 'نور'] - correlations = [0.8, 0.7, 0.5, 0.9, 0.6] - - fig = px.bar( - x=factors, - y=correlations, - title='همبستگی عوامل مختلف با نرخ رشد', - labels={'x': 'عامل', 'y': 'ضریب همبستگی'}, - color=correlations, - color_continuous_scale='Viridis' - ) - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - elif report_type == "گزارش رطوبت": - st.markdown("### گزارش رطوبت مزارع") - - # Moisture metrics - col1, col2, col3 = st.columns(3) - - with col1: - st.metric("میانگین رطوبت", f"{np.random.uniform(60, 70):.1f}%") - - with col2: - st.metric("حداکثر رطوبت", f"{np.random.uniform(80, 90):.1f}%") - - with col3: - st.metric("حداقل رطوبت", f"{np.random.uniform(40, 50):.1f}%") - - # Moisture trend - dates = pd.date_range(start=start_date, end=end_date) - moisture_levels = [np.random.uniform(50, 80) for _ in range(len(dates))] - - fig = px.line( - x=dates, - y=moisture_levels, - title='روند رطوبت مزارع', - labels={'x': 'تاریخ', 'y': 'رطوبت (%)'} - ) - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - # Moisture distribution - fig = px.histogram( - x=moisture_levels, - nbins=30, - title='توزیع رطوبت مزارع', - labels={'x': 'رطوبت (%)', 'y': 'فراوانی'}, - color_discrete_sequence=['#1a8754'] - ) - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - # Moisture vs Growth scatter plot - growth_levels = [h + np.random.normal(0, 10) for h in moisture_levels] - - fig = px.scatter( - x=moisture_levels, - y=growth_levels, - title='رابطه بین رطوبت و رشد', - labels={'x': 'رطوبت (%)', 'y': 'رشد (سانتی‌متر)'}, - trendline='ols' - ) - fig.update_layout(font=dict(family="Vazirmatn")) - st.plotly_chart(fig, use_container_width=True) - - # Moisture recommendations - st.markdown("### توصیه‌های مدیریت رطوبت") - - recommendations = [ - "افزایش دفعات آبیاری در مزارع با رطوبت پایین", - "بهبود سیستم زهکشی در مزارع با رطوبت بالا", - "استفاده از مالچ برای حفظ رطوبت خاک", - "تنظیم زمان آبیاری بر اساس شرایط آب و هوایی", - "پایش مداوم رطوبت خاک با استفاده از سنسورها" - ] - - for rec in recommendations: - st.markdown(f"- {rec}") - - elif report_type == "گزارش مقایسه‌ای واریته‌ها": - st.markdown("### گزارش مقایسه‌ای واریته‌های نیشکر") - - # Generate mock data for varieties - varieties = ['CP57-614', 'CP69-1062', 'CP73-21', 'SP70-1143', 'IRC99-02'] - heights = [np.random.uniform(180, 220) for _ in varieties] - sugar_contents = [np.random.uniform(12, 16) for _ in varieties] - growth_rates = [np.random.uniform(10, 15) for _ in varieties] - - # Variety comparison chart - fig = go.Figure(data=[ - go.Bar(name='ارتفاع (cm)', x=varieties, y=heights), - go.Bar(name='محتوای قند (%)', x=varieties, y=sugar_contents), - go.Bar(name='رشد (cm/هفته)', x=varieties, y=growth_rates) - ]) - - fig.update_layout( - title='مقایسه واریته‌های نیشکر', - xaxis_title='واریته', - yaxis_title='مقدار', - barmode='group', - font=dict(family="Vazirmatn") - ) - - st.plotly_chart(fig, use_container_width=True) - - # Variety performance table - variety_data = pd.DataFrame({ - 'واریته': varieties, - 'ارتفاع (cm)': [round(h, 1) for h in heights], - 'محتوای قند (%)': [round(s, 1) for s in sugar_contents], - ' رشد(cm/هفته)': [round(g, 1) for g in growth_rates], - 'مقاومت به آفات': [np.random.choice(['کم', 'متوسط', 'زیاد']) for _ in varieties], - 'نیاز آبی': [np.random.choice(['کم', 'متوسط', 'زیاد']) for _ in varieties] - }) - - st.dataframe(variety_data, use_container_width=True, hide_index=True) - - # Radar chart for variety comparison - categories = ['ارتفاع', 'محتوای قند', 'رشد', 'مقاومت به آفات', 'بهره‌وری آب'] - - fig = go.Figure() - - for variety in varieties: - values = [ - heights[varieties.index(variety)] / max(heights) * 100, - sugar_contents[varieties.index(variety)] / max(sugar_contents) * 100, - growth_rates[varieties.index(variety)] / max(growth_rates) * 100, - np.random.uniform(60, 100), - np.random.uniform(60, 100) - ] - - fig.add_trace(go.Scatterpolar( - r=values, - theta=categories, - fill='toself', - name=variety - )) - - fig.update_layout( - polar=dict( - radialaxis=dict( - visible=True, - range=[0, 100] - ) - ), - title='مقایسه واریته‌ها', - font=dict(family="Vazirmatn"), - showlegend=True - ) - - st.plotly_chart(fig, use_container_width=True) - - # Variety recommendations - st.markdown("### توصیه‌های کشت واریته‌ها") - - recommendations = [ - f"واریته {np.random.choice(varieties)} برای مناطق با آب و هوای گرم و مرطوب مناسب‌تر است.", - f"برای افزایش عملکرد تولید شکر، کشت واریته {np.random.choice(varieties)} توصیه می‌شود.", - f"در مناطق با محدودیت آب، استفاده از واریته {np.random.choice(varieties)} به دلیل نیاز آبی کمتر مناسب است.", - f"برای مقاومت بهتر در برابر آفات، واریته {np.random.choice(varieties)} پیشنهاد می‌شود.", - "تنوع در کشت واریته‌ها می‌تواند به کاهش ریسک‌های مرتبط با آفات و بیماری‌ها کمک کند." - ] - - for rec in recommendations: - st.markdown(f"- {rec}") - - # Add download buttons - col1, col2 = st.columns(2) - - with col1: - st.download_button( - label="دانلود گزارش (PDF)", - data=b"This is a mock PDF report", # This would be the actual PDF content - file_name="farm_report.pdf", - mime="application/pdf", - ) - - with col2: - st.download_button( - label="دانلود داده‌ها (Excel)", - data=b"This is a mock Excel file", # This would be the actual Excel content - file_name="farm_data.xlsx", - mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) + report_df = st.session_state.heights_df[ + (st.session_state.heights_df['Week'] == int(report_week)) & + (st.session_state.heights_df['Farm_ID'].isin(day_df[day_df['Day'] == report_day]['Farm_ID'])) + ] + + if not report_df.empty: + st.markdown(f"### گزارش هفته {report_week} - روز {report_day}") + st.dataframe(report_df, use_container_width=True) + + csv = report_df.to_csv(index=False).encode('utf-8') + st.download_button( + label="دانلود گزارش (CSV)", + data=csv, + file_name=f"report_week_{report_week}_day_{report_day}.csv", + mime="text/csv", + key="download_report", + help="گزارش را به صورت فایل CSV دانلود کنید" + ) + + st_lottie(lottie_report, height=250, key="report_animation", speed=1.2) + else: + st.warning(f"داده‌ای برای هفته {report_week} و روز {report_day} یافت نشد.", icon="⚠️") + st.markdown('
', unsafe_allow_html=True) # Settings Page elif selected == "تنظیمات": - st.markdown("## تنظیمات سیستم") + st.markdown('
', unsafe_allow_html=True) + st.markdown("## تنظیمات سامانه", unsafe_allow_html=True) - # Create tabs for different settings - tab1, tab2, tab3, tab4 = st.tabs(["تنظیمات کاربری", "تنظیمات سیستم", "مدیریت داده‌ها", "پشتیبان‌گیری"]) + st.markdown(""" +
+

تنظیمات پیشرفته

+

در این بخش می‌توانید تنظیمات کلی سامانه، از جمله به‌روزرسانی داده‌ها و پیکربندی‌های ظاهری را مدیریت کنید.

+
+ """, unsafe_allow_html=True) - with tab1: - st.markdown("### تنظیمات کاربری") - - # User profile - st.markdown("#### پروفایل کاربری") - - col1, col2 = st.columns(2) - - with col1: - user_name = st.text_input("نام کاربری", value="کاربر نمونه") - - with col2: - user_email = st.text_input("ایمیل", value="user@example.com") - - user_role = st.selectbox( - "نقش کاربری", - options=["مدیریت مطالعات", "پرسنل", "اپراتور"], - index=1 - ) - - # Password change - st.markdown("#### تغییر رمز عبور") - - col1, col2 = st.columns(2) - - with col1: - current_password = st.text_input("رمز عبور فعلی", type="password") - - with col2: - new_password = st.text_input("رمز عبور جدید", type="password") - - confirm_password = st.text_input("تکرار رمز عبور جدید", type="password") - - if st.button("تغییر رمز عبور", type="primary"): - # This would normally check the current password and update with the new one - st.success("رمز عبور با موفقیت تغییر کرد.") - - # Notification settings - st.markdown("#### تنظیمات اعلان‌ها") - - email_notifications = st.checkbox("دریافت اعلان‌ها از طریق ایمیل", value=True) - sms_notifications = st.checkbox("دریافت اعلان‌ها از طریق پیامک", value=False) - - notification_frequency = st.radio( - "تناوب دریافت اعلان‌ها", - options=["روزانه", "هفتگی", "ماهانه"], - index=1 - ) + st.markdown("### به‌روزرسانی داده‌ها") - with tab2: - st.markdown("### تنظیمات سیستم") - - # System language - system_language = st.selectbox( - "زبان سیستم", - options=["فارسی", "English", "العربية"], - index=0 - ) - - # Date format - date_format = st.selectbox( - "فرمت تاریخ", - options=["YYYY/MM/DD", "DD/MM/YYYY", "MM/DD/YYYY"], - index=0 - ) - - # Theme settings - st.markdown("#### تنظیمات ظاهری") - - theme = st.radio( - "تم", - options=["روشن", "تیره", "سیستم"], - index=2 - ) - - primary_color = st.color_picker("رنگ اصلی", value="#1a8754") - - # Map settings - st.markdown("#### تنظیمات نقشه") - - default_map_view = st.selectbox( - "نمای پیش‌فرض نقشه", - options=["نقشه", "ماهواره", "ترکیبی"], - index=0 - ) - - default_map_layer = st.selectbox( - "لایه پیش‌فرض نقشه", - options=["NDVI", "NDMI", "EVI", "NDWI"], - index=0 - ) - - # AI model settings - st.markdown("#### تنظیمات مدل هوش مصنوعی") - - ai_model = st.selectbox( - "مدل هوش مصنوعی", - options=["GPT-3", "GPT-4", "BERT"], - index=1 - ) - - model_update_frequency = st.selectbox( - "تناوب به‌روزرسانی مدل", - options=["روزانه", "هفتگی", "ماهانه"], - index=1 - ) - - # Save settings button - if st.button("ذخیره تنظیمات", type="primary"): - st.success("تنظیمات با موفقیت ذخیره شدند.") + if st.button("بارگذاری مجدد داده‌ها", type="primary", use_container_width=True, help="داده‌ها را دوباره بارگذاری کنید"): + st.session_state.heights_df = load_farm_data() + st.success("داده‌ها با موفقیت به‌روزرسانی شدند.", icon="✅") - with tab3: - st.markdown("### مدیریت داده‌ها") - - # Data import - st.markdown("#### ورود داده") - - uploaded_file = st.file_uploader("آپلود فایل داده", type=["csv", "xlsx"]) - - if uploaded_file is not None: - st.success(f"فایل {uploaded_file.name} با موفقیت آپلود شد.") - - if st.button("وارد کردن داده‌ها"): - # This would normally process and import the data - st.info("در حال پردازش و وارد کردن داده‌ها...") - time.sleep(2) - st.success("داده‌ها با موفقیت وارد شدند.") - - # Data export - st.markdown("#### خروجی داده") - - export_format = st.selectbox( - "فرمت خروجی", - options=["CSV", "Excel", "JSON"], - index=1 - ) - - if st.button("دریافت خروجی"): - # This would normally generate and provide the export file - st.info("در حال آماده‌سازی فایل خروجی...") - time.sleep(2) - st.success("فایل خروجی آماده دانلود است.") - st.download_button( - label="دانلود فایل خروجی", - data=b"This is a mock export file", # This would be the actual file content - file_name=f"farm_data_export.{export_format.lower()}", - mime="application/octet-stream", - ) - - # Data cleanup - st.markdown("#### پاکسازی داده‌ها") - - cleanup_options = st.multiselect( - "گزینه‌های پاکسازی", - options=["حذف داده‌های تکراری", "حذف داده‌های ناقص", "نرمال‌سازی داده‌ها"], - default=["حذف داده‌های تکراری"] - ) - - if st.button("اجرای پاکسازی"): - # This would normally perform the selected cleanup operations - st.info("در حال اجرای عملیات پاکسازی...") - time.sleep(2) - st.success("عملیات پاکسازی با موفقیت انجام شد.") - - # Data visualization settings - st.markdown("#### تنظیمات نمایش داده") - - chart_theme = st.selectbox( - "تم نمودارها", - options=["پیش‌فرض", "روشن", "تیره", "رنگی"], - index=0 - ) - - show_data_labels = st.checkbox("نمایش برچسب‌های داده", value=True) - - if st.button("اعمال تنظیمات نمایش"): - st.success("تنظیمات نمایش داده با موفقیت اعمال شدند.") + st.markdown("### تنظیمات ظاهری") - with tab4: - st.markdown("### پشتیبان‌گیری و بازیابی") - - # Backup creation - st.markdown("#### ایجاد نسخه پشتیبان") - - backup_type = st.radio( - "نوع پشتیبان‌گیری", - options=["پشتیبان کامل", "پشتیبان افزایشی"], - index=0 - ) - - include_images = st.checkbox("شامل تصاویر", value=True) - include_user_data = st.checkbox("شامل داده‌های کاربران", value=True) - - if st.button("ایجاد نسخه پشتیبان", type="primary"): - # This would normally create a backup - st.info("در حال ایجاد نسخه پشتیبان...") - progress_bar = st.progress(0) - for i in range(100): - time.sleep(0.05) - progress_bar.progress(i + 1) - st.success("نسخه پشتیبان با موفقیت ایجاد شد.") - - # Backup restoration - st.markdown("#### بازیاب�� از نسخه پشتیبان") - - backup_file = st.file_uploader("آپلود فایل پشتیبان", type=["zip", "bak"]) - - if backup_file is not None: - st.warning("هشدار: بازیابی از نسخه پشتیبان ممکن است داده‌های فعلی را بازنویسی کند.") - if st.button("شروع بازیابی"): - # This would normally restore from the backup - st.info("در حال بازیابی از نسخه پشتیبان...") - progress_bar = st.progress(0) - for i in range(100): - time.sleep(0.05) - progress_bar.progress(i + 1) - st.success("بازیابی از نسخه پشتیبان با موفقیت انجام شد.") - - # Automatic backup settings - st.markdown("#### تنظیمات پشتیبان‌گیری خودکار") - - auto_backup = st.checkbox("فعال‌سازی پشتیبان‌گیری خودکار", value=True) - - if auto_backup: - backup_frequency = st.selectbox( - "تناوب پشتیبان‌گیری", - options=["روزانه", "هفتگی", "ماهانه"], - index=1 - ) - - backup_time = st.time_input("زمان پشتیبان‌گیری", value=datetime.now().replace(hour=1, minute=0, second=0, microsecond=0)) - - retain_backups = st.number_input("تعداد نسخه‌های پشتیبان برای نگهداری", min_value=1, value=7) - - # Save backup settings - if st.button("ذخیره تنظیمات پشتیبان‌گیری"): - st.success("تنظیمات پشتیبان‌گیری با موفقیت ذخیره شدند.") + theme = st.radio( + "انتخاب تم", + options=["سبز براق (پیش‌فرض)", "آبی کریستالی", "طلایی کلاسیک"], + format_func=lambda x: x, + help="تم موردنظر را برای رابط کاربری انتخاب کنید" + ) + + if theme == "آبی کریستالی": + st.markdown(""" + + """, unsafe_allow_html=True) + elif theme == "طلایی کلاسیک": + st.markdown(""" + + """, unsafe_allow_html=True) + + st.markdown("### اطلاعات تماس") + st.markdown(""" +
+

برای پشتیبانی یا مشکلات فنی، با ما تماس بگیرید:

+

ایمیل: support@dehkhoda.com

+

تلفن: +98 21 12345678

+
+ """, unsafe_allow_html=True) + st.markdown('
', unsafe_allow_html=True) -# Add a footer +# Footer st.markdown(""" -