Spaces:
Configuration error
Configuration error
Update app.py
Browse files
app.py
CHANGED
@@ -28,7 +28,6 @@ from streamlit_card import card
|
|
28 |
import pydeck as pdk
|
29 |
import math
|
30 |
|
31 |
-
|
32 |
# Page configuration with custom theme
|
33 |
st.set_page_config(
|
34 |
page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا",
|
@@ -518,30 +517,14 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"):
|
|
518 |
|
519 |
|
520 |
if layer_type == "NDVI":
|
521 |
-
s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
|
522 |
-
.filterDate(start_date, end_date) \
|
523 |
-
.filterBounds(region) \
|
524 |
-
.sort('CLOUDY_PIXEL_PERCENTAGE') \
|
525 |
-
.first()
|
526 |
-
|
527 |
index = s2.normalizedDifference(['B8', 'B4']).rename('NDVI')
|
528 |
viz_params = {'min': -0.2, 'max': 0.8, 'palette': ['#ff0000', '#ff4500', '#ffd700', '#32cd32', '#006400']}
|
529 |
legend_title = 'شاخص پوشش گیاهی (NDVI)'
|
530 |
elif layer_type == "NDMI":
|
531 |
-
s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
|
532 |
-
.filterDate(start_date, end_date) \
|
533 |
-
.filterBounds(region) \
|
534 |
-
.sort('CLOUDY_PIXEL_PERCENTAGE') \
|
535 |
-
.first()
|
536 |
index = s2.normalizedDifference(['B8', 'B11']).rename('NDMI')
|
537 |
viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#8b0000', '#ff8c00', '#00ced1', '#00b7eb', '#00008b']}
|
538 |
legend_title = 'شاخص رطوبت (NDMI)'
|
539 |
elif layer_type == "EVI":
|
540 |
-
s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
|
541 |
-
.filterDate(start_date, end_date) \
|
542 |
-
.filterBounds(region) \
|
543 |
-
.sort('CLOUDY_PIXEL_PERCENTAGE') \
|
544 |
-
.first()
|
545 |
nir = s2.select('B8')
|
546 |
red = s2.select('B4')
|
547 |
blue = s2.select('B2')
|
@@ -549,11 +532,6 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"):
|
|
549 |
viz_params = {'min': 0, 'max': 1, 'palette': ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#4caf50']}
|
550 |
legend_title = 'شاخص پیشرفته گیاهی (EVI)'
|
551 |
elif layer_type == "NDWI":
|
552 |
-
s2 = ee.ImageCollection('COPERNICUS/S2_SR') \
|
553 |
-
.filterDate(start_date, end_date) \
|
554 |
-
.filterBounds(region) \
|
555 |
-
.sort('CLOUDY_PIXEL_PERCENTAGE') \
|
556 |
-
.first()
|
557 |
index = s2.normalizedDifference(['B3', 'B8']).rename('NDWI')
|
558 |
viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#00008b', '#00b7eb', '#add8e6', '#fdae61', '#d73027']}
|
559 |
legend_title = 'شاخص آب (NDWI)'
|
@@ -566,6 +544,9 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"):
|
|
566 |
.sort('system:time_start') \
|
567 |
.first()
|
568 |
|
|
|
|
|
|
|
569 |
soil_moisture = s1.select('VV')
|
570 |
|
571 |
viz_params = {
|
@@ -587,19 +568,10 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"):
|
|
587 |
control=True
|
588 |
).add_to(m)
|
589 |
|
|
|
590 |
except Exception as e:
|
591 |
st.error(f"Error loading Soil Moisture data: {e}")
|
592 |
-
return None
|
593 |
-
|
594 |
-
if layer_type != "SoilMoisture": # for other layers
|
595 |
-
map_id_dict = ee.Image(index).getMapId(viz_params)
|
596 |
-
folium.TileLayer(
|
597 |
-
tiles=map_id_dict['tile_fetcher'].url_format,
|
598 |
-
attr='Google Earth Engine',
|
599 |
-
name=layer_type,
|
600 |
-
overlay=True,
|
601 |
-
control=True
|
602 |
-
).add_to(m)
|
603 |
|
604 |
|
605 |
folium.Marker(
|
@@ -644,34 +616,365 @@ def create_ee_map(farm_id, date_str, layer_type="NDVI"):
|
|
644 |
</div>
|
645 |
</div>
|
646 |
'''
|
647 |
-
if layer_type == "SoilMoisture":
|
648 |
-
legend_html = '''
|
649 |
-
<div style="position: fixed;
|
650 |
-
bottom: 50px; right: 50px;
|
651 |
-
border: 2px solid grey; z-index: 9999;
|
652 |
-
background-color: white;
|
653 |
-
padding: 10px;
|
654 |
-
border-radius: 5px;
|
655 |
-
direction: rtl;
|
656 |
-
font-family: 'Vazirmatn', sans-serif;">
|
657 |
-
<div style="font-size: 14px; font-weight: bold; margin-bottom: 5px;">''' + legend_title + '''</div>
|
658 |
-
<div style="display: flex; align-items: center; margin-bottom: 5px;">
|
659 |
-
<div style="background: ''' + viz_params['palette'][0] + '''; width: 20px; height: 20px; margin-left: 5px;"></div>
|
660 |
-
<span>خشک</span>
|
661 |
-
</div>
|
662 |
-
<div style="display: flex; align-items: center; margin-bottom: 5px;">
|
663 |
-
<div style="background: ''' + viz_params['palette'][2] + '''; width: 20px; height: 20px; margin-left: 5px;"></div>
|
664 |
-
<span>معتدل</span>
|
665 |
-
</div>
|
666 |
-
<div style="display: flex; align-items: center;">
|
667 |
-
<div style="background: ''' + viz_params['palette'][-1] + '''; width: 20px; height: 20px; margin-left: 5px;"></div>
|
668 |
-
<span>مرطوب</span>
|
669 |
-
</div>
|
670 |
-
</div>
|
671 |
-
'''
|
672 |
-
|
673 |
m.get_root().html.add_child(folium.Element(legend_html))
|
674 |
|
675 |
return m
|
676 |
except Exception as e:
|
677 |
-
st.error(f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
import pydeck as pdk
|
29 |
import math
|
30 |
|
|
|
31 |
# Page configuration with custom theme
|
32 |
st.set_page_config(
|
33 |
page_title="سامانه هوشمند پایش مزارع نیشکر دهخدا",
|
|
|
517 |
|
518 |
|
519 |
if layer_type == "NDVI":
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
index = s2.normalizedDifference(['B8', 'B4']).rename('NDVI')
|
521 |
viz_params = {'min': -0.2, 'max': 0.8, 'palette': ['#ff0000', '#ff4500', '#ffd700', '#32cd32', '#006400']}
|
522 |
legend_title = 'شاخص پوشش گیاهی (NDVI)'
|
523 |
elif layer_type == "NDMI":
|
|
|
|
|
|
|
|
|
|
|
524 |
index = s2.normalizedDifference(['B8', 'B11']).rename('NDMI')
|
525 |
viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#8b0000', '#ff8c00', '#00ced1', '#00b7eb', '#00008b']}
|
526 |
legend_title = 'شاخص رطوبت (NDMI)'
|
527 |
elif layer_type == "EVI":
|
|
|
|
|
|
|
|
|
|
|
528 |
nir = s2.select('B8')
|
529 |
red = s2.select('B4')
|
530 |
blue = s2.select('B2')
|
|
|
532 |
viz_params = {'min': 0, 'max': 1, 'palette': ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#4caf50']}
|
533 |
legend_title = 'شاخص پیشرفته گیاهی (EVI)'
|
534 |
elif layer_type == "NDWI":
|
|
|
|
|
|
|
|
|
|
|
535 |
index = s2.normalizedDifference(['B3', 'B8']).rename('NDWI')
|
536 |
viz_params = {'min': -0.5, 'max': 0.5, 'palette': ['#00008b', '#00b7eb', '#add8e6', '#fdae61', '#d73027']}
|
537 |
legend_title = 'شاخص آب (NDWI)'
|
|
|
544 |
.sort('system:time_start') \
|
545 |
.first()
|
546 |
|
547 |
+
if s1.getInfo() is None: #Check if image is available
|
548 |
+
raise Exception("No Sentinel-1 image found for the selected date and region.")
|
549 |
+
|
550 |
soil_moisture = s1.select('VV')
|
551 |
|
552 |
viz_params = {
|
|
|
568 |
control=True
|
569 |
).add_to(m)
|
570 |
|
571 |
+
|
572 |
except Exception as e:
|
573 |
st.error(f"Error loading Soil Moisture data: {e}")
|
574 |
+
return None # Return None so the map is not displayed if there's an error.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
575 |
|
576 |
|
577 |
folium.Marker(
|
|
|
616 |
</div>
|
617 |
</div>
|
618 |
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
619 |
m.get_root().html.add_child(folium.Element(legend_html))
|
620 |
|
621 |
return m
|
622 |
except Exception as e:
|
623 |
+
st.error(f"خطا در ایجاد نقشه: {e}")
|
624 |
+
return None
|
625 |
+
|
626 |
+
# Generate mock growth data (Same as before)
|
627 |
+
def generate_mock_growth_data(farm_data, selected_variety="all", selected_age="all"):
|
628 |
+
# ... (Mock growth data generation – same as before)
|
629 |
+
|
630 |
+
|
631 |
+
# Calculate statistics for a farm (modified for SoilMoisture)
|
632 |
+
def calculate_farm_stats(farm_id, layer_type="NDVI", date_str=None):
|
633 |
+
if layer_type == "NDVI":
|
634 |
+
mean = round(np.random.uniform(0.6, 0.8), 2)
|
635 |
+
min_val = round(mean - np.random.uniform(0.2, 0.3), 2)
|
636 |
+
max_val = round(mean + np.random.uniform(0.1, 0.2), 2)
|
637 |
+
std_dev = round(np.random.uniform(0.05, 0.15), 2)
|
638 |
+
elif layer_type == "NDMI":
|
639 |
+
mean = round(np.random.uniform(0.3, 0.5), 2)
|
640 |
+
min_val = round(mean - np.random.uniform(0.2, 0.3), 2)
|
641 |
+
max_val = round(mean + np.random.uniform(0.1, 0.2), 2)
|
642 |
+
std_dev = round(np.random.uniform(0.05, 0.15), 2)
|
643 |
+
elif layer_type == "EVI":
|
644 |
+
mean = round(np.random.uniform(0.4, 0.6), 2)
|
645 |
+
min_val = round(mean - np.random.uniform(0.2, 0.3), 2)
|
646 |
+
max_val = round(mean + np.random.uniform(0.1, 0.2), 2)
|
647 |
+
std_dev = round(np.random.uniform(0.05, 0.15), 2)
|
648 |
+
elif layer_type == "NDWI":
|
649 |
+
mean = round(np.random.uniform(-0.1, 0.1), 2)
|
650 |
+
min_val = round(mean - np.random.uniform(0.2, 0.3), 2)
|
651 |
+
max_val = round(mean + np.random.uniform(0.1, 0.2), 2)
|
652 |
+
std_dev = round(np.random.uniform(0.05, 0.15), 2)
|
653 |
+
elif layer_type == "SoilMoisture":
|
654 |
+
if date_str is None:
|
655 |
+
st.error("Date is required for Soil Moisture calculations.")
|
656 |
+
return None
|
657 |
+
|
658 |
+
try:
|
659 |
+
farm_row = coordinates_df[coordinates_df['مزرعه'] == farm_id].iloc[0]
|
660 |
+
lat, lon = farm_row['عرض جغرافیایی'], farm_row['طول جغرافیایی']
|
661 |
+
date_obj = datetime.strptime(date_str, '%Y-%m-%d')
|
662 |
+
start_date = (date_obj - timedelta(days=5)).strftime('%Y-%m-%d')
|
663 |
+
end_date = (date_obj + timedelta(days=5)).strftime('%Y-%m-%d')
|
664 |
+
region = ee.Geometry.Point([lon, lat]).buffer(1500)
|
665 |
+
|
666 |
+
s1 = ee.ImageCollection('COPERNICUS/S1_GRD') \
|
667 |
+
.filterDate(start_date, end_date) \
|
668 |
+
.filterBounds(region) \
|
669 |
+
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) \
|
670 |
+
.sort('system:time_start') \
|
671 |
+
.first()
|
672 |
+
|
673 |
+
if s1.getInfo() is None:
|
674 |
+
raise Exception("No Sentinel-1 image found for the selected date and region.")
|
675 |
+
|
676 |
+
|
677 |
+
soil_moisture = s1.select('VV')
|
678 |
+
|
679 |
+
mean = ee.Number(soil_moisture.reduceRegion(ee.Reducer.mean(), region).get('VV')).getInfo()
|
680 |
+
min_val = ee.Number(soil_moisture.reduceRegion(ee.Reducer.min(), region).get('VV')).getInfo()
|
681 |
+
max_val = ee.Number(soil_moisture.reduceRegion(ee.Reducer.max(), region).get('VV')).getInfo()
|
682 |
+
std_dev = ee.Number(soil_moisture.reduceRegion(ee.Reducer.stdDev(), region).get('VV')).getInfo()
|
683 |
+
|
684 |
+
|
685 |
+
# Mock histogram data (replace with actual if possible)
|
686 |
+
hist_data = np.random.normal(mean, std_dev, 1000)
|
687 |
+
hist_data = np.clip(hist_data, min_val, max_val)
|
688 |
+
|
689 |
+
|
690 |
+
return {
|
691 |
+
'mean': mean,
|
692 |
+
'min': min_val,
|
693 |
+
'max': max_val,
|
694 |
+
'std_dev': std_dev,
|
695 |
+
'histogram_data': hist_data
|
696 |
+
}
|
697 |
+
|
698 |
+
except Exception as e:
|
699 |
+
st.error(f"Error calculating Soil Moisture stats: {e}")
|
700 |
+
return None
|
701 |
+
|
702 |
+
|
703 |
+
hist_data = np.random.normal(mean, std_dev, 1000)
|
704 |
+
hist_data = np.clip(hist_data, min_val, max_val)
|
705 |
+
|
706 |
+
return {
|
707 |
+
'mean': mean,
|
708 |
+
'min': min_val,
|
709 |
+
'max': max_val,
|
710 |
+
'std_dev': std_dev,
|
711 |
+
'histogram_data': hist_data
|
712 |
+
}
|
713 |
+
|
714 |
+
|
715 |
+
# Initialize Earth Engine
|
716 |
+
ee_initialized = initialize_earth_engine()
|
717 |
+
|
718 |
+
# Load data
|
719 |
+
farm_df = load_farm_data()
|
720 |
+
coordinates_df = load_coordinates_data()
|
721 |
+
|
722 |
+
# Load animations
|
723 |
+
lottie_farm = load_lottie_url('https://assets5.lottiefiles.com/packages/lf20_ystsffqy.json')
|
724 |
+
lottie_analysis = load_lottie_url('https://assets3.lottiefiles.com/packages/lf20_qp1q7mct.json')
|
725 |
+
lottie_report = load_lottie_url('https://assets9.lottiefiles.com/packages/lf20_vwcugezu.json')
|
726 |
+
|
727 |
+
# Create session state for storing data
|
728 |
+
if 'heights_df' not in st.session_state:
|
729 |
+
st.session_state.heights_df = pd.DataFrame(columns=[
|
730 |
+
'Farm_ID', 'Week', 'Measurement_Date', 'Height', 'Station1', 'Station2', 'Station3',
|
731 |
+
'Station4', 'Station5', 'Groundwater1', 'Groundwater2', 'Sheath_Moisture', 'Nitrogen',
|
732 |
+
'Variety', 'Age', 'Area', 'Channel', 'Administration'
|
733 |
+
])
|
734 |
+
|
735 |
+
# Main header
|
736 |
+
st.markdown('<div class="main-header">', unsafe_allow_html=True)
|
737 |
+
st.markdown('<h1>سامانه هوشمند پایش مزارع نیشکر دهخدا</h1>', unsafe_allow_html=True)
|
738 |
+
st.markdown('<p>پلتفرم جامع مدیریت، پایش و تحلیل دادههای مزارع نیشکر با استفاده از تصاویر ماهوارهای و هوش مصنوعی</p>', unsafe_allow_html=True)
|
739 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
740 |
+
|
741 |
+
# Create a modern navigation menu
|
742 |
+
selected = option_menu(
|
743 |
+
menu_title=None,
|
744 |
+
options=["داشبورد", "نقشه مزارع", "ورود اطلاعات", "تحلیل دادهها", "گزارشگیری", "تنظیمات"],
|
745 |
+
icons=["speedometer2", "map", "pencil-square", "graph-up", "file-earmark-text", "gear"],
|
746 |
+
menu_icon="cast",
|
747 |
+
default_index=0,
|
748 |
+
orientation="horizontal",
|
749 |
+
styles={
|
750 |
+
"container": {"padding": "0!important", "background-color": "transparent", "margin-bottom": "20px"},
|
751 |
+
"icon": {"color": "#1a8754", "font-size": "18px"},
|
752 |
+
"nav-link": {"font-size": "16px", "text-align": "center", "margin":"0px", "--hover-color": "#e9f7ef", "border-radius": "10px"},
|
753 |
+
"nav-link-selected": {"background-color": "#1a8754", "color": "white", "font-weight": "600"},
|
754 |
+
}
|
755 |
+
)
|
756 |
+
|
757 |
+
# Dashboard (same as before)
|
758 |
+
if selected == "داشبورد":
|
759 |
+
# ... (Dashboard content – same as before)
|
760 |
+
|
761 |
+
# Map Page
|
762 |
+
elif selected == "نقشه مزارع":
|
763 |
+
st.markdown("## نقشه مزارع با شاخصهای ماهوارهای")
|
764 |
+
|
765 |
+
col1, col2 = st.columns([1, 3])
|
766 |
+
|
767 |
+
with col1:
|
768 |
+
st.markdown('<div class="glass-card">', unsafe_allow_html=True)
|
769 |
+
st.markdown("### تنظیمات نقشه")
|
770 |
+
|
771 |
+
selected_farm = st.selectbox(
|
772 |
+
"انتخاب مزرعه",
|
773 |
+
options=coordinates_df['مزرعه'].tolist(),
|
774 |
+
index=0,
|
775 |
+
format_func=lambda x: f"مزرعه {x}"
|
776 |
+
)
|
777 |
+
|
778 |
+
selected_date = st.date_input(
|
779 |
+
"انتخاب تاریخ",
|
780 |
+
value=datetime.now(),
|
781 |
+
format="YYYY-MM-DD"
|
782 |
+
)
|
783 |
+
|
784 |
+
selected_layer = st.selectbox(
|
785 |
+
"انتخاب شاخص",
|
786 |
+
options=["NDVI", "NDMI", "EVI", "NDWI", "SoilMoisture"],
|
787 |
+
format_func=lambda x: {
|
788 |
+
"NDVI": "شاخص پوشش گیاهی (NDVI)",
|
789 |
+
"NDMI": "شاخص رطوبت (NDMI)",
|
790 |
+
"EVI": "شاخص پیشرفته گیاهی (EVI)",
|
791 |
+
"NDWI": "شاخص آب (NDWI)",
|
792 |
+
"SoilMoisture": "رطوبت خاک (Soil Moisture)"
|
793 |
+
}[x]
|
794 |
+
)
|
795 |
+
|
796 |
+
generate_map = st.button(
|
797 |
+
"تولید نقشه",
|
798 |
+
type="primary",
|
799 |
+
use_container_width=True
|
800 |
+
)
|
801 |
+
|
802 |
+
st.markdown('<hr style="margin: 20px 0;">', unsafe_allow_html=True)
|
803 |
+
|
804 |
+
st.markdown("### راهنمای شاخصها")
|
805 |
+
|
806 |
+
with st.expander("شاخص پوشش گیاهی (NDVI)", expanded=selected_layer == "NDVI"):
|
807 |
+
st.markdown("""
|
808 |
+
**شاخص تفاضل نرمالشده پوشش گیاهی (NDVI)** معیاری برای سنجش سلامت و تراکم پوشش گیاهی است.
|
809 |
+
- **مقادیر بالا (0.6 تا 1.0)**: پوشش گیاهی متراکم و سالم
|
810 |
+
- **مقادیر متوسط (0.2 تا 0.6)**: پوشش گیاهی متوسط
|
811 |
+
- **مقادیر پایین (-1.0 تا 0.2)**: پوشش گیاهی کم یا خاک لخت
|
812 |
+
فرمول: NDVI = (NIR - RED) / (NIR + RED)
|
813 |
+
""")
|
814 |
+
|
815 |
+
with st.expander("شاخص رطوبت (NDMI)", expanded=selected_layer == "NDMI"):
|
816 |
+
st.markdown("""
|
817 |
+
**شاخص تفاضل نرمالشده رطوبت (NDMI)** برای ارزیابی محتوای رطوبت گیاهان استفاده میشود.
|
818 |
+
- **مقادیر بالا (0.4 تا 1.0)**: محتوای رطوبت بالا
|
819 |
+
- **مقادیر متوسط (0.0 تا 0.4)**: محتوای رطوبت متوسط
|
820 |
+
- **مقادیر پایین (-1.0 تا 0.0)**: محتوای رطوبت کم
|
821 |
+
فرمول: NDMI = (NIR - SWIR) / (NIR + SWIR)
|
822 |
+
""")
|
823 |
+
|
824 |
+
with st.expander("شاخص پیشرفته گیاهی (EVI)", expanded=selected_layer == "EVI"):
|
825 |
+
st.markdown("""
|
826 |
+
**شاخص پیشرفته پوشش گیاهی (EVI)** نسخه بهبودیافته NDVI است که حساسیت کمتری به اثرات خاک و اتمسفر دارد.
|
827 |
+
- **مقادیر بالا (0.4 تا 1.0)**: پوشش گیاهی متراکم و سالم
|
828 |
+
- **مقادیر متوسط (0.2 تا 0.4)**: پوشش گیاهی متوسط
|
829 |
+
- **مقادیر پایین (0.0 تا 0.2)**: پوشش گیاهی کم
|
830 |
+
فرمول: EVI = 2.5 * ((NIR - RED) / (NIR + 6*RED - 7.5*BLUE + 1))
|
831 |
+
""")
|
832 |
+
|
833 |
+
with st.expander("شاخص آب (NDWI)", expanded=selected_layer == "NDWI"):
|
834 |
+
st.markdown("""
|
835 |
+
**شاخص تفاضل نرمالشده آب (NDWI)** برای شناسایی پهنههای آبی و ارزیابی محتوای آب در گیاهان استفاده میشود.
|
836 |
+
- **مقادیر بالا (0.3 تا 1.0)**: پهنههای آبی
|
837 |
+
- **مقادیر متوسط (0.0 تا 0.3)**: محتوای آب متوسط
|
838 |
+
- **مقادیر پایین (-1.0 تا 0.0)**: محتوای آب کم یا خاک خشک
|
839 |
+
فرمول: NDWI = (GREEN - NIR) / (GREEN + NIR)
|
840 |
+
""")
|
841 |
+
|
842 |
+
with st.expander("رطوبت خاک (Soil Moisture)", expanded=selected_layer == "SoilMoisture"):
|
843 |
+
st.markdown("""
|
844 |
+
**رطوبت خاک (Soil Moisture)** با استفاده از دادههای راداری Sentinel-1 سطح رطوبت خاک را به صورت داینامیک بررسی میکند.
|
845 |
+
- **مقادیر بالا**: رطوبت خاک بالا
|
846 |
+
- **مقادیر پایین**: رطوبت خاک کم
|
847 |
+
این شاخص به مدیریت بهتر منابع آب کمک میکند.
|
848 |
+
""")
|
849 |
+
|
850 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
851 |
+
|
852 |
+
with col2:
|
853 |
+
map_tab, stats_tab = st.tabs(["نقشه", "آمار و تحلیل"])
|
854 |
+
|
855 |
+
with map_tab:
|
856 |
+
st.markdown('<div class="map-container">', unsafe_allow_html=True)
|
857 |
+
|
858 |
+
if generate_map or 'last_map' not in st.session_state:
|
859 |
+
with st.spinner('در حال تولید نقشه...'):
|
860 |
+
m = create_ee_map(
|
861 |
+
selected_farm,
|
862 |
+
selected_date.strftime('%Y-%m-%d'),
|
863 |
+
selected_layer
|
864 |
+
)
|
865 |
+
if m:
|
866 |
+
st.session_state.last_map = m
|
867 |
+
folium_static(m, width=800, height=600)
|
868 |
+
st.success(f"نقشه {selected_layer} برای مزرعه {selected_farm} با موفقیت تولید شد.")
|
869 |
+
else:
|
870 |
+
st.error("خطا در تولید نقشه. لطفاً دوباره تلاش کنید.")
|
871 |
+
elif 'last_map' in st.session_state:
|
872 |
+
folium_static(st.session_state.last_map, width=800, height=600)
|
873 |
+
|
874 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
875 |
+
st.info("""
|
876 |
+
**نکته:** این نقشه بر اساس تصاویر Sentinel-2 و Sentinel-1 تولید شده است.
|
877 |
+
برای دقت بیشتر، تاریخی با ابرناکی کم انتخاب کنید.
|
878 |
+
""")
|
879 |
+
|
880 |
+
with stats_tab:
|
881 |
+
if 'last_map' in st.session_state:
|
882 |
+
|
883 |
+
stats = calculate_farm_stats(selected_farm, selected_layer, selected_date.strftime('%Y-%m-%d')) # Pass the date string
|
884 |
+
|
885 |
+
if stats: #Check for errors
|
886 |
+
col1, col2, col3, col4 = st.columns(4)
|
887 |
+
|
888 |
+
with col1:
|
889 |
+
st.markdown('<div class="metric-card">', unsafe_allow_html=True)
|
890 |
+
st.markdown(f'<div class="metric-value">{stats["mean"]:.2f}</div>', unsafe_allow_html=True)
|
891 |
+
st.markdown(f'<div class="metric-label">میانگین {selected_layer}</div>', unsafe_allow_html=True)
|
892 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
893 |
+
|
894 |
+
with col2:
|
895 |
+
st.markdown('<div class="metric-card">', unsafe_allow_html=True)
|
896 |
+
st.markdown(f'<div class="metric-value">{stats["max"]:.2f}</div>', unsafe_allow_html=True)
|
897 |
+
st.markdown(f'<div class="metric-label">حداکثر {selected_layer}</div>', unsafe_allow_html=True)
|
898 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
899 |
+
|
900 |
+
with col3:
|
901 |
+
st.markdown('<div class="metric-card">', unsafe_allow_html=True)
|
902 |
+
st.markdown(f'<div class="metric-value">{stats["min"]:.2f}</div>', unsafe_allow_html=True)
|
903 |
+
st.markdown(f'<div class="metric-label">حداقل {selected_layer}</div>', unsafe_allow_html=True)
|
904 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
905 |
+
|
906 |
+
with col4:
|
907 |
+
st.markdown('<div class="metric-card">', unsafe_allow_html=True)
|
908 |
+
st.markdown(f'<div class="metric-value">{stats["std_dev"]:.2f}</div>', unsafe_allow_html=True)
|
909 |
+
st.markdown(f'<div class="metric-label">انحراف معیار</div>', unsafe_allow_html=True)
|
910 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
911 |
+
|
912 |
+
fig = px.histogram(
|
913 |
+
x=stats["histogram_data"],
|
914 |
+
nbins=20,
|
915 |
+
title=f"توزیع مقادیر {selected_layer} در مزرعه {selected_farm}",
|
916 |
+
labels={"x": f"مقدار {selected_layer}", "y": "فراوانی"},
|
917 |
+
color_discrete_sequence=["#1a8754"]
|
918 |
+
)
|
919 |
+
fig.update_layout(
|
920 |
+
font=dict(family="Vazirmatn"),
|
921 |
+
template="plotly_white",
|
922 |
+
bargap=0.1
|
923 |
+
)
|
924 |
+
st.plotly_chart(fig, use_container_width=True)
|
925 |
+
|
926 |
+
st.markdown("### تحلیل زمانی")
|
927 |
+
dates = pd.date_range(end=selected_date, periods=30, freq='D')
|
928 |
+
values = np.random.normal(stats["mean"], stats["std_dev"] / 2, 30)
|
929 |
+
values = np.clip(values, stats["min"], stats["max"])
|
930 |
+
fig = px.line(
|
931 |
+
x=dates,
|
932 |
+
y=values,
|
933 |
+
title=f"روند تغییرات {selected_layer} در 30 روز گذشته",
|
934 |
+
labels={"x": "تاریخ", "y": f"مقدار {selected_layer}"},
|
935 |
+
markers=True
|
936 |
+
)
|
937 |
+
fig.update_layout(
|
938 |
+
font=dict(family="Vazirmatn"),
|
939 |
+
template="plotly_white",
|
940 |
+
hovermode="x unified"
|
941 |
+
)
|
942 |
+
st.plotly_chart(fig, use_container_width=True)
|
943 |
+
|
944 |
+
if selected_layer == "SoilMoisture":
|
945 |
+
st.markdown("### پیشنهادات مدیریت آب")
|
946 |
+
if stats["mean"] < -20:
|
947 |
+
st.markdown("- **افزایش آبیاری**: رطوبت خاک بسیار پایین است.")
|
948 |
+
elif stats["mean"] > -10:
|
949 |
+
st.markdown("- **کاهش آبیاری**: رطوبت خاک بیش از حد است.")
|
950 |
+
else:
|
951 |
+
st.markdown("- **مدیریت بهینه**: رطوبت خاک در محدوده مناسب است.")
|
952 |
+
else:
|
953 |
+
st.warning("Could not calculate stats. Check error messages above.") #Inform user
|
954 |
+
|
955 |
+
|
956 |
+
else:
|
957 |
+
st.warning("لطفاً ابتدا یک نقشه تولید کنید.")
|
958 |
+
|
959 |
+
# Data Entry Page (same as before)
|
960 |
+
elif selected == "ورود اطلاعات":
|
961 |
+
# ... (Data Entry Page content – same as before)
|
962 |
+
|
963 |
+
# Data Analysis Page (same as before)
|
964 |
+
elif selected == "تحلیل دادهها":
|
965 |
+
# ... (Data Analysis Page content – same as before)
|
966 |
+
|
967 |
+
# Reporting Page (same as before)
|
968 |
+
elif selected == "گزارشگیری":
|
969 |
+
# ... (Reporting Page content – same as before)
|
970 |
+
|
971 |
+
# Settings Page (same as before)
|
972 |
+
elif selected == "تنظیمات":
|
973 |
+
# ... (Settings Page content – same as before)
|
974 |
+
|
975 |
+
# Add a footer (same as before)
|
976 |
+
st.markdown("""
|
977 |
+
<footer style="position: fixed; left: 0; bottom: 0; width: 100%; background-color: #1a8754; color: white; text-align: center; padding: 10px 0;">
|
978 |
+
<p>© سامانه هوشمند پایش مزارع نیشکر کشت و صنعت دهخدا | طراحی شده توسط تیم مطالعات کاربردی توسعه</p>
|
979 |
+
</footer>
|
980 |
+
""", unsafe_allow_html=True)
|