diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,582 +1,2182 @@
-import streamlit as st
+import streamlit
import pandas as pd
-import ee
-import geemap
-import geemap.foliumap as geemap
-import datetime
import numpy as np
+import folium#
+from streamlit_folium import folium_static
+import ee
import os
+import json
+import time
+from datetime import datetime, timedelta
import plotly.express as px
import plotly.graph_objects as go
+from PIL import Image
+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
-import json
-from datetime import datetime, timedelta
-import time
+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
-# تنظیم صفحه و عنوان برنامه
+# Page configuration with custom theme
st.set_page_config(
- page_title="سیستم مانیتورینگ مزارع نیشکر",
- page_icon="🌱",
+ page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا",
+ page_icon="🌿",
layout="wide",
initial_sidebar_state="expanded"
)
-# استایل و تنظیمات فارسی
+# Custom CSS with modern design and animations
st.markdown("""
""", unsafe_allow_html=True)
-# تنظیم Earth Engine
+# Initialize Earth Engine
@st.cache_resource
-def initialize_ee():
- # مسیر فایل JSON برای احراز هویت
- service_account = 'dehkhodamap-e9f0da4ce9f6514021@ee-esmaeilkiani13877.iam.gserviceaccount.com'
-
- # بررسی وجود فایل اعتبارنامه
- credentials_path = 'ee-esmaeilkiani13877-cfdea6eaf411.json'
-
- if os.path.exists(credentials_path):
- credentials = ee.ServiceAccountCredentials(service_account, credentials_path)
+def initialize_earth_engine():
+ 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)
- else:
- # اگر فایل وجود نداشت، ایجاد آن از طریق متغیر محیطی یا ورودی کاربر
- try:
- # تلاش برای دریافت از متغیر محیطی
- ee_token = os.environ.get('EE_TOKEN')
- if ee_token:
- with open(credentials_path, 'w') as f:
- f.write(ee_token)
- credentials = ee.ServiceAccountCredentials(service_account, credentials_path)
- ee.Initialize(credentials)
- else:
- # اگر در متغیرهای محیطی نبود، از کاربر بخواه
- st.warning("فایل اعتبارنامه Google Earth Engine یافت نشد.")
- ee_key = st.text_area("لطفاً محتوای فایل JSON اعتبارنامه را وارد کنید:")
- if ee_key:
- try:
- with open(credentials_path, 'w') as f:
- f.write(ee_key)
- credentials = ee.ServiceAccountCredentials(service_account, credentials_path)
- ee.Initialize(credentials)
- except Exception as e:
- st.error(f"خطا در احراز هویت: {e}")
- else:
- st.info("برای استفاده از این برنامه، فایل اعتبارنامه GEE ضروری است.")
- ee.Initialize()
- except Exception as e:
- st.error(f"خطا در تنظیم Earth Engine: {e}")
- ee.Initialize()
-
- return True
-
-# شروع تنظیم Earth Engine
-ee_initialized = initialize_ee()
+
+ os.remove(credentials_file)
+
+ return True
+ except Exception as e:
+ st.error(f"خطا در اتصال به Earth Engine: {e}")
+ return False
-# خواندن فایل CSV مزارع
+# Load data
@st.cache_data
def load_farm_data():
try:
- return pd.read_csv('پایگاه داده (1).csv')
- except FileNotFoundError:
- try:
- return pd.read_csv('farm_coordinates.csv')
- except FileNotFoundError:
- st.error("فایل دادههای مزارع یافت نشد. لطفاً فایل CSV را در مسیر پروژه قرار دهید.")
- # ایجاد دیتافریم نمونه
- return pd.DataFrame({
- 'مزرعه': ['مزرعه 1', 'مزرعه 2', 'مزرعه 3'],
- 'سن': [12, 8, 15],
- 'تنوع': ['CP73-21', 'CP69-1062', 'CP57-614'],
- 'طول جغرافیایی': [48.724416, 48.734416, 48.714416],
- 'عرض جغرافیایی': [31.534442, 31.544442, 31.524442]
- })
+ df = pd.read_csv("پایگاه داده (1).csv")
+ return df
+ except Exception as e:
+ st.error(f"خطا در بارگذاری دادههای مزارع: {e}")
+ return pd.DataFrame()
-# بارگیری دادههای مزارع
-farms_df = load_farm_data()
+@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()
-# تبدیل نام ستونها به فارسی اگر به انگلیسی باشند
-column_mapping = {
- 'farm': 'مزرعه',
- 'age': 'سن',
- 'variety': 'تنوع',
- 'longitude': 'طول جغرافیایی',
- 'latitude': 'عرض جغرافیایی'
-}
+# 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()
-farms_df = farms_df.rename(columns={col: column_mapping.get(col, col) for col in farms_df.columns})
+# Function to get weather data
+def get_weather_data(lat, lon, api_key):
+ url = f"http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={api_key}&units=metric"
+ response = requests.get(url)
+ if response.status_code == 200:
+ return response.json()
+ else:
+ return None
-# تابع برای محاسبه شاخصهای گیاهی با استفاده از GEE
-def calculate_vegetation_indices(lat, lon, start_date, end_date):
- # تعریف نقطه مورد نظر
- point = ee.Geometry.Point([lon, lat])
-
- # فیلتر تصاویر Sentinel-2
- s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
- .filterDate(start_date, end_date) \
- .filterBounds(point) \
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10))
-
- if s2.size().getInfo() == 0:
- # اگر تصویری یافت نشد، بازه زمانی را افزایش میدهیم
- s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
- .filterDate(ee.Date(start_date).advance(-30, 'day'), end_date) \
- .filterBounds(point) \
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
-
- # گرفتن آخرین تصویر
- image = ee.Image(s2.sort('system:time_start', False).first())
-
- # محاسبه شاخصها
- ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
- ndwi = image.normalizedDifference(['B3', 'B8']).rename('NDWI')
- ndmi = image.normalizedDifference(['B8', 'B11']).rename('NDMI')
-
- # محاسبه LAI (Leaf Area Index) بر اساس NDVI
- lai = ndvi.expression(
- '3.618 * exp(2.0 * NDVI)', {
- 'NDVI': ndvi
- }).rename('LAI')
-
- # محاسبه CHL (Chlorophyll content) با استفاده از باندهای مرئی و لبه قرمز
- chl = image.expression(
- '((B7 - B5) / (B7 + B5)) * ((B7 / B5))', {
- 'B7': image.select('B7'),
- 'B5': image.select('B5')
- }).rename('CHL')
-
- # استخراج مقادیر برای نقطه مورد نظر
- values = image.addBands(ndvi).addBands(ndwi).addBands(ndmi).addBands(lai).addBands(chl) \
- .reduceRegion(
- reducer=ee.Reducer.mean(),
- geometry=point,
- scale=10
- ).getInfo()
-
- # استخراج تاریخ تصویر
- try:
- image_date = ee.Date(image.get('system:time_start')).format('YYYY-MM-dd').getInfo()
- except:
- image_date = "تاریخ نامشخص"
-
- return {
- 'ndvi': values.get('NDVI', None),
- 'ndwi': values.get('NDWI', None),
- 'ndmi': values.get('NDMI', None),
- 'lai': values.get('LAI', None),
- 'chl': values.get('CHL', None),
- 'date': image_date,
- 'image': image
- }
+# Function to estimate water requirement
+def estimate_water_requirement(farm_id, date_str):
+ api_key = "ed47316a45379e2221a75f813229fb46"
+ farm_row = coordinates_df[coordinates_df['مزرعه'] == farm_id].iloc[0]
+ lat, lon = farm_row['عرض جغرافیایی'], farm_row['طول جغرافیایی']
+ weather_data = get_weather_data(lat, lon, api_key)
+ if weather_data:
+ temperature = weather_data['main']['temp']
+ humidity = weather_data['main']['humidity']
+ # Simple formula for water requirement (mm/day)
+ water_requirement = (temperature - 20) * 0.5 + (100 - humidity) * 0.1
+ return max(0, water_requirement)
+ else:
+ return None
-# تابع برای تبدیل NDVI به مرحله رشد نیشکر (لیف استیج 0-6)
-def calculate_leaf_stage(ndvi):
- if ndvi is None:
+# Create Earth Engine map with indices
+def create_ee_map(farm_id, date_str, layer_type="NDVI"):
+ try:
+ farm_row = coordinates_df[coordinates_df['مزرعه'] == farm_id].iloc[0]
+ lat, lon = farm_row['عرض جغرافیایی'], farm_row['طول جغرافیایی']
+
+ 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)'
+ elif layer_type == "SoilMoisture":
+ s1 = ee.ImageCollection('COPERNICUS/S1_GRD') \
+ .filterDate(start_date, end_date) \
+ .filterBounds(region) \
+ .sort('system:time_start') \
+ .first()
+ index = s1.select('VV').rename('SoilMoisture')
+ viz_params = {'min': -25, 'max': -5, 'palette': ['#00008b', '#add8e6', '#ffffff']}
+ legend_title = 'رطوبت خاک (Soil Moisture)'
+
+ 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')
+ ).add_to(m)
+
+ folium.Circle(
+ [lat, lon],
+ radius=1500,
+ color='green',
+ fill=True,
+ fill_color='green',
+ fill_opacity=0.1
+ ).add_to(m)
+
+ folium.LayerControl().add_to(m)
+
+ legend_html = '''
+
+
''' + legend_title + '''
+
+
+
+
+ '''
+ m.get_root().html.add_child(folium.Element(legend_html))
+
+ return m
+ except Exception as e:
+ st.error(f"خطا در ایجاد نقشه: {e}")
return None
-
- # بر اساس مقادیر استاندارد نیشکر NDVI به مراحل رشد
- if ndvi < 0.2:
- return 0 # بدون پوشش یا کاشت جدید
- elif ndvi < 0.3:
- return 1 # مرحله اولیه جوانه زنی
- elif ndvi < 0.4:
- return 2 # مرحله جوانه زنی پیشرفته
- elif ndvi < 0.5:
- return 3 # مرحله رشد اولیه
- elif ndvi < 0.6:
- return 4 # مرحله رشد میانی
- elif ndvi < 0.7:
- return 5 # مرحله رشد پیشرفته
- else:
- return 6 # مرحله بلوغ کامل
-# تابع برای نمایش نقشه با شاخص NDVI
-def display_ndvi_map(center_lat, center_lon):
- # ایجاد یک نقشه با مرکزیت مشخص
- m = geemap.Map()
- m.setCenter(center_lon, center_lat, 13)
-
- # تعریف محدوده زمانی (یک هفته اخیر)
- end_date = datetime.now()
- start_date = end_date - timedelta(days=30) # افزایش به 30 روز برای اطمینان از وجود تصویر
-
- # فیلتر کلکشن Sentinel-2
- s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
- .filterDate(start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')) \
- .filterBounds(ee.Geometry.Point([center_lon, center_lat])) \
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10)) \
- .sort('system:time_start', False)
-
- # بررسی وجود تصویر
- if s2.size().getInfo() > 0:
- # گرفتن آخرین تصویر
- image = ee.Image(s2.first())
-
- # محاسبه NDVI
- ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
-
- # تعریف پالت رنگی NDVI
- ndvi_vis = {
- 'min': 0.0,
- 'max': 0.8,
- 'palette': [
- '#d73027', # قرمز (تنش شدید)
- '#f46d43', # نارنجی (تنش متوسط)
- '#fdae61', # نارنجی روشن (تنش کم)
- '#fee08b', # زرد (رشد ضعیف)
- '#d9ef8b', # سبز-زرد (رشد متوسط)
- '#a6d96a', # سبز کم رنگ (رشد خوب)
- '#66bd63', # سبز (رشد عالی)
- '#1a9850' # سبز تیره (بهترین حالت رشد)
- ]
- }
+# Generate mock growth data
+def generate_mock_growth_data(farm_data, selected_variety="all", selected_age="all"):
+ weeks = list(range(1, 23))
+
+ filtered_farms = farm_data
+ if selected_variety != "all":
+ filtered_farms = filtered_farms[filtered_farms['واریته'] == selected_variety]
+ if selected_age != "all":
+ filtered_farms = filtered_farms[filtered_farms['سن'] == selected_age]
+
+ farm_growth_data = []
+ for _, farm in filtered_farms.iterrows():
+ base_height = np.random.uniform(50, 100)
+ growth_rate = np.random.uniform(5, 15)
- # اضافه کردن لایه NDVI به نقشه
- m.addLayer(ndvi, ndvi_vis, 'شاخص NDVI')
-
- # اضافه کردن کنترل لایه
- m.add_layer_control()
-
- # اضافه کردن راهنمای نقشه
- legend_dict = {
- '≥ 0.7 (مرحله بلوغ کامل)': '#1a9850',
- '0.6-0.7 (رشد پیشرفته)': '#66bd63',
- '0.5-0.6 (رشد میانی)': '#a6d96a',
- '0.4-0.5 (رشد اولیه)': '#d9ef8b',
- '0.3-0.4 (جوانه زنی پیشرفته)': '#fee08b',
- '0.2-0.3 (جوانه زنی اولیه)': '#fdae61',
- '< 0.2 (کاشت جدید/تنش)': '#d73027'
+ growth_data = {
+ 'farm_id': farm['مزرعه'],
+ 'variety': farm['واریته'],
+ 'age': farm['سن'],
+ 'weeks': weeks,
+ 'heights': [round(base_height + growth_rate * week) for week in weeks]
}
+ farm_growth_data.append(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)))
- m.add_legend(title="راهنمای شاخص NDVI", legend_dict=legend_dict)
+ avg_growth_data = {
+ 'farm_id': 'میانگین',
+ 'variety': 'همه',
+ 'age': 'همه',
+ 'weeks': weeks,
+ 'heights': avg_heights
+ }
- # تاریخ تصویر
- image_date = ee.Date(image.get('system:time_start')).format('YYYY-MM-dd').getInfo()
- st.info(f"تاریخ تصویر استفاده شده: {image_date}")
+ return {
+ 'individual': farm_growth_data,
+ 'average': avg_growth_data
+ }
else:
- st.warning("هیچ تصویری با شرایط مورد نظر (ابر کمتر از 10%) در 30 روز اخیر یافت نشد.")
+ 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"):
+ 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)
+ elif layer_type == "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)
+ elif layer_type == "SoilMoisture":
+ mean = round(np.random.uniform(-20, -10), 2)
+ min_val = round(mean - np.random.uniform(5, 10), 2)
+ max_val = round(mean + np.random.uniform(5, 10), 2)
+ std_dev = round(np.random.uniform(2, 5), 2)
+
+ hist_data = np.random.normal(mean, std_dev, 1000)
+ hist_data = np.clip(hist_data, min_val, max_val)
- return m
+ return {
+ 'mean': mean,
+ 'min': min_val,
+ 'max': max_val,
+ 'std_dev': std_dev,
+ 'histogram_data': hist_data
+ }
+
+# Initialize Earth Engine
+ee_initialized = initialize_earth_engine()
+
+# Load data
+farm_df = load_farm_data()
+coordinates_df = load_coordinates_data()
+
+# Load animations
+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 get_persian_weekday(date):
- persian_days = {
- 0: "دوشنبه",
- 1: "سهشنبه",
- 2: "چهارشنبه",
- 3: "پنجشنبه",
- 4: "جمعه",
- 5: "شنبه",
- 6: "یکشنبه"
- }
- weekday = date.weekday()
- return persian_days[weekday]
+# 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.title("سیستم مانیتورینگ مزارع نیشکر 🌱")
+# Main header
+st.markdown('', unsafe_allow_html=True)
+st.markdown('
سامانه هوشمند پایش مزارع نیشکر دهخدا ', unsafe_allow_html=True)
+st.markdown('
پلتفرم جامع مدیریت، پایش و تحلیل دادههای مزارع نیشکر با استفاده از تصاویر ماهوارهای و هوش مصنوعی
', unsafe_allow_html=True)
+st.markdown('
', unsafe_allow_html=True)
-# منوی اصلی
-selected_tab = option_menu(
+# Create a modern navigation menu
+selected = option_menu(
menu_title=None,
- options=["داشبورد", "نقشه", "گزارشها", "تنظیمات"],
- icons=['speedometer', 'map', 'file-earmark-text', 'gear'],
+ options=["داشبورد", "نقشه مزارع", "ورود اطلاعات", "تحلیل دادهها", "گزارشگیری", "تنظیمات"],
+ icons=["speedometer2", "map", "pencil-square", "graph-up", "file-earmark-text", "gear"],
menu_icon="cast",
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"},
+ }
)
-# نمایش دکمههای روزهای هفته به صورت آنیمیشنی
-if selected_tab == "داشبورد":
- st.header("برنامه هفتگی مانیتورینگ مزارع")
-
- # ایجاد دکمههای روزهای هفته به صورت متحرک
- today = datetime.now()
-
- # تعیین شنبه هفته جاری
- days_since_saturday = (today.weekday() - 5) % 7
- saturday = today - timedelta(days=days_since_saturday)
-
- # ایجاد لیست روزهای هفته از شنبه تا پنجشنبه
- week_days = []
- for i in range(6): # 6 روز از شنبه تا پنجشنبه
- day = saturday + timedelta(days=i)
- persian_day = get_persian_weekday(day)
- day_str = day.strftime("%Y-%m-%d")
- week_days.append((persian_day, day_str))
-
- # نمایش دکمههای روزهای هفته با انیمیشن
- cols = st.columns(6)
- selected_day = None
-
- for i, (day_name, day_date) in enumerate(week_days):
- with cols[i]:
- day_button = st.button(
- f"{day_name}\n{day_date}",
- key=f"day_{i}"
- )
- if day_button:
- selected_day = (day_name, day_date)
+# Dashboard
+if selected == "داشبورد":
+ 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('
', unsafe_allow_html=True)
- # اگر روزی انتخاب شده باشد
- if selected_day:
- st.subheader(f"برنامه مانیتورینگ مزارع برای روز {selected_day[0]}")
+ with col2:
+ active_farms = int(len(farm_df) * 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)
+ 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)
+ st.markdown('
میانگین رطوبت
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ tab1, tab2, tab3, tab4 = st.tabs(["نمای کلی", "نقشه مزارع", "نمودارها", "دادهها"])
+
+ with tab1:
+ st.markdown("### توزیع واریتهها و سن محصول")
- # مثالی از فیلتر کردن مزارع بر اساس روز
- # در یک پروژه واقعی، این بخش باید با منطق کسب و کار واقعی تطبیق داده شود
+ col1, col2 = st.columns(2)
- # شبیهسازی فیلتر بر اساس روز هفته
- weekday_idx = ["شنبه", "یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه"].index(selected_day[0])
+ with col1:
+ variety_counts = farm_df['واریته'].value_counts().reset_index()
+ variety_counts.columns = ['واریته', 'تعداد']
+ fig = px.pie(
+ variety_counts,
+ values='تعداد',
+ names='واریته',
+ 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)
+ )
+ st.plotly_chart(fig, use_container_width=True)
- # برای شبیهسازی، تقسیم مزارع بر اساس باقیمانده تقسیم بر 6
- filtered_farms = farms_df[farms_df.index % 6 == weekday_idx].copy()
+ with col2:
+ age_counts = farm_df['سن'].value_counts().reset_index()
+ age_counts.columns = ['سن', 'تعداد']
+ fig = px.pie(
+ age_counts,
+ values='تعداد',
+ names='سن',
+ 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)
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ st.markdown("### اطلاعات کلی مزارع")
+
+ total_area = farm_df['مساحت'].astype(float).sum()
+
+ col1, col2, col3 = st.columns(3)
+ col1.metric("تعداد کل مزارع", f"{len(farm_df)}")
+ col2.metric("مساحت کل (هکتار)", f"{total_area:.2f}")
+ col3.metric("تعداد کانالها", f"{farm_df['کانال'].nunique()}")
- if len(filtered_farms) > 0:
- # محاسبه شاخصهای گیاهی برای مزارع فیلتر شده
- end_date = datetime.now().strftime('%Y-%m-%d')
- start_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
+ st.markdown(' ', unsafe_allow_html=True)
+ st_lottie(lottie_farm, height=300, key="farm_animation")
+
+ with tab2:
+ st.markdown("### نقشه مزارع")
+
+ 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')
- indices_data = []
+ for _, farm in coordinates_df.iterrows():
+ lat = farm['عرض جغرافیایی']
+ lon = farm['طول جغرافیایی']
+ name = farm['مزرعه']
+
+ farm_info = farm_df[farm_df['مزرعه'] == name]
+ if not farm_info.empty:
+ variety = farm_info['واریته'].iloc[0]
+ age = farm_info['سن'].iloc[0]
+ area = farm_info['مساحت'].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='green', icon='leaf')
+ ).add_to(m)
- progress_bar = st.progress(0)
- status_text = st.empty()
+ st.markdown('', unsafe_allow_html=True)
+ folium_static(m, width=1000, height=600)
+ st.markdown('
', unsafe_allow_html=True)
+ else:
+ st.warning("دادههای مختصات در دسترس نیست.")
+
+ with tab3:
+ st.markdown("### نمودار رشد هفتگی")
+
+ col1, col2 = st.columns(2)
+ with col1:
+ selected_variety = st.selectbox(
+ "انتخاب واریته",
+ ["all"] + list(farm_df['واریته'].unique()),
+ format_func=lambda x: "همه واریتهها" if x == "all" else x
+ )
+
+ with col2:
+ selected_age = st.selectbox(
+ "انتخاب سن",
+ ["all"] + list(farm_df['سن'].unique()),
+ format_func=lambda x: "همه سنین" if x == "all" else x
+ )
+
+ growth_data = generate_mock_growth_data(farm_df, 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='#1a8754', width=3),
+ marker=dict(size=8, color='#1a8754')
+ ))
+ fig.update_layout(
+ title='میانگین رشد هفتگی',
+ xaxis_title='هفته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family='Vazirmatn', size=14),
+ hovermode='x unified',
+ template='plotly_white',
+ height=500
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ with chart_tab2:
+ if growth_data['individual']:
+ fig = go.Figure()
+ colors = ['#1a8754', '#1976d2', '#e65100', '#9c27b0', '#d32f2f']
+ for i, farm_data in enumerate(growth_data['individual'][:5]):
+ fig.add_trace(go.Scatter(
+ x=farm_data['weeks'],
+ y=farm_data['heights'],
+ mode='lines+markers',
+ name=f"مزرعه {farm_data['farm_id']}",
+ line=dict(color=colors[i % len(colors)], width=2),
+ marker=dict(size=6, color=colors[i % len(colors)])
+ ))
+ fig.update_layout(
+ title='رشد هفتگی مزارع فردی',
+ xaxis_title='هفته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family='Vazirmatn', size=14),
+ hovermode='x unified',
+ template='plotly_white',
+ height=500
+ )
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.warning("دادهای برای نمایش وجود ندارد.")
+
+ with tab4:
+ st.markdown("### دادههای مزارع")
+
+ search_term = st.text_input("جستجو در دادهها", placeholder="نام مزرعه، واریته، سن و...")
+
+ if search_term:
+ filtered_df = farm_df[
+ farm_df['مزرعه'].astype(str).str.contains(search_term) |
+ farm_df['واریته'].astype(str).str.contains(search_term) |
+ farm_df['سن'].astype(str).str.contains(search_term) |
+ farm_df['کانال'].astype(str).str.contains(search_term)
+ ]
+ else:
+ filtered_df = farm_df
+
+ 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",
+ )
+ st.dataframe(
+ filtered_df,
+ use_container_width=True,
+ height=400,
+ hide_index=True
+ )
+ st.info(f"نمایش {len(filtered_df)} مزرعه از {len(farm_df)} مزرعه")
+ else:
+ st.warning("هیچ دادهای یافت نشد.")
+
+# Map Page
+elif selected == "نقشه مزارع":
+ st.markdown("## نقشه مزارع با شاخصهای ماهوارهای")
+
+ col1, col2 = st.columns([1, 3])
+
+ with col1:
+ st.markdown('', unsafe_allow_html=True)
+ st.markdown("### تنظیمات نقشه")
+
+ selected_farm = st.selectbox(
+ "انتخاب مزرعه",
+ options=coordinates_df['مزرعه'].tolist(),
+ index=0,
+ format_func=lambda x: f"مزرعه {x}"
+ )
+
+ selected_date = st.date_input(
+ "انتخاب تاریخ",
+ value=datetime.now(),
+ format="YYYY-MM-DD"
+ )
+
+ selected_layer = st.selectbox(
+ "انتخاب شاخص",
+ options=["NDVI", "NDMI", "EVI", "NDWI", "SoilMoisture"],
+ format_func=lambda x: {
+ "NDVI": "شاخص پوشش گیاهی (NDVI)",
+ "NDMI": "شاخص رطوبت (NDMI)",
+ "EVI": "شاخص پیشرفته گیاهی (EVI)",
+ "NDWI": "شاخص آب (NDWI)",
+ "SoilMoisture": "رطوبت خاک (Soil Moisture)"
+ }[x]
+ )
+
+ generate_map = st.button(
+ "تولید نقشه",
+ type="primary",
+ use_container_width=True
+ )
+
+ st.markdown('
', unsafe_allow_html=True)
+
+ st.markdown("### راهنمای شاخصها")
+
+ with st.expander("شاخص پوشش گیاهی (NDVI)", expanded=selected_layer == "NDVI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده پوشش گیاهی (NDVI)** معیاری برای سنجش سلامت و تراکم پوشش گیاهی است.
+ - **مقادیر بالا (0.6 تا 1.0)**: پوشش گیاهی متراکم و سالم
+ - **مقادیر متوسط (0.2 تا 0.6)**: پوشش گیاهی متوسط
+ - **مقادیر پایین (-1.0 تا 0.2)**: پوشش گیاهی کم یا خاک لخت
+ فرمول: NDVI = (NIR - RED) / (NIR + RED)
+ """)
+
+ with st.expander("شاخص رطوبت (NDMI)", expanded=selected_layer == "NDMI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده رطوبت (NDMI)** برای ارزیابی محتوای رطوبت گیاهان استفاده میشود.
+ - **مقادیر بالا (0.4 تا 1.0)**: محتوای رطوبت بالا
+ - **مقادیر متوسط (0.0 تا 0.4)**: محتوای رطوبت متوسط
+ - **مقادیر پایین (-1.0 تا 0.0)**: محتوای رطوبت کم
+ فرمول: NDMI = (NIR - SWIR) / (NIR + SWIR)
+ """)
+
+ with st.expander("شاخص پیشرفته گیاهی (EVI)", expanded=selected_layer == "EVI"):
+ st.markdown("""
+ **شاخص پیشرفته پوشش گیاهی (EVI)** نسخه بهبودیافته NDVI است که حساسیت کمتری به اثرات خاک و اتمسفر دارد.
+ - **مقادیر بالا (0.4 تا 1.0)**: پوشش گیاهی متراکم و سالم
+ - **مقادیر متوسط (0.2 تا 0.4)**: پوشش گیاهی متوسط
+ - **مقادیر پایین (0.0 تا 0.2)**: پوشش گیاهی کم
+ فرمول: EVI = 2.5 * ((NIR - RED) / (NIR + 6*RED - 7.5*BLUE + 1))
+ """)
+
+ with st.expander("شاخص آب (NDWI)", expanded=selected_layer == "NDWI"):
+ st.markdown("""
+ **شاخص تفاضل نرمالشده آب (NDWI)** برای شناسایی پهنههای آبی و ارزیابی محتوای آب در گیاهان استفاده میشود.
+ - **مقادیر بالا (0.3 تا 1.0)**: پهنههای آبی
+ - **مقادیر متوسط (0.0 تا 0.3)**: محتوای آب متوسط
+ - **مقادیر پایین (-1.0 تا 0.0)**: محتوای آب کم یا خاک خشک
+ فرمول: NDWI = (GREEN - NIR) / (GREEN + NIR)
+ """)
+
+ with st.expander("رطوبت خاک (Soil Moisture)", expanded=selected_layer == "SoilMoisture"):
+ st.markdown("""
+ **رطوبت خاک (Soil Moisture)** با استفاده از دادههای راداری Sentinel-1 سطح رطوبت خاک را به صورت داینامیک بررسی میکند.
+ - **مقادیر بالا**: رطوبت خاک بالا
+ - **مقادیر پایین**: رطوبت خاک کم
+ این شاخص به مدیریت بهتر منابع آب کمک میکند.
+ """)
+
+ st.markdown('', unsafe_allow_html=True)
+
+ with col2:
+ map_tab, stats_tab = st.tabs(["نقشه", "آمار و تحلیل"])
+
+ with map_tab:
+ st.markdown('', unsafe_allow_html=True)
- for idx, farm in filtered_farms.iterrows():
- status_text.text(f"در حال محاسبه شاخصهای مزرعه {farm['مزرعه']}...")
-
- try:
- indices = calculate_vegetation_indices(
- farm['عرض جغرافیایی'],
- farm['طول جغرافیایی'],
- start_date,
- end_date
+ 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
)
-
- leaf_stage = calculate_leaf_stage(indices['ndvi'])
-
- indices_data.append({
- 'مزرعه': farm['مزرعه'],
- 'سن': farm['سن'],
- 'تنوع': farm['تنوع'],
- 'NDVI': indices['ndvi'],
- 'NDWI': indices['ndwi'],
- 'NDMI': indices['ndmi'],
- 'LAI': indices['lai'],
- 'CHL': indices['chl'],
- 'مرحله رشد': leaf_stage,
- 'تاریخ تصویر': indices['date']
+ if m:
+ st.session_state.last_map = m
+ folium_static(m, width=800, height=600)
+ st.success(f"نقشه {selected_layer} برای مزرعه {selected_farm} با موفقیت تولید شد.")
+ else:
+ st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.")
+ elif 'last_map' in st.session_state:
+ folium_static(st.session_state.last_map, width=800, height=600)
+
+ st.markdown('
', unsafe_allow_html=True)
+ st.info("""
+ **نکته:** این نقشه بر اساس تصاویر Sentinel-2 و Sentinel-1 تولید شده است.
+ برای دقت بیشتر، تاریخی با ابرناکی کم انتخاب کنید.
+ """)
+
+ with stats_tab:
+ if 'last_map' in st.session_state:
+ stats = calculate_farm_stats(selected_farm, selected_layer)
+
+ col1, col2, col3, col4 = st.columns(4)
+
+ with col1:
+ st.markdown('', unsafe_allow_html=True)
+ st.markdown(f'
{stats["mean"]}
', unsafe_allow_html=True)
+ st.markdown(f'
میانگین {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col2:
+ st.markdown('', unsafe_allow_html=True)
+ st.markdown(f'
{stats["max"]}
', unsafe_allow_html=True)
+ st.markdown(f'
حداکثر {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col3:
+ st.markdown('', unsafe_allow_html=True)
+ st.markdown(f'
{stats["min"]}
', unsafe_allow_html=True)
+ st.markdown(f'
حداقل {selected_layer}
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ with col4:
+ st.markdown('', unsafe_allow_html=True)
+ st.markdown(f'
{stats["std_dev"]}
', unsafe_allow_html=True)
+ st.markdown(f'
انحراف معیار
', unsafe_allow_html=True)
+ st.markdown('
', unsafe_allow_html=True)
+
+ fig = px.histogram(
+ x=stats["histogram_data"],
+ nbins=20,
+ title=f"توزیع مقادیر {selected_layer} در مزرعه {selected_farm}",
+ labels={"x": f"مقدار {selected_layer}", "y": "فراوانی"},
+ color_discrete_sequence=["#1a8754"]
+ )
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ bargap=0.1
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ st.markdown("### تحلیل زمانی")
+ dates = pd.date_range(end=selected_date, periods=30, freq='D')
+ values = np.random.normal(stats["mean"], stats["std_dev"] / 2, 30)
+ values = np.clip(values, stats["min"], stats["max"])
+ fig = px.line(
+ x=dates,
+ y=values,
+ title=f"روند تغییرات {selected_layer} در 30 روز گذشته",
+ labels={"x": "تاریخ", "y": f"مقدار {selected_layer}"},
+ markers=True
+ )
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ hovermode="x unified"
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ st.markdown("### تخمین نیاز آبی")
+ water_requirement = estimate_water_requirement(selected_farm, selected_date.strftime('%Y-%m-%d'))
+ if water_requirement is not None:
+ st.metric("نیاز آبی (mm/day)", f"{water_requirement:.2f}")
+ st.info(f"نیاز آبی تخمینی برای مزرعه {selected_farm}: {water_requirement:.2f} میلیمتر در روز")
+ else:
+ st.warning("دادههای هواشناسی در دسترس نیست.")
+
+ if selected_layer == "SoilMoisture":
+ st.markdown("### پیشنهادات مدیریت آب")
+ if stats["mean"] < -20:
+ st.markdown("- **افزایش آبیاری**: رطوبت خاک بسیار پایین است.")
+ elif stats["mean"] > -10:
+ st.markdown("- **کاهش آبیاری**: رطوبت خاک بیش از حد است.")
+ else:
+ st.markdown("- **مدیریت بهینه**: رطوبت خاک در محدوده مناسب است.")
+ else:
+ st.warning("لطفاً ابتدا یک نقشه تولید کنید.")
+
+# Data Entry Page
+elif selected == "ورود اطلاعات":
+ st.markdown("## ورود اطلاعات روزانه مزارع")
+
+ tab1, tab2 = st.tabs(["ورود دستی", "آپلود فایل"])
+
+ 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}"
+ )
+
+ with col2:
+ selected_day = st.selectbox(
+ "انتخاب روز",
+ options=["شنبه", "یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه"]
+ )
+
+ filtered_farms = farm_df[farm_df['روز'] == selected_day]
+
+ if filtered_farms.empty:
+ st.warning(f"هیچ مزرعهای برای روز {selected_day} در پایگاه داده وجود ندارد.")
+ 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({
+ 'مزرعه': 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)
+ })
+
+ edited_df = st.data_editor(
+ st.session_state[data_key],
+ use_container_width=True,
+ num_rows="fixed",
+ column_config={
+ "مزرعه": st.column_config.TextColumn("مزرعه", disabled=True),
+ "ایستگاه 1": st.column_config.NumberColumn("ایستگاه 1", min_value=0, max_value=300, step=1),
+ "ایستگاه 2": st.column_config.NumberColumn("ایستگاه 2", min_value=0, max_value=300, step=1),
+ "ایستگاه 3": st.column_config.NumberColumn("ایستگاه 3", min_value=0, max_value=300, step=1),
+ "ایستگاه 4": st.column_config.NumberColumn("ایستگاه 4", min_value=0, max_value=300, step=1),
+ "ایستگاه 5": st.column_config.NumberColumn("ایستگاه 5", min_value=0, max_value=300, step=1),
+ "چاهک 1": st.column_config.NumberColumn("چاهک 1", min_value=0, max_value=300, step=1),
+ "چاهک 2": st.column_config.NumberColumn("چاهک 2", min_value=0, max_value=300, step=1),
+ "رطوبت غلاف": st.column_config.NumberColumn("رطوبت غلاف", min_value=0, max_value=100, step=1),
+ "نیتروژن": st.column_config.NumberColumn("نیتروژن", min_value=0, max_value=100, step=1),
+ "میانگین ارتفاع": st.column_config.NumberColumn("میانگین ارتفاع", disabled=True),
+ },
+ hide_index=True
+ )
+
+ for i in range(len(edited_df)):
+ stations = [
+ edited_df.iloc[i]['ایستگاه 1'],
+ edited_df.iloc[i]['ایستگاه 2'],
+ edited_df.iloc[i]['ایستگاه 3'],
+ edited_df.iloc[i]['ایستگاه 4'],
+ edited_df.iloc[i]['ایستگاه 5']
+ ]
+ valid_stations = [s for s in stations if s > 0]
+ if valid_stations:
+ edited_df.iloc[i, edited_df.columns.get_loc('میانگین ارتفاع')] = round(sum(valid_stations) / len(valid_stations), 1)
+
+ st.session_state[data_key] = edited_df
+
+ if st.button("ذخیره اطلاعات", type="primary", use_container_width=True):
+ 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 = new_data.merge(
+ farm_df[['مزرعه', 'واریته', 'سن', 'مساحت', 'کانال', 'اداره']],
+ left_on='Farm_ID',
+ right_on='مزرعه',
+ how='left'
+ )
+
+ new_data = new_data.rename(columns={
+ 'واریته': 'Variety',
+ 'سن': 'Age',
+ 'مساحت': 'Area',
+ 'کانال': 'Channel',
+ 'اداره': 'Administration'
+ })
+
+ st.session_state.heights_df = pd.concat([st.session_state.heights_df, new_data], ignore_index=True)
+ st.success(f"دادههای هفته {selected_week} برای روز {selected_day} با موفقیت ذخیره شدند.")
+ st.balloons()
+
+ with tab2:
+ st.markdown("### آپلود فایل اکسل")
+
+ uploaded_file = st.file_uploader("فایل اکسل خود را آپلود کنید", type=["xlsx", "xls", "csv"])
+
+ 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)
+ if st.button("ذخیره فایل", type="primary"):
+ st.success("فایل با موفقیت ذخیره شد.")
+ st.balloons()
+ except Exception as e:
+ st.error(f"خطا در خواندن فایل: {e}")
+
+ st.markdown("### راهنمای فرمت فایل")
+ st.markdown("""
+ فایل اکسل باید شامل ستونهای زیر باشد:
+ - مزرعه
+ - ایستگاه 1 تا 5
+ - چاهک 1 و 2
+ - رطوبت غلاف
+ - نیتروژن
+ میتوانید از [این فایل نمونه](https://example.com/sample.xlsx) به عنوان الگو استفاده کنید.
+ """)
+
+ st.markdown("""
+
+
+
+
+
+
+
فایل خود را اینجا رها کنید یا روی دکمه بالا کلیک کنید
+
+ """, unsafe_allow_html=True)
+
+# Data Analysis Page
+elif selected == "تحلیل دادهها":
+ st.markdown("## تحلیل هوشمند دادهها")
+
+ col1, col2 = st.columns([1, 2])
+
+ with col1:
+ st_lottie(lottie_analysis, height=200, key="analysis_animation")
+
+ 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['واریته'].unique()),
+ format_func=lambda x: "همه واریتهها" if x == "all" else x,
+ key="growth_variety"
+ )
+
+ with col2:
+ selected_age = st.selectbox(
+ "انتخاب سن",
+ ["all"] + list(farm_df['سن'].unique()),
+ format_func=lambda x: "همه سنین" if x == "all" else x,
+ key="growth_age"
+ )
+
+ growth_data = generate_mock_growth_data(farm_df, 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']
})
- except Exception as e:
- st.error(f"خطا در محاسبه شاخصها برای مزرعه {farm['مزرعه']}: {e}")
+
+ 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=400,
+ 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)):
+ 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=400,
+ title='نرخ رشد هفتگی مزارع'
+ ).interactive()
+
+ st.altair_chart(chart, use_container_width=True)
+ else:
+ st.warning("دادهای برای نمایش وجود ندارد.")
+
+ with tab2:
+ st.markdown("### مقایسه واریتهها")
+
+ variety_age_groups = farm_df.groupby(['واریته', 'سن']).size().reset_index(name='تعداد')
+
+ fig = px.density_heatmap(
+ variety_age_groups,
+ x='واریته',
+ y='سن',
+ z='تعداد',
+ title='توزیع مزارع بر اساس واریته و سن',
+ color_continuous_scale='Viridis'
+ )
+ fig.update_layout(
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ xaxis_title="واریته",
+ yaxis_title="سن"
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ varieties = farm_df['واریته'].unique()
+ variety_heights = {variety: np.random.normal(150, 20, 100) for variety in varieties}
+
+ fig = go.Figure()
+ for variety in varieties:
+ fig.add_trace(go.Box(
+ y=variety_heights[variety],
+ name=variety,
+ boxpoints='outliers',
+ marker_color=f'hsl({hash(variety) % 360}, 70%, 50%)'
+ ))
+ fig.update_layout(
+ title='مقایسه ارتفاع بر اساس واریته',
+ yaxis_title='ارتفاع (سانتیمتر)',
+ font=dict(family="Vazirmatn"),
+ template="plotly_white",
+ boxmode='group'
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ st.markdown("### مقایسه آماری واریتهها")
+ variety_stats = {}
+ for variety in varieties:
+ heights = variety_heights[variety]
+ 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)
+
+ with tab3:
+ st.markdown("### تحلیل رطوبت مزارع")
+
+ farms = farm_df['مزرعه'].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)
+ for date in dates:
+ moisture = base_moisture + np.random.normal(0, 5)
+ 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"),
+ template="plotly_white",
+ hovermode="x unified"
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ st.markdown("### همبستگی رطوبت و ارتفاع")
+
+ correlation_data = []
+ for farm in farms:
+ for _ in range(20):
+ moisture = np.random.uniform(40, 90)
+ height = 100 + moisture * 1.5 + np.random.normal(0, 20)
+ correlation_data.append({
+ 'Farm': farm,
+ 'Moisture': moisture,
+ 'Height': height
+ })
+
+ 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"),
+ template="plotly_white"
+ )
+ st.plotly_chart(fig, use_container_width=True)
+
+ correlation = correlation_df['Moisture'].corr(correlation_df['Height'])
+ st.info(f"ضریب همبستگی بین رطوبت و ارتفاع: {correlation:.2f}")
+
+ with tab4:
+ st.markdown("### پیشبینی رشد مزارع")
+
+ selected_farm_for_prediction = st.selectbox(
+ "انتخاب مزرعه",
+ options=farm_df['مزرعه'].tolist(),
+ format_func=lambda x: f"مزرعه {x}"
+ )
+
+ weeks = list(range(1, 16))
+ heights = [50 + i * 10 + np.random.normal(0, 5) for i in range(len(weeks))]
+
+ historical_df = pd.DataFrame({
+ 'Week': weeks,
+ 'Height': heights
+ })
+
+ future_weeks = list(range(16, 23))
+
+ 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))
+
+ lower_bound = future_heights - 15
+ upper_bound = future_heights + 15
+
+ future_df = pd.DataFrame({
+ 'Week': future_weeks,
+ 'Height': future_heights,
+ 'Lower': lower_bound,
+ 'Upper': upper_bound
+ })
+
+ fig = go.Figure()
+
+ 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')
+ ))
+
+ 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')
+ ))
+
+ 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
+ )
+ )
+
+ fig.add_vline(x=15.5, line_width=1, line_dash="dash", line_color="gray")
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ 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"
+ )
+
+ 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)
+
+ st.markdown("### عوامل مؤثر بر رشد")
+
+ 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)
+
+# Reporting Page
+elif selected == "گزارشگیری":
+ st.markdown("## گزارشگیری پیشرفته")
+
+ 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)
+
+ 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"
+ )
+
+ report_type = st.selectbox(
+ "نوع گزارش",
+ options=["گزارش کلی", "گزارش رشد", "گزارش رطوبت", "گزارش مقایسهای واریتهها"]
+ )
+
+ if st.button("تولید گزارش", type="primary", use_container_width=True):
+ with st.spinner('در حال تولید گزارش...'):
+ time.sleep(2)
+
+ if report_type == "گزارش کلی":
+ st.markdown("### گزارش کلی وضعیت مزارع")
+
+ 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_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)
- # بهروزرسانی نوار پیشرفت
- progress_bar.progress((idx + 1) / len(filtered_farms))
+ 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_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)
- # تبدیل نتایج به DataFra me
- if indices_data:
- indices_df = pd.DataFrame(indices_data)
-
- # ایجاد ستون وضعیت برای رنگبندی
- def get_status(ndvi):
- if ndvi is None:
- return "نامشخص"
- elif ndvi < 0.3:
- return "تنش شدید"
- elif ndvi < 0.4:
- return "تنش متوسط"
- elif ndvi < 0.5:
- return "رشد ضعیف"
- elif ndvi < 0.65:
- return "رشد خوب"
- else:
- return "رشد عالی"
+ elif report_type == "گزارش رشد":
+ st.markdown("### گزارش رشد مزارع")
+
+ col1, col2, col3 = st.columns(3)
- indices_df['وضعیت'] = indices_df['NDVI'].apply(get_status)
+ with col1:
+ st.metric("میانگین رشد هفتگی", f"{np.random.uniform(10, 15):.1f} cm")
- # مرتبسازی بر اساس NDVI نزولی
- indices_df = indices_df.sort_values(by='NDVI', ascending=False)
+ with col2:
+ st.metric("حداکثر رشد هفتگی", f"{np.random.uniform(20, 25):.1f} cm")
- # نمایش جدول با رنگبندی
- st.subheader("اطلاعات شاخصهای مزارع")
+ with col3:
+ st.metric("حداقل رشد هفتگی", f"{np.random.uniform(5, 10):.1f} cm")
- # تعیین رنگ سطرها بر اساس وضعیت
- def highlight_row(row):
- status = row['وضعیت']
- if status == "رشد عالی":
- return ['background-color: #d4edda'] * len(row)
- elif status == "رشد خوب":
- return ['background-color: #a6d96a'] * len(row)
- elif status == "رشد ضعیف":
- return ['background-color: #fff3cd'] * len(row)
- elif status in ["تنش متوسط", "تنش شدید"]:
- return ['background-color: #f8d7da'] * len(row)
- return [''] * len(row)
+ 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)
- st.dataframe(indices_df.style.apply(highlight_row, axis=1))
+ 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)
- # نمودارها
- st.subheader("تحلیل شاخصهای مزارع")
+ 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("### گزارش رطوبت مزارع")
- col1, col2 = st.columns(2)
+ col1, col2, col3 = st.columns(3)
with col1:
- # نمودار NDVI برای مزارع
- fig_ndvi = px.bar(
- indices_df,
- x='مزرعه',
- y='NDVI',
- color='NDVI',
- color_continuous_scale=['red', 'yellow', 'green'],
- labels={'NDVI': 'شاخص NDVI', 'مزرعه': 'نام مزرعه'},
- title="مقایسه شاخص NDVI مزارع"
- )
- st.plotly_chart(fig_ndvi, use_container_width=True)
+ st.metric("میانگین رطوبت", f"{np.random.uniform(60, 70):.1f}%")
with col2:
- # نمودار مرحله رشد
- fig_stage = px.bar(
- indices_df,
- x='مزرعه',
- y='مرحله رشد',
- color='مرحله رشد',
- color_continuous_scale=['red', 'yellow', 'green'],
- labels={'مرحله رشد': 'مرحله رشد (0-6)', 'مزرعه': 'نام مزرعه'},
- title="مرحله رشد مزارع"
- )
- st.plotly_chart(fig_stage, use_container_width=True)
-
- # شناسایی مزارع با بیشترین و کمترین رشد
- if len(indices_df) > 0:
- best_farm = indices_df.iloc[0]
- worst_farm = indices_df.iloc[-1]
-
- col1, col2 = st.columns(2)
-
- with col1:
- st.markdown(f"""
-
-
مزرعه با بیشترین رشد
-
مزرعه: {best_farm['مزرعه']}
-
شاخص NDVI: {best_farm['NDVI']:.3f}
-
مرحله رشد: {best_farm['مرحله رشد']}
-
تنوع: {best_farm['تنوع']}
-
- """, unsafe_allow_html=True)
-
- with col2:
- st.markdown(f"""
-
-
مزرعه با کمترین رشد
-
مزرعه: {worst_farm['مزرعه']}
-
شاخص NDVI: {worst_farm['NDVI']:.3f}
-
مرحله رشد: {worst_farm['مرحله رشد']}
-
تنوع: {worst_farm['تنوع']}
-
- """, unsafe_allow_html=True)
-
- # شناسایی مزارع دارای تنش
- stress_farms = indices_df[indices_df['NDVI'] < 0.4]
-
- if len(stress_farms) > 0:
- st.subheader("مزارع دارای تنش")
- st.markdown("""
-
-
مزارع زیر دارای تنش هستند و نیاز به بررسی دارند:
-
- """, unsafe_allow_html=True)
-
- st.dataframe(stress_farms[['مزرعه', 'NDVI', 'NDWI', 'مرحله رشد', 'وضعیت']])
- else:
- st.warning("دادهای برای نمایش یافت نشد.")
- else:
- st.warning(f"هیچ مزرعهای برای روز {selected_day[0]} برنامهریزی نشده است.")
+ st.metric("حداکثر رطوبت", f"{np.random.uniform(80, 90):.1f}%")
+
+ with col3:
+ st.metric("حداقل رطوبت", f"{np.random.uniform(40, 50):.1f}%")
+
+ 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)
+
+ 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)
+
+ 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)
+
+ st.markdown("### توصیههای مدیریت رطوبت")
+ recommendations = [
+ "افزایش دفعات آبیاری در مزارع با رطوبت پایین",
+ "بهبود سیستم زهکشی در مزارع با رطوبت بالا",
+ "استفاده از مالچ برای حفظ رطوبت خاک",
+ "تنظیم زمان آبیاری بر اساس شرایط آب و هوایی",
+ "پایش مداوم رطوبت خاک با استفاده از سنسورها"
+ ]
+ for rec in recommendations:
+ st.markdown(f"- {rec}")
+
+ elif report_type == "گزارش مقایسهای واریتهها":
+ st.markdown("### گزارش مقایسهای واریتههای نیشکر")
+
+ 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]
+
+ 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_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)
+
+ 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)
+
+ 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}")
+
+ col1, col2 = st.columns(2)
+ with col1:
+ st.download_button(
+ label="دانلود گزارش (PDF)",
+ data=b"This is a mock PDF report",
+ file_name="farm_report.pdf",
+ mime="application/pdf",
+ )
+ with col2:
+ st.download_button(
+ label="دانلود دادهها (Excel)",
+ data=b"This is a mock Excel file",
+ file_name="farm_data.xlsx",
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ )
-# نمایش نقشه
-elif selected_tab == "نقشه":
- st.header("نقشه مانیتورینگ مزارع نیشکر")
+# Settings Page
+elif selected == "تنظیمات":
+ st.markdown("## تنظیمات سیستم")
- # مختصات مرکزی
- CENTER_LAT = 31.534442
- CENTER_LON = 48.724416
+ tab1, tab2, tab3, tab4 = st.tabs(["تنظیمات کاربری", "تنظیمات سیستم", "مدیریت دادهها", "پشتیبانگیری"])
- # توضیحات شاخص NDVI
- with st.expander("راهنمای شاخص NDVI"):
- st.markdown("""
- ### راهنمای تفسیر شاخص NDVI
-
- شاخص NDVI (Normalized Difference Vegetation Index) نشاندهنده سلامت گیاه و میزان فتوسنتز است:
-
- - **0.7 تا 1.0**: پوشش گیاهی بسیار متراکم و سالم (سبز تیره)
- مناطق با تراکم بالای گیاهان سالم و فعالیت فتوسنتزی قوی.
- - **0.6 تا 0.7**: پوشش گیاهی متراکم و سالم (سبز)
- پوشش گیاهی خوب با سلامت بالا، معمولاً در جنگلها یا مزارع پررونق.
- - **0.5 تا 0.6**: پوشش گیاهی متوسط (سبز روشن)
- مناطقی با پوشش گیاهی قابل قبول اما نه در حداکثر سلامت یا تراکم.
- - **0.4 تا 0.5**: پوشش گیاهی کم تراکم (سبز-زرد)
- گیاهان با تراکم کم، ممکن است نشاندهنده شروع تنش یا شرایط متوسط باشد.
- - **0.3 تا 0.4**: پوشش گیاهی بسیار کم تراکم یا مناطق خشک (زرد)
- مناطقی که پوشش گیاهی کمی دارند و ممکن است در معرض خشکی باشند.
- - **0.2 تا 0.3**: خاک خشک یا مناطق بدون پوشش گیاهی (قرمز)
- مناطقی که عمدتاً خاک خشک یا سنگلاخی هستند و پوشش گیاهی ناچیز است.
- - **کمتر از 0.2**: آب یا سطوح غیر گیاهی (آبی)
- سطوح آبی مانند رودخانهها، دریاچهها یا مناطقی بدون گیاه (مثل آسفالت یا سنگ).
-""")
\ No newline at end of file
+ with tab1:
+ st.markdown("### تنظیمات کاربری")
+
+ 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
+ )
+
+ 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"):
+ st.success("رمز عبور با موفقیت تغییر کرد.")
+
+ st.markdown("#### تنظیمات اعلانها")
+ email_notifications = st.checkbox("دریافت اعلانها از طریق ایمیل", value=True)
+ sms_notifications = st.checkbox("دریافت اعلانها از طریق پیامک", value=False)
+ notification_frequency = st.radio(
+ "تناوب دریافت اعلانها",
+ options=["روزانه", "هفتگی", "ماهانه"],
+ index=1
+ )
+
+ with tab2:
+ st.markdown("### تنظیمات سیستم")
+
+ system_language = st.selectbox(
+ "زبان سیستم",
+ options=["فارسی", "English", "العربية"],
+ index=0
+ )
+
+ date_format = st.selectbox(
+ "فرمت تاریخ",
+ options=["YYYY/MM/DD", "DD/MM/YYYY", "MM/DD/YYYY"],
+ index=0
+ )
+
+ st.markdown("#### تنظیمات ظاهری")
+ theme = st.radio(
+ "تم",
+ options=["روشن", "تیره", "سیستم"],
+ index=2
+ )
+ primary_color = st.color_picker("رنگ اصلی", value="#1a8754")
+
+ st.markdown("#### تنظیمات نقشه")
+ default_map_view = st.selectbox(
+ "نمای پیشفرض نقشه",
+ options=["نقشه", "ماهواره", "ترکیبی"],
+ index=0
+ )
+ default_map_layer = st.selectbox(
+ "لایه پیشفرض نقشه",
+ options=["NDVI", "NDMI", "EVI", "NDWI", "SoilMoisture"],
+ index=0
+ )
+
+ st.markdown("#### تنظیمات مدل هوش مصنوعی")
+ ai_model = st.selectbox(
+ "مدل هوش مصنوعی",
+ options=["GPT-3", "GPT-4", "BERT"],
+ index=1
+ )
+ model_update_frequency = st.selectbox(
+ "تناوب بهروزرسانی مدل",
+ options=["روزانه", "هفتگی", "ماهانه"],
+ index=1
+ )
+
+ if st.button("ذخیره تنظیمات", type="primary"):
+ st.success("تنظیمات با موفقیت ذخیره شدند.")
+
+ with tab3:
+ st.markdown("### مدیریت دادهها")
+
+ 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("وارد کردن دادهها"):
+ st.info("در حال پردازش و وارد کردن دادهها...")
+ time.sleep(2)
+ st.success("دادهها با موفقیت وارد شدند.")
+
+ st.markdown("#### خروجی داده")
+ export_format = st.selectbox(
+ "فرمت خروجی",
+ options=["CSV", "Excel", "JSON"],
+ index=1
+ )
+ if st.button("دریافت خروجی"):
+ st.info("در حال آمادهسازی فایل خروجی...")
+ time.sleep(2)
+ st.success("فایل خروجی آماده دانلود است.")
+ st.download_button(
+ label="دانلود فایل خروجی",
+ data=b"This is a mock export file",
+ file_name=f"farm_data_export.{export_format.lower()}",
+ mime="application/octet-stream",
+ )
+
+ st.markdown("#### پاکسازی دادهها")
+ cleanup_options = st.multiselect(
+ "گزینههای پاکسازی",
+ options=["حذف دادههای تکراری", "حذف دادههای ناقص", "نرمالسازی دادهها"],
+ default=["حذف دادههای تکراری"]
+ )
+ if st.button("اجرای پاکسازی"):
+ st.info("در حال اجرای عملیات پاکسازی...")
+ time.sleep(2)
+ st.success("عملیات پاکسازی با موفقیت انجام شد.")
+
+ st.markdown("#### تنظیمات نمایش داده")
+ chart_theme = st.selectbox(
+ "تم نمودارها",
+ options=["پیشفرض", "روشن", "تیره", "رنگی"],
+ index=0
+ )
+ show_data_labels = st.checkbox("نمایش برچسبهای داده", value=True)
+ if st.button("اعمال تنظیمات نمایش"):
+ st.success("تنظیمات نمایش داده با موفقیت اعمال شدند.")
+
+ with tab4:
+ st.markdown("### پشتیبانگیری و بازیابی")
+
+ 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"):
+ st.info("در حال ایجاد نسخه پشتیبان...")
+ progress_bar = st.progress(0)
+ for i in range(100):
+ time.sleep(0.05)
+ progress_bar.progress(i + 1)
+ st.success("نسخه پشتیبان با موفقیت ایجاد شد.")
+
+ st.markdown("#### بازیابی از نسخه پشتیبان")
+ backup_file = st.file_uploader("آپلود فایل پشتیبان", type=["zip", "bak"])
+ if backup_file is not None:
+ st.warning("هشدار: بازیابی از نسخه پشتیبان ممکن است دادههای فعلی را بازنویسی کند.")
+ if st.button("شروع بازیابی"):
+ st.info("در حال بازیابی از نسخه پشتیبان...")
+ progress_bar = st.progress(0)
+ for i in range(100):
+ time.sleep(0.05)
+ progress_bar.progress(i + 1)
+ st.success("بازیابی از نسخه پشتیبان با موفقیت انجام شد.")
+
+ 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)
+
+ if st.button("ذخیره تنظیمات پشتیبانگیری"):
+ st.success("تنظیمات پشتیبانگیری با موفقیت ذخیره شدند.")
+
+# Add a footer
+st.markdown("""
+
+""", unsafe_allow_html=True)
\ No newline at end of file