diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,1907 +1,568 @@
import streamlit as st
-
-# تعریف نام ستونهای فایل
-column_names = {
- 0: "سال",
- 1: "هفته",
- 2: "مزرعه",
- 3: "کانال",
- 4: "اداره",
- 5: "مساحت",
- 6: "مساحت زیر مجموعه",
- 7: "رقم",
- 8: "سن",
- 9: "ایستگاه 1",
- 10: "ایستگاه 2",
- 11: "ایستگاه 3",
- 12: "ایستگاه 4",
- 13: "ایستگاه 5",
- 14: "ارتفاع هفته جاری مزرعه",
- 15: "ارتفاع هفته گذشته مزرعه",
- 16: "رشد هفته جاری",
- 17: "رشد هفته گذشته",
- 18: "نیتروژن فعلی",
- 19: "نیتروژن استاندارد فعلی",
- 20: "نیتروژن قبلی",
- 21: "نیتروژن استاندارد قبلی",
- 22: "رطوبت غلاف فعلی",
- 23: "رطوبت استاندارد فعلی",
- 24: "رطوبت غلاف قبلی",
- 25: "رطوبت استاندارد قبلی",
- 26: "چاهک 1",
- 27: "تاریخ قرائت",
- 28: "چاهک 2",
- 29: "تاریخ قرائت.1"
-}
import pandas as pd
import numpy as np
-import folium
-from streamlit_folium import folium_static
+import geemap.foliumap as geemap
import ee
import os
-import json
-import time
-from datetime import datetime, timedelta
+import datetime
import plotly.express as px
import plotly.graph_objects as go
-from PIL import Image
+from streamlit_folium import folium_static
+import folium
+from folium.plugins import Draw, Fullscreen, MeasureControl
+import json
import base64
-from io import BytesIO
-import matplotlib.pyplot as plt
-import seaborn as sns
-import altair as alt
-from streamlit_option_menu import option_menu
-from streamlit_lottie import st_lottie
-import requests
-import hydralit_components as hc
-from streamlit_extras.colored_header import colored_header
-from streamlit_extras.metric_cards import style_metric_cards
-from streamlit_extras.chart_container import chart_container
-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
+from PIL import Image
+import io
-# تنظیمات صفحه با تم سفارشی
+# تنظیم عنوان صفحه
st.set_page_config(
- page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا",
+ page_title="داشبورد مانیتورینگ مزارع نیشکر دهخدا",
page_icon="🌱",
layout="wide",
- initial_sidebar_state="expanded"
+ initial_sidebar_state="expanded",
)
-# CSS سفارشی با طراحی مدرن و جذاب
+# استایلهای CSS
st.markdown("""
""", unsafe_allow_html=True)
-# بارگذاری دادههای واقعی مزارع از CSV
-@st.cache_data
-def load_farm_data():
- try:
- df = pd.read_csv("کراپ لاگ کلی (1).csv")
- st.write("ستونهای موجود در فایل:", df.columns.tolist())
- 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')
-
- # Convert numeric columns to appropriate types
- numeric_columns = ['CurrentHeight', 'PreviousHeight', 'CurrentGrowth', 'PreviousGrowth',
- 'CurrentNitrogen', 'StandardNitrogen', 'PreviousNitrogen', 'PreviousStandardNitrogen',
- 'CurrentMoisture', 'StandardMoisture', 'PreviousMoisture', 'PreviousStandardMoisture',
- 'Well1', 'Well2', 'Station1', 'Station2', 'Station3', 'Station4', 'Station5']
-
- for col in numeric_columns:
- if col in df.columns:
- df[col] = pd.to_numeric(df[col], errors='coerce')
-
- 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()
-
-# بارگذاری انیمیشن JSON
-@st.cache_data
-def load_lottie_url(url: str):
- r = requests.get(url)
- if r.status_code != 200:
- return None
- return r.json()
-
-# مقداردهی اولیه Earth Engine
+# تابع برای احراز هویت GEE
@st.cache_resource
-def initialize_earth_engine():
+def initialize_gee():
try:
service_account = 'dehkhodamap-e9f0da4ce9f6514021@ee-esmaeilkiani13877.iam.gserviceaccount.com'
- credentials_dict = {
- "type": "service_account",
- "project_id": "ee-esmaeilkiani13877",
- "private_key_id": "cfdea6eaf4115cb6462626743e4b15df85fd0c7f",
- "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCjeOvgKi+gWK6k\n2/0RXOA3LAo51DVxA1ja9v0qFOn4FNOStxkwlKvcK8yDQNb53FPORHFIUHvev3y7\niHr/UEUqnn5Rzjbf0k3qWB/fS377/UP4VznMsFpKiHNxCBtaNS8KLk6Rat6Y7Xfm\nJfpSU7ZjYZmVc81M/7iFofGUSJoHYpxhyt3rjp53huxJNNW5e12TFnLkyg1Ja/9X\nGMTt+vjVcO4XhQCIlaGVdSKS2sHlHgzpzE6KtuUKjDMEBqPkWF4xc16YavYltwPd\nqULCu2/t6dczhYL4NEFj8wL+KJqOojfsyoWmzqPFx1Bbxk4BVPk/lslq9+m9p5kq\nSCG0/9W9AgMBAAECggEAEGchw+x3uu8rFv+79PIMzXxtyj+w3RYo5E/EN2TB1VLB\nqAcXT/ibBgyfCMyIxamF/zx+4XKx+zfbnDWlodi8F/qvUiYO+4ZuqwUMras1orNX\nDqQx+If5h2EJtF3L4NFVVwAuggjnLREm5sEIzRn5Qx+X+ZcVEpTWPxJw2yAt1G+3\nk311KqD+zR7jQfchXU4xQQ1ZoHkdAJ/DPGun6x+HUOq7Gus73A6IzLp12ZoiHN3n\nkY+lG8cMs039QAe/OhZFEo5I9cNSaI688HmsLRivZ26WoPEnwcN0MHQGtXqGmMUI\nCcpgJqllqdWMuBlYcpSadn7rZzPujSlzIxkvieLeAQKBgQDNTYUWZdGbA2sHcBpJ\nrqKwDYF/AwZtjx+hXHVBRbR6DJ1bO2P9n51ioTMP/H9K61OBAMZ7w71xJ2I+9Snv\ncYumPWoiUwiOhTh3O7nYz6mR7sK0HuUCZfYdaxJVnLgNCgj+w9AxYnkzOyL9/QvJ\nknrlMKf4H59NbapBqy5spilq1QKBgQDL1wkGHhoTuLb5Xp3X3CX4S7WMke4T01bO\nPpMmlewVgH5lK5wTcZjB8QRO2QFQtUZTP/Ghv6ZH4h/3P9/ZIF3hV5CSsUkr/eFf\nMY+fQL1K/puwfZbSDcH1GtDToOyoLFIvPXBJo0Llg/oF2TK1zGW3cPszeDf/Tm6x\nUwUMw2BjSQKBgEJzAMyLEBi4NoAlzJxkpcuN04gkloQHexljL6B8yzlls9i/lFGW\nw/4UZs6ZzymUmWZ7tcKBTGO/d5EhEP2rJqQb5KpPbcmTXP9amYCPVjchrGtYRI9O\nKSbEbR7ApuGxic/L2Sri0I/AaEcFDDel7ZkY8oTg11LcV+sBWPlZnrYxAoGBALXj\n/DlpQvu2KA/9TfwAhiE57Zax4S/vtdX0IHqd7TyCnEbK00rGYvksiBuTqIjMOSSw\nOn2K9mXOcZe/d4/YQe2CpY9Ag3qt4R2ArBf/POpep66lYp+thxWgCBfP0V1/rxZY\nTIppFJiZW9E8LvPqoBlAx+b1r4IyCrRQ0IDDFo+BAoGBAMCff4XKXHlV2SDOL5uh\nV/f9ApEdF4leuo+hoMryKuSQ9Y/H0A/Lzw6KP5FLvVtqc0Kw2D1oLy8O72a1xwfY\n8dpZMNzKAWWS7viN0oC+Ebj2Foc2Mn/J6jdhtP/YRLTqvoTWCa2rVcn4R1BurMIf\nLa4DJE9BagGdVNTDtynBhKhZ\n-----END PRIVATE KEY-----\n",
- "client_email": "dehkhodamap-e9f0da4ce9f6514021@ee-esmaeilkiani13877.iam.gserviceaccount.com",
- "client_id": "113062529451626176784",
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
- "token_uri": "https://oauth2.googleapis.com/token",
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/dehkhodamap-e9f0da4ce9f6514021%40ee-esmaeilkiani13877.iam.gserviceaccount.com",
- "universe_domain": "googleapis.com"
- }
credentials_file = 'ee-esmaeilkiani13877-cfdea6eaf411.json'
- with open(credentials_file, 'w') as f:
- json.dump(credentials_dict, f)
credentials = ee.ServiceAccountCredentials(service_account, credentials_file)
ee.Initialize(credentials)
- os.remove(credentials_file)
return True
except Exception as e:
- st.error(f"خطا در اتصال به Earth Engine: {e}")
+ st.error(f"خطا در اتصال به Google Earth Engine: {e}")
return False
-# ایج��د نقشه Earth Engine با شاخصها
-def create_ee_map(farm_id, date_str, layer_type="NDVI"):
+# خواندن دادههای CSV
+@st.cache_data
+def load_data():
try:
- 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')
- 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')
- region = ee.Geometry.Point([lon, lat]).buffer(1500)
- s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
- .filterDate(start_date, end_date) \
- .filterBounds(region) \
- .sort('CLOUDY_PIXEL_PERCENTAGE') \
- .first()
- 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']}
- legend_title = 'شاخص پوشش گیاهی (NDVI)'
- elif layer_type == "NDMI":
- index = s2.normalizedDifference(['B8', 'B11']).rename('NDMI')
- viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#8b0000', '#ff8c00', '#00ced1', '#00b7eb', '#00008b']}
- legend_title = 'شاخص رطوبت (NDMI)'
- elif layer_type == "EVI":
- nir = s2.select('B8')
- red = s2.select('B4')
- blue = s2.select('B2')
- index = nir.subtract(red).multiply(2.5).divide(nir.add(red.multiply(6)).subtract(blue.multiply(7.5)).add(1)).rename('EVI')
- viz_params = {'min': 0, 'max': 1, 'palette': ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#4caf50']}
- legend_title = 'شاخص پیشرفته گیاهی (EVI)'
- elif layer_type == "NDWI":
- index = s2.normalizedDifference(['B3', 'B8']).rename('NDWI')
- viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#00008b', '#00b7eb', '#add8e6', '#fdae61', '#d73027']}
- legend_title = 'شاخص آب (NDWI)'
- map_id_dict = ee.Image(index).getMapId(viz_params)
- folium.TileLayer(
- tiles=map_id_dict['tile_fetcher'].url_format,
- attr='Google Earth Engine',
- name=layer_type,
- overlay=True,
- control=True
- ).add_to(m)
- folium.Marker(
- [lat, lon],
- popup=f'مزرعه {farm_id}',
- tooltip=f'مزرعه {farm_id}',
- icon=folium.Icon(color='green', icon='leaf', prefix='fa')
- ).add_to(m)
- folium.Circle(
- [lat, lon],
- radius=1500,
- color='green',
- fill=True,
- fill_color='green',
- fill_opacity=0.1,
- weight=2
- ).add_to(m)
- folium.LayerControl().add_to(m)
- legend_html = '''
-
-
''' + legend_title + '''
-
-
-
-
- '''
- m.get_root().html.add_child(folium.Element(legend_html))
- return m
+ df = pd.read_csv('output (1).csv')
+ return df
except Exception as e:
- st.error(f"خطا در ایجاد نقشه: {e}")
+ st.error(f"خطا در خواندن فایل CSV: {e}")
return None
-# محاسبه آمار واقعی مزارع
-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([])
+# تابع برای محاسبه شاخصهای مختلف
+def calculate_indices(image):
+ # NDVI
+ ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
+
+ # EVI
+ evi = image.expression(
+ '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))',
+ {
+ 'NIR': image.select('B8'),
+ 'RED': image.select('B4'),
+ 'BLUE': image.select('B2')
}
- return stats
-
-# تولید دادههای رشد واقعی
-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['Variety'] == selected_variety]
- if selected_age != "all":
- filtered_farms = filtered_farms[filtered_farms['Age'] == selected_age]
+ ).rename('EVI')
- farm_growth_data = []
- 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_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': [farm_data[farm_data['Week'] == week]['CurrentHeight'].mean() if not farm_data[farm_data['Week'] == week].empty else 0 for week in weeks]
+ # NDMI (Normalized Difference Moisture Index)
+ ndmi = image.normalizedDifference(['B8', 'B11']).rename('NDMI')
+
+ # LAI (Leaf Area Index) - simplified model
+ lai = image.expression(
+ '3.618 * EVI - 0.118',
+ {
+ 'EVI': evi
}
- farm_growth_data.append(growth_data)
+ ).rename('LAI')
- if farm_growth_data:
- avg_heights = []
- for week in weeks:
- 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(np.mean(week_heights) if week_heights else 0)
-
- avg_growth_data = {
- 'farm_id': 'میانگین',
- 'variety': 'همه',
- 'age': 'همه',
- 'weeks': weeks,
- 'heights': avg_heights
+ # Biomass - simplified model based on LAI
+ biomass = image.expression(
+ '0.8 * LAI + 0.2',
+ {
+ 'LAI': lai
}
- return {'individual': farm_growth_data, 'average': avg_growth_data}
- return {
- 'individual': [],
- 'average': {'farm_id': 'میانگین', 'variety': 'همه', 'age': 'همه', 'weeks': weeks, 'heights': [0] * len(weeks)}
- }
+ ).rename('Biomass')
+
+ # MSI (Moisture Stress Index)
+ msi = image.expression(
+ 'SWIR1 / NIR',
+ {
+ 'SWIR1': image.select('B11'),
+ 'NIR': image.select('B8')
+ }
+ ).rename('MSI')
+
+ # Chlorophyll Index
+ chlorophyll = image.expression(
+ 'NIR / RED - 1',
+ {
+ 'NIR': image.select('B8'),
+ 'RED': image.select('B4')
+ }
+ ).rename('Chlorophyll')
+
+ # Add all indices to the image
+ return image.addBands([ndvi, evi, ndmi, lai, biomass, msi, chlorophyll])
-# مقداردهی اولیه Earth Engine و بارگذاری دادهها
-ee_initialized = initialize_earth_engine()
-farm_df = load_farm_data()
-coordinates_df = load_coordinates_data()
-day_df = load_day_data()
+# تابع برای دریافت تصاویر Sentinel-2
+def get_sentinel_imagery(start_date, end_date, aoi):
+ # فیلتر کردن مجموعه داده Sentinel-2
+ s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
+ .filterDate(start_date, end_date) \
+ .filterBounds(aoi) \
+ .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
+
+ if s2.size().getInfo() == 0:
+ return None
+
+ # محاسبه میانگین تصاویر
+ s2_median = s2.median()
+
+ # محاسبه شاخصها
+ s2_indices = calculate_indices(s2_median)
+
+ return s2_indices
-# بارگذاری انیمیشنها
-lottie_farm = load_lottie_url('https://assets5.lottiefiles.com/packages/lf20_ystsffqy.json')
-lottie_analysis = load_lottie_url('https://assets3.lottiefiles.com/packages/lf20_qp1q7mct.json')
-lottie_report = load_lottie_url('https://assets9.lottiefiles.com/packages/lf20_vwcugezu.json')
+# تابع برای ایجاد نقشه
+def create_map(center_lat, center_lon, zoom=13):
+ m = geemap.Map()
+ m.set_center(center_lon, center_lat, zoom)
+ m.add_basemap('HYBRID')
+ return m
-# ایجاد حالت جلسه برای ذخیره دادهها
-if 'heights_df' not in st.session_state:
- st.session_state.heights_df = farm_df.copy()
+# تابع برای اضافه کردن لایه شاخص به نقشه
+def add_index_layer(m, image, index_name, vis_params, layer_name):
+ if image is not None:
+ m.add_layer(image.select(index_name), vis_params, layer_name)
+ return m
-# سرصفحه اصلی با انیمیشن
-st.markdown('', unsafe_allow_html=True)
-st.markdown('
سامانه هوشمند پایش مزارع نیشکر دهخدا ', unsafe_allow_html=True)
-st.markdown('
پلتفرم جامع مدیریت، پایش و تحلیل دادههای مزارع نیشکر با هوش مصنوعی پیشرفته
', unsafe_allow_html=True)
-st.markdown('
', unsafe_allow_html=True)
+# تابع برای ایجاد نمودار زمانی
+def create_time_series(aoi, index_name, start_date, end_date, interval='day'):
+ # تعریف بازههای زمانی
+ if interval == 'day':
+ step = 1
+ unit = 'day'
+ elif interval == 'week':
+ step = 7
+ unit = 'day'
+ elif interval == 'month':
+ step = 1
+ unit = 'month'
+
+ # ایجاد لیست تاریخها
+ dates = []
+ values = []
+
+ current_date = start_date
+ while current_date <= end_date:
+ next_date = current_date + datetime.timedelta(days=step) if unit == 'day' else \
+ datetime.date(current_date.year + (current_date.month + step - 1) // 12,
+ (current_date.month + step - 1) % 12 + 1,
+ 1)
+
+ # دریافت تصویر برای این بازه زمانی
+ image = get_sentinel_imagery(current_date.strftime('%Y-%m-%d'),
+ next_date.strftime('%Y-%m-%d'),
+ aoi)
+
+ if image is not None:
+ # محاسبه میانگین شاخص در منطقه مورد نظر
+ mean_value = image.select(index_name).reduceRegion(
+ reducer=ee.Reducer.mean(),
+ geometry=aoi,
+ scale=10
+ ).get(index_name).getInfo()
+
+ if mean_value is not None:
+ dates.append(current_date.strftime('%Y-%m-%d'))
+ values.append(mean_value)
+
+ current_date = next_date
+
+ # ایجاد دیتافریم برای نمودار
+ if len(dates) > 0:
+ df = pd.DataFrame({
+ 'Date': dates,
+ index_name: values
+ })
+ return df
+ else:
+ return None
-# ایجاد منوی ناوبری جذاب
-selected = option_menu(
- menu_title=None,
- options=["داشبورد", "نقشه مزارع", "ورود اطلاعات", "تحلیل دادهها", "گزارشگیری", "تنظیمات"],
- 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": "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)"},
- }
-)
+# تابع برای دانلود تصویر نقشه
+def get_map_download_link(m, filename="map.html"):
+ """تولید لینک دانلود برای نقشه"""
+ m.to_html(filename)
+ with open(filename, 'rb') as f:
+ html_data = f.read()
+
+ b64 = base64.b64encode(html_data).decode()
+ href = f'دانلود نقشه '
+ return href
-# داشبورد
-if selected == "داشبورد":
- st.markdown('', unsafe_allow_html=True)
- st.markdown("### نمای کلی مزارع", unsafe_allow_html=True)
- st.markdown('
', unsafe_allow_html=True)
+# تابع برای رتبهبندی مزارع بر اساس شاخصها
+def rank_farms(df, index_values):
+ """رتبهبندی مزارع بر اساس مقادیر شاخصها"""
+ if df is None or index_values is None or len(index_values) == 0:
+ return None
- # معیارهای داشبورد با انیمیشن
- col1, col2, col3, col4 = st.columns(4)
+ # ترکیب دادههای مزارع با مقادیر شاخصها
+ farm_ranks = df.copy()
- 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)
+ # اضافه کردن مقادیر شاخصها (در اینجا فرض میکنیم که index_values یک دیکشنری است)
+ for farm_id, values in index_values.items():
+ for index_name, value in values.items():
+ farm_ranks.loc[farm_ranks['مزرعه'] == farm_id, index_name] = value
- with col2:
- 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)
+ # رتبهبندی بر اساس NDVI (به عنوان مثال)
+ if 'NDVI' in farm_ranks.columns:
+ farm_ranks['رتبه NDVI'] = farm_ranks['NDVI'].rank(ascending=False)
- with col3:
- 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)
+ return farm_ranks
+
+# تابع اصلی برنامه
+def main():
+ # عنوان اصلی
+ st.title("داشبورد مانیتورینگ مزارع نیشکر دهخدا")
- with col4:
- 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)
+ # احراز هویت GEE
+ gee_initialized = initialize_gee()
- # تبهای داشبورد با انیمیشن
- tab1, tab2, tab3, tab4 = st.tabs(["نمای کلی", "نقشه مزارع", "نمودارها", "دادهها"])
+ if not gee_initialized:
+ st.error("اتصال به Google Earth Engine برقرار نشد. لطفاً فایل احراز هویت را بررسی کنید.")
+ return
- with tab1:
- st.markdown('', unsafe_allow_html=True)
- st.markdown("### توزیع واریتهها و سن محصول", unsafe_allow_html=True)
-
- col1, col2 = st.columns(2)
-
- with col1:
- variety_counts = farm_df['Variety'].value_counts().reset_index()
- variety_counts.columns = ['Variety', 'Count']
- fig = px.pie(
- variety_counts,
- 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),
- template="plotly_white",
- height=400
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
-
- with col2:
- age_counts = farm_df['Age'].value_counts().reset_index()
- age_counts.columns = ['Age', 'Count']
- fig = px.pie(
- age_counts,
- 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),
- template="plotly_white",
- height=400
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
-
- st.markdown("### اطلاعات کلی مزارع")
-
- total_area = farm_df['Area'].sum()
-
- col1, col2, col3 = st.columns(3)
- 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)
-
- st.markdown('
', unsafe_allow_html=True)
-
- st_lottie(lottie_farm, height=350, key="farm_animation", speed=1.2)
- st.markdown('
', unsafe_allow_html=True)
+ # خواندن دادهها
+ df = load_data()
- with tab2:
- st.markdown('', unsafe_allow_html=True)
- st.markdown("### نقشه مزارع", unsafe_allow_html=True)
-
- if coordinates_df is not None and not coordinates_df.empty:
- m = folium.Map(location=[31.45, 48.72], zoom_start=12, tiles='CartoDB positron')
- for _, farm in coordinates_df.iterrows():
- 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['Variety'].iloc[0]
- age = farm_info['Age'].iloc[0]
- area = farm_info['Area'].iloc[0]
- popup_text = f"""
-
-
مزرعه {name}
-
واریته: {variety}
-
سن: {age}
-
مساحت: {area} هکتار
-
- """
- else:
- popup_text = f"
مزرعه {name}
"
- folium.Marker(
- [lat, lon],
- popup=folium.Popup(popup_text, max_width=300),
- tooltip=f"مزرعه {name}",
- icon=folium.Icon(color='#2ecc71', icon='leaf', prefix='fa')
- ).add_to(m)
- st.markdown('
', unsafe_allow_html=True)
- folium_static(m, width=1000, height=600)
- st.markdown('
', unsafe_allow_html=True)
- else:
- st.warning("دادههای مختصات در دسترس نیست.", icon="⚠️")
- st.markdown('
', unsafe_allow_html=True)
+ if df is None:
+ st.error("خواندن دادهها با مشکل مواجه شد. لطفاً فایل CSV را بررسی کنید.")
+ return
- with tab3:
- st.markdown('', unsafe_allow_html=True)
- st.markdown("### نمودار رشد هفتگی", unsafe_allow_html=True)
-
- col1, col2 = st.columns(2)
- with col1:
- selected_variety = st.selectbox(
- "انتخاب واریته",
- ["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['Age'].unique()),
- format_func=lambda x: "همه سنین" if x == "all" else x,
- key="growth_age",
- help="سن موردنظر را برای تحلیل انتخاب کنید"
- )
-
- growth_data = generate_real_growth_data(selected_variety, selected_age)
-
- chart_tab1, chart_tab2 = st.tabs(["میانگین رشد", "رشد مزارع فردی"])
-
- with chart_tab1:
- 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='#2ecc71', width=4),
- marker=dict(size=10, color='#2ecc71')
- ))
- fig.update_layout(
- title='میانگین رشد هفتگی',
- xaxis_title='هفته',
- yaxis_title='ارتفاع (سانتیمتر)',
- font=dict(family='Vazirmatn', size=16),
- hovermode='x unified',
- template='plotly_white',
- height=500,
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff'
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
-
- with chart_tab2:
- if growth_data['individual']:
- fig = go.Figure()
- 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=3),
- marker=dict(size=8, color=colors[i % len(colors)])
- ))
- fig.update_layout(
- title='رشد هفتگی مزارع فردی',
- xaxis_title='هفته',
- yaxis_title='ارتفاع (سانتیمتر)',
- font=dict(family='Vazirmatn', size=16),
- hovermode='x unified',
- template='plotly_white',
- height=500,
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff'
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
- else:
- st.warning("دادهای برای نمایش وجود ندارد.", icon="⚠️")
- st.markdown('
', unsafe_allow_html=True)
+ # تبدیل ستونهای مختصات به عدد
+ df['طول جغرافیایی'] = pd.to_numeric(df['طول جغرافیایی'], errors='coerce')
+ df['عرض جغرافیایی'] = pd.to_numeric(df['عرض جغرافیایی'], errors='coerce')
- with tab4:
- st.markdown('', unsafe_allow_html=True)
- st.markdown("### دادههای مزارع", unsafe_allow_html=True)
-
- search_term = st.text_input(
- "جستجو در دادهها",
- placeholder="نام مزرعه، واریته، سن و...",
- help="عبارت موردنظر را برای جستجو وارد کنید"
- )
-
- if search_term:
- filtered_df = farm_df[
- 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
-
- if not filtered_df.empty:
- 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="دادههای فیلترشده را دانلود کنید"
- )
- st.dataframe(
- filtered_df,
- use_container_width=True,
- height=450,
- hide_index=True
- )
- st.info(f"نمایش {len(filtered_df)} مزرعه از {len(farm_df)} مزرعه", icon="ℹ️")
- else:
- st.warning("هیچ دادهای یافت نشد.", icon="⚠️")
- st.markdown('
', unsafe_allow_html=True)
-
-# صفحه نقشه
-elif selected == "نقشه مزارع":
- st.markdown('', unsafe_allow_html=True)
- st.markdown("## نقشه مزارع با شاخصهای ماهوارهای", unsafe_allow_html=True)
+ # حذف ردیفهای با مختصات نامعتبر
+ df = df[~((df['طول جغرافیایی'] == 0) | (df['عرض جغرافیایی'] == 0) |
+ df['طول جغرافیایی'].isna() | df['عرض جغرافیایی'].isna())]
- col1, col2 = st.columns([1, 3])
+ # ایجاد ستونهای جدید برای نمایش بهتر
+ df['مزرعه_نمایشی'] = df['مزرعه'].astype(str)
- with col1:
- st.markdown('
', unsafe_allow_html=True)
- st.markdown("### تنظیمات نقشه")
-
- selected_farm = st.selectbox(
- "انتخاب مزرعه",
- options=coordinates_df['Farm_ID'].tolist(),
- index=0,
- format_func=lambda x: f"مزرعه {x}",
- help="مزرعه موردنظر را برای نمایش نقشه انتخاب کنید"
- )
-
- selected_date = st.date_input(
- "انتخاب تاریخ",
- value=datetime.now(),
- format="YYYY-MM-DD",
- help="تاریخی را برای تولید نقشه انتخاب کنید"
- )
-
- selected_layer = st.selectbox(
- "انتخاب شاخص",
- options=["NDVI", "NDMI", "EVI", "NDWI"],
- format_func=lambda x: {
- "NDVI": "شاخص پوشش گیاهی (NDVI)",
- "NDMI": "شاخص رطوبت (NDMI)",
- "EVI": "شاخص پیشرفته گیاهی (EVI)",
- "NDWI": "شاخص آب (NDWI)"
- }[x],
- help="شاخص موردنظر را برای تحلیل انتخاب کنید"
- )
-
- generate_map = st.button(
- "تولید نقشه",
- type="primary",
- use_container_width=True,
- help="نقشه را با تنظیمات انتخابشده تولید کنید"
- )
+ # ایجاد sidebar
+ st.sidebar.title("فیلترها و تنظیمات")
+
+ # فیلتر روز هفته
+ days_of_week = df['روزهای هفته'].unique().tolist()
+ selected_day = st.sidebar.selectbox("انتخاب روز هفته", days_of_week)
+
+ # فیلتر مزرعه
+ filtered_df = df[df['روزهای هفته'] == selected_day]
+ farm_ids = filtered_df['مزرعه'].unique().tolist()
+ selected_farm = st.sidebar.selectbox("انتخاب مزرعه", farm_ids)
+
+ # فیلتر شاخص
+ indices = ['NDVI', 'EVI', 'NDMI', 'LAI', 'Biomass', 'MSI', 'Chlorophyll']
+ selected_index = st.sidebar.selectbox("انتخاب شاخص", indices)
+
+ # تنظیمات تاریخ
+ st.sidebar.subheader("بازه زمانی")
+ today = datetime.date.today()
+ start_date = st.sidebar.date_input("تاریخ شروع", today - datetime.timedelta(days=30))
+ end_date = st.sidebar.date_input("تاریخ پایان", today)
+
+ # تنظیمات نمایش نقشه
+ st.sidebar.subheader("تنظیمات نقشه")
+ map_zoom = st.sidebar.slider("بزرگنمایی نقشه", 10, 18, 13)
+
+ # دکمه اعمال فیلترها
+ apply_filters = st.sidebar.button("اعمال فیلترها")
+
+ # نمایش اطلاعات مزرعه انتخاب شده
+ if selected_farm:
+ farm_data = filtered_df[filtered_df['مزرعه'] == selected_farm].iloc[0]
- st.markdown('
', unsafe_allow_html=True)
+ st.subheader(f"اطلاعات مزرعه {selected_farm}")
- st.markdown("### راهنمای شاخصها")
+ # نمایش اطلاعات در چند ستون
+ col1, col2, col3 = st.columns(3)
- 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)
- """, unsafe_allow_html=True)
+ with col1:
+ st.markdown(f"**کانال:** {farm_data['کانال']}")
+ st.markdown(f"**اداره:** {farm_data['اداره']}")
+ st.markdown(f"**مساحت داشت:** {farm_data['مساحت داشت']} هکتار")
- 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)
- """, unsafe_allow_html=True)
+ with col2:
+ st.markdown(f"**واریته:** {farm_data['واریته']}")
+ st.markdown(f"**سن:** {farm_data['سن']}")
+ st.markdown(f"**روز هفته:** {farm_data['روزهای هفته']}")
- with st.expander("شاخص پیشرفته گیاهی (EVI)", expanded=selected_layer == "EVI"):
- st.markdown("""
- **شاخص پیشرفته پوشش گیاهی (EVI)** نسخه بهبودیافته NDVI است که حساسیت کمتری به اثرات خاک و اتمسفر دارد.
+ with col3:
+ st.markdown(f"**طول جغرافیایی:** {farm_data['طول جغرافیایی']}")
+ st.markdown(f"**عرض جغرافیایی:** {farm_data['عرض جغرافیایی']}")
+
+ # ایجاد تبها برای نمایش نقشه و نمودارها
+ tab1, tab2, tab3 = st.tabs(["نقشه", "نمودارها", "جدول مقایسه"])
+
+ with tab1:
+ if apply_filters and selected_farm:
+ # دریافت مختصات مزرعه انتخاب شده
+ farm_data = filtered_df[filtered_df['مزرعه'] == selected_farm].iloc[0]
+ center_lat = farm_data['عرض جغرافیایی']
+ center_lon = farm_data['طول جغرافیایی']
- - **مقادیر بالا (0.4 تا 1.0)**: پوشش گیاهی متراکم و سالم
- - **مقادیر متوسط (0.2 تا 0.4)**: پوشش گیاهی متوسط
- - **مقادیر پایین (0.0 تا 0.2)**: پوشش گیاهی کم
+ # ایجاد منطقه مورد نظر (AOI) - یک بافر 500 متری اطراف نقطه مرکزی مزرعه
+ point = ee.Geometry.Point([center_lon, center_lat])
+ aoi = point.buffer(500)
- فرمول: 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("""
- **شاخص تفاضل نرمالشده آب (NDWI)** برای شناسایی پهنههای آبی و ارزیابی محتوای آب در گیاهان استفاده میشود.
+ # ایجاد نقشه
+ m = create_map(center_lat, center_lon, map_zoom)
- - **مقادیر بالا (0.3 تا 1.0)**: پهنههای آبی
- - **مقادیر متوسط (0.0 تا 0.3)**: محتوای آب متوسط
- - **مقادیر پایین (-1.0 تا 0.0)**: محتوای آب کم یا خاک خشک
+ # دریافت تصاویر Sentinel-2
+ imagery = get_sentinel_imagery(start_date.strftime('%Y-%m-%d'),
+ end_date.strftime('%Y-%m-%d'),
+ aoi)
- فرمول: NDWI = (GREEN - NIR) / (GREEN + NIR)
- """, unsafe_allow_html=True)
-
- st.markdown('', unsafe_allow_html=True)
-
- with col2:
- 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('
'):
- 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=900, height=600)
- st.success(f"نقشه {selected_layer} برای مزرعه {selected_farm} با موفقیت تولید شد.", icon="✅")
- else:
- st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.", icon="❌")
- elif 'last_map' in st.session_state:
- folium_static(st.session_state.last_map, width=900, height=600)
- st.markdown('
', unsafe_allow_html=True)
- st.info("""
- **نکته:** این نقشه بر اساس تصاویر ماهوارهای Sentinel-2 تولید شده است.
- برای دقت بیشتر، تاریخی را انتخاب کنید که ابرناکی کمتری داشته باشد.
- """, icon="ℹ️")
-
- with stats_tab:
- if 'last_map' in st.session_state:
- stats = calculate_farm_stats(selected_farm, selected_layer)
+ if imagery is not None:
+ # تنظیم پارامترهای نمایش برای شاخص انتخاب شده
+ vis_params = {
+ 'NDVI': {'min': -0.2, 'max': 0.8, 'palette': ['red', 'yellow', 'green']},
+ 'EVI': {'min': -0.2, 'max': 1, 'palette': ['red', 'yellow', 'green']},
+ 'NDMI': {'min': -0.2, 'max': 0.8, 'palette': ['red', 'yellow', 'blue']},
+ 'LAI': {'min': 0, 'max': 5, 'palette': ['white', 'lightgreen', 'darkgreen']},
+ 'Biomass': {'min': 0, 'max': 5, 'palette': ['white', 'lightgreen', 'darkgreen']},
+ 'MSI': {'min': 0, 'max': 2, 'palette': ['blue', 'yellow', 'red']},
+ 'Chlorophyll': {'min': 0, 'max': 5, 'palette': ['white', 'yellow', 'green']}
+ }
- col1, col2, col3, col4 = st.columns(4)
+ # اضافه کردن لایه شاخص به نقشه
+ m = add_index_layer(m, imagery, selected_index, vis_params[selected_index], f"شاخص {selected_index}")
- with col1:
- 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)
+ # اضافه کردن نقاط مزارع به نقشه
+ for _, row in filtered_df.iterrows():
+ folium.Marker(
+ location=[row['عرض جغرافیایی'], row['طول جغرافیایی']],
+ popup=f"مزرعه: {row['مزرعه']}
واریته: {row['واریته']}
سن: {row['سن']}",
+ tooltip=f"مزرعه {row['مزرعه']}",
+ icon=folium.Icon(color='blue' if row['مزرعه'] != selected_farm else 'red')
+ ).add_to(m)
- with col2:
- 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)
+ # اضافه کردن کنترلهای نقشه
+ m.add_control(Draw(export=True))
+ m.add_control(Fullscreen())
+ m.add_control(MeasureControl())
- with col3:
- 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)
+ # نمایش نقشه
+ folium_static(m)
- with col4:
- 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)
+ # دکمه دانلود نقشه
+ st.markdown(get_map_download_link(m), unsafe_allow_html=True)
- fig = px.histogram(
- x=stats["histogram_data"],
- nbins=20,
- title=f"توزیع مقادیر {selected_layer} در مزرعه {selected_farm}",
- labels={"x": f"مقدار {selected_layer}", "y": "فراوانی"},
- color_discrete_sequence=["#2ecc71"]
- )
- fig.update_layout(
- font=dict(family="Vazirmatn", size=14),
- template="plotly_white",
- bargap=0.1,
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff',
- height=400
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
+ # نمایش راهنمای رنگها
+ st.subheader("راهنمای رنگها")
- dates = pd.date_range(end=selected_date, periods=30, freq='D')
- values = [stats["mean"] + np.random.normal(0, stats["std_dev"] / 2) for _ in range(30)]
- values = np.clip(values, stats["min"], stats["max"])
+ if selected_index in ['NDVI', 'EVI']:
+ st.markdown("""
+ -
قرمز : وضعیت ضعیف (0.0-0.2)
+ -
زرد : وضعیت متوسط (0.2-0.5)
+ -
سبز : وضعیت خوب (0.5-0.8)
+ """, unsafe_allow_html=True)
+ elif selected_index == 'NDMI':
+ st.markdown("""
+ -
قرمز : خشک (0.0-0.2)
+ -
زرد : رطوبت متوسط (0.2-0.5)
+ -
آبی : رطوبت بالا (0.5-0.8)
+ """, unsafe_allow_html=True)
+ elif selected_index in ['LAI', 'Biomass']:
+ st.markdown("""
+ -
سفید : مقدار کم (0-1)
+ -
سبز روشن : مقدار متوسط (1-3)
+ -
سبز تیره : مقدار زیاد (3-5)
+ """, unsafe_allow_html=True)
- fig = px.line(
- x=dates,
- y=values,
- title=f"روند تغییرات {selected_layer} در 30 روز گذشته",
- labels={"x": "تاریخ", "y": f"مقدار {selected_layer}"},
- markers=True,
- line_shape="spline"
- )
- fig.update_layout(
- font=dict(family="Vazirmatn", size=14),
- template="plotly_white",
- hovermode="x unified",
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff',
- height=400
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
+ # محاسبه میانگین شاخص برای مزرعه انتخاب شده
+ mean_value = imagery.select(selected_index).reduceRegion(
+ reducer=ee.Reducer.mean(),
+ geometry=aoi,
+ scale=10
+ ).get(selected_index).getInfo()
- farm_names = coordinates_df['Farm_ID'].tolist()[:5]
- comparison_values = [stats["mean"] + np.random.uniform(-0.2, 0.2) for _ in range(len(farm_names))]
-
- 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", size=14),
- template="plotly_white",
- coloraxis_showscale=False,
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff',
- height=400
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
+ if mean_value is not None:
+ st.metric(f"میانگین {selected_index} مزرعه {selected_farm}", f"{mean_value:.4f}")
else:
- st.warning("لطفاً ابتدا یک نقشه تولید کنید.", icon="⚠️")
- st.markdown('
', unsafe_allow_html=True)
-
-# صفحه ورود اطلاعات
-elif selected == "ورود اطلاعات":
- st.markdown('', unsafe_allow_html=True)
- st.markdown("## ورود اطلاعات روزانه مزارع", unsafe_allow_html=True)
-
- tab1, tab2 = st.tabs(["ورود دستی", "آپلود فایل"])
+ st.warning("تصویر ماهوارهای مناسبی برای بازه زمانی انتخاب شده یافت نشد. لطفاً بازه زمانی دیگری را انتخاب کنید.")
- with tab1:
- 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}",
- help="هفته موردنظر را برای ورود اطلاعات انتخاب کنید"
- )
-
- with col2:
- days = day_df['Day'].unique().tolist()
- selected_day = st.selectbox("انتخاب روز", options=days, help="روز موردنظر را برای ورود اطلاعات انتخاب کنید")
-
- 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_week} و روز {selected_day} در پایگاه داده وجود ندارد.", icon="⚠️")
- else:
- st.markdown("### ورود دادههای مزارع")
-
- data_key = f"data_{selected_week}_{selected_day}"
- if data_key not in st.session_state:
- st.session_state[data_key] = pd.DataFrame({
- '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)
- })
+ with tab2:
+ if apply_filters and selected_farm:
+ # دریافت مختصات مزرعه انتخاب شده
+ farm_data = filtered_df[filtered_df['مزرعه'] == selected_farm].iloc[0]
+ center_lat = farm_data['عرض جغرافیایی']
+ center_lon = farm_data['طول جغرافیایی']
- edited_df = st.data_editor(
- st.session_state[data_key],
- use_container_width=True,
- num_rows="fixed",
- column_config={
- "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
- )
+ # ایجاد منطقه مورد نظر (AOI)
+ point = ee.Geometry.Point([center_lon, center_lat])
+ aoi = point.buffer(500)
- for i in range(len(edited_df)):
- stations = [
- 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('CurrentHeight')] = round(sum(valid_stations) / len(valid_stations), 1)
+ # انتخاب بازه زمانی برای نمودار
+ time_interval = st.radio("انتخاب بازه زمانی", ["روزانه", "هفتگی", "ماهانه"], horizontal=True)
+ interval_map = {"روزانه": "day", "هفتگی": "week", "ماهانه": "month"}
- st.session_state[data_key] = edited_df
+ # ایجاد نمودار زمانی
+ time_series_df = create_time_series(aoi, selected_index, start_date, end_date, interval_map[time_interval])
- if st.button("ذخیره اطلاعات", type="primary", use_container_width=True, help="دادهها را ذخیره کنید"):
- new_data = edited_df.copy()
- new_data['Week'] = int(selected_week)
- new_data['Measurement_Date'] = (datetime.now() - timedelta(weeks=(22 - int(selected_week)))).strftime('%Y-%m-%d')
- 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'])
+ if time_series_df is not None and not time_series_df.empty:
+ fig = px.line(time_series_df, x='Date', y=selected_index,
+ title=f"نمودار زمانی {selected_index} برای مزرعه {selected_farm}")
+ fig.update_layout(xaxis_title="تاریخ", yaxis_title=selected_index)
+ st.plotly_chart(fig, use_container_width=True)
- st.session_state.heights_df = pd.concat([st.session_state.heights_df, new_data], ignore_index=True)
- st.success(f"دادههای هفته {selected_week} برای روز {selected_day} با موفقیت ذخیره شدند.", icon="✅")
- st.balloons()
-
- with tab2:
- st.markdown("### آپلود فایل اکسل")
-
- uploaded_file = st.file_uploader(
- "فایل اکسل یا CSV خود را آپلود کنید",
- type=["xlsx", "xls", "csv"],
- help="فایل دادههای مزارع را آپلود کنید"
- )
-
- if uploaded_file is not None:
- try:
- if uploaded_file.name.endswith('.csv'):
- df = pd.read_csv(uploaded_file)
- else:
- df = pd.read_excel(uploaded_file)
- st.dataframe(df, use_container_width=True)
+ # نمایش دادههای نمودار
+ st.dataframe(time_series_df)
- 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}", icon="❌")
-
- st.markdown("### راهنمای فرمت فایل")
- st.markdown("""
- فایل اکسل یا CSV باید شامل ستونهای زیر باشد:
-
- - Farm_ID
- - Station1 تا Station5
- - Well1 و Well2
- - CurrentMoisture (رطوبت)
- - CurrentNitrogen
-
- میتوانید از [این فایل نمونه](https://example.com/sample.xlsx) به عنوان الگو استفاده کنید.
- """, unsafe_allow_html=True)
-
- st.markdown("""
-
-
-
-
-
-
-
فایل خود را اینجا رها کنید یا روی دکمه بالا کلیک کنید
-
- """, unsafe_allow_html=True)
- st.markdown('
', unsafe_allow_html=True)
-
-# صفحه تحلیل دادهها
-elif selected == "تحلیل دادهها":
- st.markdown('', unsafe_allow_html=True)
- st.markdown("## تحلیل هوشمند دادهها", unsafe_allow_html=True)
-
- col1, col2 = st.columns([1, 2])
-
- with col1:
- st_lottie(lottie_analysis, height=250, key="analysis_animation", speed=1.2)
-
- with col2:
- st.markdown("""
-
-
تحلیل پیشرفته دادههای مزارع
-
در این بخش میتوانید تحلیلهای پیشرفته روی دادههای مزارع انجام دهید و روندها و الگوهای مختلف را بررسی کنید.
-
- """, unsafe_allow_html=True)
-
- tab1, tab2, tab3, tab4 = st.tabs(["تحلیل رشد", "مقایسه واریتهها", "تحلیل رطوبت", "پیشبینی"])
-
- with tab1:
- st.markdown("### تحلیل رشد مزارع")
-
- col1, col2 = st.columns(2)
-
- with col1:
- selected_variety = st.selectbox(
- "انتخاب واریته",
- ["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['Age'].unique()),
- format_func=lambda x: "همه سنین" if x == "all" else x,
- key="growth_age",
- help="سن موردنظر را برای تحلیل رشد انتخاب کنید"
- )
-
- growth_data = generate_real_growth_data(selected_variety, selected_age)
-
- if growth_data['individual']:
- chart_data = []
- for farm_data in growth_data['individual']:
- for i, week in enumerate(farm_data['weeks']):
- chart_data.append({
- 'Farm': farm_data['farm_id'],
- 'Week': week,
- 'Height': farm_data['heights'][i],
- 'Variety': farm_data['variety'],
- 'Age': farm_data['age']
- })
-
- chart_df = pd.DataFrame(chart_data)
-
- chart = alt.Chart(chart_df).mark_line(point=True).encode(
- x=alt.X('Week:Q', title='هفته'),
- y=alt.Y('Height:Q', title='ارتفاع (سانتیمتر)'),
- color=alt.Color('Farm:N', title='مزرعه'),
- tooltip=['Farm', 'Week', 'Height', 'Variety', 'Age']
- ).properties(
- width='container',
- height=450,
- title='روند رشد مزارع بر اساس هفته'
- ).interactive()
-
- st.altair_chart(chart, use_container_width=True)
-
- st.markdown("### تحلیل نرخ رشد")
-
- growth_rates = []
- for farm_data in growth_data['individual']:
- heights = farm_data['heights']
- for i in range(1, len(heights)):
- 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)
-
- chart = alt.Chart(growth_rate_df).mark_bar().encode(
- x=alt.X('Week:O', title='هفته'),
- y=alt.Y('mean(Growth Rate):Q', title='نرخ رشد (سانتیمتر در هفته)'),
- color=alt.Color('Farm:N', title='مزرعه'),
- tooltip=['Farm', 'Week', 'mean(Growth Rate)']
- ).properties(
- width='container',
- height=450,
- title='نرخ رشد هفتگی مزارع'
- ).interactive()
-
- st.altair_chart(chart, use_container_width=True)
- else:
- st.warning("دادهای برای نمایش وجود ندارد.", icon="⚠️")
-
- with tab2:
- st.markdown("### مقایسه واریتهها")
-
- variety_age_groups = farm_df.groupby(['Variety', 'Age']).size().reset_index(name='Count')
-
- fig = px.density_heatmap(
- variety_age_groups,
- x='Variety',
- y='Age',
- z='Count',
- title='توزیع مزارع بر اساس واریته و سن',
- color_continuous_scale='Viridis'
- )
- fig.update_layout(
- font=dict(family="Vazirmatn", size=14),
- template="plotly_white",
- xaxis_title="واریته",
- yaxis_title="سن",
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff',
- height=450
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
-
- variety_heights = farm_df.groupby('Variety')['CurrentHeight'].apply(list).to_dict()
-
- fig = go.Figure()
- for variety, heights in variety_heights.items():
- fig.add_trace(go.Box(
- 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", size=14),
- template="plotly_white",
- boxmode='group',
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff',
- height=450
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
-
- variety_stats = {}
- for variety, heights in variety_heights.items():
- variety_stats[variety] = {
- 'میانگین': np.mean(heights),
- 'میانه': np.median(heights),
- 'انحراف معیار': np.std(heights),
- 'حداقل': np.min(heights),
- 'حداکثر': np.max(heights)
- }
- variety_stats_df = pd.DataFrame(variety_stats).T
- st.dataframe(variety_stats_df, use_container_width=True)
+ # دکمه دانلود دادههای نمودار
+ csv = time_series_df.to_csv(index=False)
+ b64 = base64.b64encode(csv.encode()).decode()
+ href = f'
دانلود دادههای نمودار '
+ st.markdown(href, unsafe_allow_html=True)
+ else:
+ st.warning("دادهای برای نمایش نمودار زمانی یافت نشد. لطفاً بازه زمانی دیگری را انتخاب کنید.")
with tab3:
- st.markdown("### تحلیل رطوبت مزارع")
-
- farms = farm_df['Farm_ID'].unique()[:10]
- dates = pd.date_range(end=datetime.now(), periods=30, freq='D')
-
- moisture_data = []
- for farm in farms:
- farm_data = farm_df[farm_df['Farm_ID'] == farm]
- for date in dates:
- 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,
- 'Moisture': moisture
- })
-
- moisture_df = pd.DataFrame(moisture_data)
-
- fig = px.line(
- moisture_df,
- x='Date',
- y='Moisture',
- color='Farm',
- title='روند رطوبت مزارع در 30 روز گذشته',
- labels={'Date': 'تاریخ', 'Moisture': 'رطوبت (%)', 'Farm': 'مزرعه'}
- )
- fig.update_layout(
- font=dict(family="Vazirmatn", size=14),
- template="plotly_white",
- hovermode="x unified",
- plot_bgcolor='#f5faff',
- paper_bgcolor='#f5faff',
- height=450
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
-
- st.markdown("### همبستگی رطوبت و ارتفاع")
-
- correlation_data = []
- for farm in farms:
- farm_data = farm_df[farm_df['Farm_ID'] == farm]
- for _, row in farm_data.iterrows():
- correlation_data.append({
- 'Farm': farm,
- 'Moisture': row['CurrentMoisture'],
- 'Height': row['CurrentHeight']
- })
-
- correlation_df = pd.DataFrame(correlation_data)
-
- fig = px.scatter(
- correlation_df,
- x='Moisture',
- y='Height',
- color='Farm',
- title='همبستگی بین رطوبت و ارتفاع',
- labels={'Moisture': 'رطوبت (%)', 'Height': 'ارتفاع (سانتیمتر)', 'Farm': 'مزرعه'},
- trendline='ols'
- )
- fig.update_layout(
- 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})
-
- correlation = correlation_df['Moisture'].corr(correlation_df['Height'])
- st.info(f"ضریب همبستگی بین رطوبت و ارتفاع: {correlation:.2f}", icon="ℹ️")
-
- with tab4:
- st.markdown("### پیشبینی رشد مزارع")
-
- selected_farm_for_prediction = st.selectbox(
- "انتخاب مزرعه",
- options=farm_df['Farm_ID'].tolist(),
- format_func=lambda x: f"مزرعه {x}",
- help="مزرعه موردنظر را برای پیشبینی رشد انتخاب کنید"
- )
-
- farm_data = farm_df[farm_df['Farm_ID'] == selected_farm_for_prediction]
- historical_weeks = farm_data['Week'].values
- historical_heights = farm_data['CurrentHeight'].values
-
- if len(historical_weeks) > 1 and len(historical_heights) > 1:
- model = LinearRegression()
- model.fit(historical_weeks.reshape(-1, 1), historical_heights)
+ if apply_filters:
+ st.subheader("مقایسه مزارع")
- 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
+ # انتخاب مزارع برای مقایسه
+ farms_to_compare = st.multiselect("انتخاب مزارع برای مقایسه", farm_ids, default=[selected_farm] if selected_farm else [])
- 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'
- )
- st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
- else:
- st.warning("دادههای کافی برای پیشبینی وجود ندارد.", icon="⚠️")
- st.markdown('
', unsafe_allow_html=True)
-
-# صفحه گزارشگیری
-elif selected == "گزارشگیری":
- st.markdown('', unsafe_allow_html=True)
- st.markdown("## گزارشگیری", unsafe_allow_html=True)
-
- 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="روز موردنظر را برای گزارش انتخاب کنید"
- )
-
- 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)
-
-# صفحه تنظیمات
-elif selected == "تنظیمات":
- st.markdown('', unsafe_allow_html=True)
- st.markdown("## تنظیمات سامانه", unsafe_allow_html=True)
-
- st.markdown("""
-
-
تنظیمات پیشرفته
-
در این بخش میتوانید تنظیمات کلی سامانه، از جمله بهروزرسانی دادهها و پیکربندیهای ظاهری را مدیریت کنید.
-
- """, unsafe_allow_html=True)
-
- st.markdown("### بهروزرسانی دادهها")
-
- if st.button("بارگذاری مجدد دادهها", type="primary", use_container_width=True, help="دادهها را دوباره بارگذاری کنید"):
- st.session_state.heights_df = load_farm_data()
- st.success("دادهها با موفقیت بهروزرسانی شدند.", icon="✅")
-
- st.markdown("### تنظیمات ظاهری")
-
- 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)
+ if farms_to_compare:
+ # ایجاد دیکشنری برای ذخیره مقادیر شاخصها
+ index_values = {}
+
+ # محاسبه مقادیر شاخصها برای هر مزرعه
+ for farm_id in farms_to_compare:
+ farm_data = filtered_df[filtered_df['مزرعه'] == farm_id].iloc[0]
+ center_lat = farm_data['عرض جغرافیایی']
+ center_lon = farm_data['طول جغرافیایی']
+
+ point = ee.Geometry.Point([center_lon, center_lat])
+ aoi = point.buffer(500)
+
+ imagery = get_sentinel_imagery(start_date.strftime('%Y-%m-%d'),
+ end_date.strftime('%Y-%m-%d'),
+ aoi)
+
+ if imagery is not None:
+ # محاسبه میانگین شاخصها
+ values = {}
+ for index_name in indices:
+ mean_value = imagery.select(index_name).reduceRegion(
+ reducer=ee.Reducer.mean(),
+ geometry=aoi,
+ scale=10
+ ).get(index_name).getInfo()
+
+ if mean_value is not None:
+ values[index_name] = mean_value
+
+ index_values[farm_id] = values
+
+ # ایجاد دیتافریم برای مقایسه
+ comparison_data = []
+ for farm_id in farms_to_compare:
+ if farm_id in index_values:
+ row = {'مزرعه': farm_id}
+ row.update(index_values[farm_id])
+ comparison_data.append(row)
+
+ if comparison_data:
+ comparison_df = pd.DataFrame(comparison_data)
+
+ # نمایش جدول مقایسه
+ st.dataframe(comparison_df)
+
+ # ایجاد نمودار مقایسهای
+ if len(comparison_df) > 1: # اگر بیش از یک مزرعه انتخاب شده باشد
+ fig = go.Figure()
+
+ for index_name in indices:
+ if index_name in comparison_df.columns:
+ fig.add_trace(go.Bar(
+ x=comparison_df['مزرعه'],
+ y=comparison_df[index_name],
+ name=index_name
+ ))
+
+ fig.update_layout(
+ title="مقایسه شاخصها بین مزارع",
+ xaxis_title="مزرعه",
+ yaxis_title="مقدار شاخص",
+ barmode='group'
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ # دکمه دانلود دادههای مقایسه
+ csv = comparison_df.to_csv(index=False)
+ b64 = base64.b64encode(csv.encode()).decode()
+ href = f'دانلود دادههای مقایسه '
+ st.markdown(href, unsafe_allow_html=True)
+ else:
+ st.warning("دادهای برای مقایسه مزارع یافت نشد.")
+ else:
+ st.info("لطفاً حداقل یک مزرعه را برای مقایسه انتخاب کنید.")
-# پاورقی
-st.markdown("""
-
-""", unsafe_allow_html=True)
\ No newline at end of file
+# اجرای برنامه
+if __name__ == "__main__":
+ main()
\ No newline at end of file