Updated Layout
Browse files- app.py +51 -20
- authentication.py +1 -1
- pag/add_field.py +3 -3
- pag/edit.py +15 -18
- pag/monitor.py +38 -57
app.py
CHANGED
@@ -1,27 +1,56 @@
|
|
1 |
# main.py
|
2 |
import streamlit as st
|
3 |
import authentication
|
|
|
4 |
import streamlit as st
|
5 |
-
from pag import add_field, edit, monitor
|
|
|
6 |
|
7 |
|
8 |
def authenticate_user():
|
9 |
-
st.title("Welcome to :orange[Field Monitoring App]")
|
10 |
st.markdown("""
|
11 |
<style>
|
12 |
.stSelectbox > div > div {cursor: pointer;}
|
13 |
</style>
|
14 |
""", unsafe_allow_html=True)
|
15 |
if not st.session_state.authenticated:
|
16 |
-
|
|
|
17 |
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
-
elif choice == "Login":
|
22 |
-
authentication.login()
|
23 |
-
elif choice == "SignUp":
|
24 |
-
authentication.signup()
|
25 |
|
26 |
return False
|
27 |
|
@@ -33,19 +62,21 @@ def main():
|
|
33 |
|
34 |
if st.session_state.authenticated:
|
35 |
st.sidebar.title("Navigation")
|
|
|
|
|
36 |
options = st.sidebar.radio("Choose an option:",
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
|
|
47 |
elif options == "Monitor Fields":
|
48 |
-
st.title(":orange[Field Monitoring]")
|
49 |
monitor.monitor_fields()
|
50 |
else:
|
51 |
authenticate_user()
|
|
|
1 |
# main.py
|
2 |
import streamlit as st
|
3 |
import authentication
|
4 |
+
from authentication import greeting
|
5 |
import streamlit as st
|
6 |
+
from pag import add_field, edit, monitor,contact_form
|
7 |
+
st. set_page_config(layout="wide")
|
8 |
|
9 |
|
10 |
def authenticate_user():
|
|
|
11 |
st.markdown("""
|
12 |
<style>
|
13 |
.stSelectbox > div > div {cursor: pointer;}
|
14 |
</style>
|
15 |
""", unsafe_allow_html=True)
|
16 |
if not st.session_state.authenticated:
|
17 |
+
st.title("Welcome to :orange[Field Monitoring App]")
|
18 |
+
row1_col1, row1_col2 = st.columns([2, 1])
|
19 |
|
20 |
+
with row1_col1:
|
21 |
+
choice = st.selectbox("Interested? Sign up or log in if you have an account",options=["Login","SignUp","Contact Us"])
|
22 |
+
if choice == "SignUp":
|
23 |
+
authentication.signup()
|
24 |
+
elif choice == "Login":
|
25 |
+
st.title("Have an account? :orange[Sign In]")
|
26 |
+
st.toast("Use your username and password to access our services", icon='😍')
|
27 |
+
authentication.login()
|
28 |
+
elif choice == "Contact Us":
|
29 |
+
contact_form.main()
|
30 |
+
|
31 |
+
|
32 |
+
|
33 |
+
with row1_col2:
|
34 |
+
st.title(":orange[App Description]")
|
35 |
+
|
36 |
+
st.markdown("""
|
37 |
+
Our application is designed to empower farmers and land managers with precise, up-to-date information about their fields. Leveraging the power of advanced satellite imagery analysis, our tool provides key metrics like the Normalized Difference Vegetation Index (NDVI) to assess plant health, moisture levels, and overall field conditions.
|
38 |
+
|
39 |
+
#### :orange[Key Features]
|
40 |
+
|
41 |
+
- **:orange[Real-time Field Data]**: Access the latest satellite data to monitor your fields in real-time.
|
42 |
+
- **:orange[Field Health Analysis]**: Utilize NDVI and other indices to make informed decisions about crop health and management strategies.
|
43 |
+
- **:orange[Interactive Map Views]**: Explore your fields with interactive maps, get detailed insights with just a click.
|
44 |
+
- **:orange[Field History Tracking]**: Review historical data to track changes and adapt your farming practices accordingly.
|
45 |
+
- **:orange[Data-Driven Insights]**: Make better decisions with insights driven by accurate, reliable data.
|
46 |
+
|
47 |
+
We are committed to providing you with the tools you need to manage your fields more effectively and increase your yields. Get started by adding your fields and see the immediate benefits of precision agriculture.
|
48 |
+
|
49 |
+
For any questions or assistance, feel free to reach out through our contact page.
|
50 |
+
|
51 |
+
Happy Farming!
|
52 |
+
""", unsafe_allow_html=True)
|
53 |
|
|
|
|
|
|
|
|
|
54 |
|
55 |
return False
|
56 |
|
|
|
62 |
|
63 |
if st.session_state.authenticated:
|
64 |
st.sidebar.title("Navigation")
|
65 |
+
row1_col1, row1_col2 = st.columns([2, 1])
|
66 |
+
|
67 |
options = st.sidebar.radio("Choose an option:",
|
68 |
+
("Add and Manage Fields", "Monitor Fields"))
|
69 |
+
if options == "Add and Manage Fields":
|
70 |
+
with row1_col1:
|
71 |
+
st.title("Welcome to :orange[Field Monitoring App]")
|
72 |
+
add_field.add_drawing()
|
73 |
+
with row1_col2:
|
74 |
+
st.title(":orange[Field Management]")
|
75 |
+
current_user = greeting("Manage your fields")
|
76 |
+
|
77 |
+
edit.edit_fields(current_user)
|
78 |
+
|
79 |
elif options == "Monitor Fields":
|
|
|
80 |
monitor.monitor_fields()
|
81 |
else:
|
82 |
authenticate_user()
|
authentication.py
CHANGED
@@ -172,4 +172,4 @@ def login():
|
|
172 |
st.warning("Incorrect Username/Password")
|
173 |
|
174 |
# Call create_usertable to ensure the table is created/updated when the script runs
|
175 |
-
create_usertable()
|
|
|
172 |
st.warning("Incorrect Username/Password")
|
173 |
|
174 |
# Call create_usertable to ensure the table is created/updated when the script runs
|
175 |
+
create_usertable()
|
pag/add_field.py
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import utils
|
2 |
import os
|
3 |
import folium
|
@@ -8,12 +9,10 @@ from folium.plugins import Draw
|
|
8 |
from shapely.geometry import Polygon
|
9 |
from streamlit_folium import st_folium
|
10 |
from authentication import greeting, check_password
|
11 |
-
from functools import partial
|
12 |
import geopy
|
13 |
from pyproj import Transformer
|
14 |
from shapely.ops import transform
|
15 |
from geopy.geocoders import Nominatim
|
16 |
-
from streamlit_folium import folium_static
|
17 |
from shapely.ops import transform
|
18 |
from geopy.geocoders import Nominatim
|
19 |
|
@@ -38,7 +37,7 @@ def display_existing_fields(current_user):
|
|
38 |
with st.expander("Existing Fields", expanded=False):
|
39 |
if os.path.exists(f"fields_{current_user}.parquet"):
|
40 |
gdf = gpd.read_parquet(f"fields_{current_user}.parquet")
|
41 |
-
st.
|
42 |
mm = gdf.explore()
|
43 |
st_folium(mm)
|
44 |
else:
|
@@ -80,6 +79,7 @@ def display_map_and_drawing_controls(field_map, center_start):
|
|
80 |
st.info("IMPORTANT: Click on the drawing to confirm the drawn field", icon="🚨")
|
81 |
sat_basemap = utils.basemaps['Google Satellite Hybrid'] # Change this line to use 'Google Satellite Hybrid'
|
82 |
sat_basemap.add_to(field_map)
|
|
|
83 |
folium.LayerControl().add_to(field_map)
|
84 |
output = st_folium(field_map, center=center_start, zoom=zoom_start, key="new", width=800)
|
85 |
active_drawing = output['last_active_drawing']
|
|
|
1 |
+
# add_field.py
|
2 |
import utils
|
3 |
import os
|
4 |
import folium
|
|
|
9 |
from shapely.geometry import Polygon
|
10 |
from streamlit_folium import st_folium
|
11 |
from authentication import greeting, check_password
|
|
|
12 |
import geopy
|
13 |
from pyproj import Transformer
|
14 |
from shapely.ops import transform
|
15 |
from geopy.geocoders import Nominatim
|
|
|
16 |
from shapely.ops import transform
|
17 |
from geopy.geocoders import Nominatim
|
18 |
|
|
|
37 |
with st.expander("Existing Fields", expanded=False):
|
38 |
if os.path.exists(f"fields_{current_user}.parquet"):
|
39 |
gdf = gpd.read_parquet(f"fields_{current_user}.parquet")
|
40 |
+
st.table(gdf.name.tolist())
|
41 |
mm = gdf.explore()
|
42 |
st_folium(mm)
|
43 |
else:
|
|
|
79 |
st.info("IMPORTANT: Click on the drawing to confirm the drawn field", icon="🚨")
|
80 |
sat_basemap = utils.basemaps['Google Satellite Hybrid'] # Change this line to use 'Google Satellite Hybrid'
|
81 |
sat_basemap.add_to(field_map)
|
82 |
+
folium.plugins.Geocoder().add_to(field_map)
|
83 |
folium.LayerControl().add_to(field_map)
|
84 |
output = st_folium(field_map, center=center_start, zoom=zoom_start, key="new", width=800)
|
85 |
active_drawing = output['last_active_drawing']
|
pag/edit.py
CHANGED
@@ -1,15 +1,13 @@
|
|
|
|
1 |
import os
|
2 |
import utils
|
3 |
import streamlit as st
|
4 |
import geopandas as gpd
|
5 |
-
from streamlit_folium import
|
6 |
-
from authentication import greeting, check_password
|
7 |
import folium
|
8 |
-
import json
|
9 |
import time
|
10 |
import pandas as pd
|
11 |
|
12 |
-
|
13 |
def add_properties(df, col_name, value, field_name):
|
14 |
if col_name not in df.columns:
|
15 |
df[col_name] = None
|
@@ -41,8 +39,8 @@ def read_custom_property():
|
|
41 |
return custom_property_name, custom_property_value
|
42 |
|
43 |
|
44 |
-
def edit_fields():
|
45 |
-
current_user = greeting("Manage your fields")
|
46 |
fields_file_path = f"fields_{current_user}.parquet"
|
47 |
history_file_path = f"history_{current_user}.csv"
|
48 |
|
@@ -60,21 +58,21 @@ def edit_fields():
|
|
60 |
history_df = pd.DataFrame(columns=['field_name', 'start_date', 'end_date', 'crop', 'irrigation_method'])
|
61 |
|
62 |
st.info("Hover over the field to show the properties or check the Existing Fields List below")
|
63 |
-
fields_map = gdf.explore()
|
64 |
-
sat_basemap = utils.basemaps['Google Satellite']
|
65 |
-
sat_basemap.add_to(fields_map)
|
66 |
-
folium.LayerControl().add_to(fields_map)
|
67 |
-
folium_static(fields_map, height=300, width=600)
|
68 |
-
|
69 |
-
with st.expander("Existing Fields List", expanded=False):
|
70 |
-
# lis = [(f"Name:{gdf.iloc[i]['name']}",f"location: {gdf.iloc[i]['geometry']}" )for i in range(len(gdf))]
|
71 |
-
st.write(gdf)
|
72 |
-
|
73 |
field_name = select_field(gdf)
|
74 |
if field_name == "Select Field":
|
|
|
|
|
|
|
|
|
|
|
75 |
st.info("No Field Selected Yet!")
|
76 |
else:
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
78 |
option_menu = st.radio(f"Please add your {field_name} field information, historical data will help train our AI model", options=["View Field Info", "Add Field Information","Add Field Cultivation History", "Delete"], key="option_menu", help="Select the operation to perform")
|
79 |
if option_menu == "View Field Info":
|
80 |
field = gdf[gdf['name'] == field_name]
|
@@ -105,7 +103,6 @@ def edit_fields():
|
|
105 |
if custom_property_name != "" and custom_property_value != "":
|
106 |
gdf = add_properties(gdf, custom_property_name, custom_property_value, field_name)
|
107 |
gdf.to_parquet(f"fields_{current_user}.parquet")
|
108 |
-
# st.rerun()
|
109 |
st.success("Field Information Updated Successfully!")
|
110 |
st.info("Please Select View above to see the updated field information")
|
111 |
|
|
|
1 |
+
# edit.py
|
2 |
import os
|
3 |
import utils
|
4 |
import streamlit as st
|
5 |
import geopandas as gpd
|
6 |
+
from streamlit_folium import folium_static
|
|
|
7 |
import folium
|
|
|
8 |
import time
|
9 |
import pandas as pd
|
10 |
|
|
|
11 |
def add_properties(df, col_name, value, field_name):
|
12 |
if col_name not in df.columns:
|
13 |
df[col_name] = None
|
|
|
39 |
return custom_property_name, custom_property_value
|
40 |
|
41 |
|
42 |
+
def edit_fields(current_user):
|
43 |
+
# current_user = greeting("Manage your fields")
|
44 |
fields_file_path = f"fields_{current_user}.parquet"
|
45 |
history_file_path = f"history_{current_user}.csv"
|
46 |
|
|
|
58 |
history_df = pd.DataFrame(columns=['field_name', 'start_date', 'end_date', 'crop', 'irrigation_method'])
|
59 |
|
60 |
st.info("Hover over the field to show the properties or check the Existing Fields List below")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
field_name = select_field(gdf)
|
62 |
if field_name == "Select Field":
|
63 |
+
fields_map = gdf.explore()
|
64 |
+
sat_basemap = utils.basemaps['Google Satellite']
|
65 |
+
sat_basemap.add_to(fields_map)
|
66 |
+
folium.LayerControl().add_to(fields_map)
|
67 |
+
folium_static(fields_map, height=300, width=400)
|
68 |
st.info("No Field Selected Yet!")
|
69 |
else:
|
70 |
+
fields_map = gdf[gdf['name'] == field_name].explore()
|
71 |
+
sat_basemap = utils.basemaps['Google Satellite']
|
72 |
+
sat_basemap.add_to(fields_map)
|
73 |
+
folium.LayerControl().add_to(fields_map)
|
74 |
+
folium_static(fields_map, height=300, width=400)
|
75 |
+
st.subheader(f":green[{field_name}]")
|
76 |
option_menu = st.radio(f"Please add your {field_name} field information, historical data will help train our AI model", options=["View Field Info", "Add Field Information","Add Field Cultivation History", "Delete"], key="option_menu", help="Select the operation to perform")
|
77 |
if option_menu == "View Field Info":
|
78 |
field = gdf[gdf['name'] == field_name]
|
|
|
103 |
if custom_property_name != "" and custom_property_value != "":
|
104 |
gdf = add_properties(gdf, custom_property_name, custom_property_value, field_name)
|
105 |
gdf.to_parquet(f"fields_{current_user}.parquet")
|
|
|
106 |
st.success("Field Information Updated Successfully!")
|
107 |
st.info("Please Select View above to see the updated field information")
|
108 |
|
pag/monitor.py
CHANGED
@@ -1,22 +1,15 @@
|
|
|
|
1 |
import os
|
2 |
import utils
|
3 |
import streamlit as st
|
4 |
import geopandas as gpd
|
5 |
-
from streamlit_folium import st_folium, folium_static
|
6 |
from authentication import greeting, check_password
|
7 |
-
import folium
|
8 |
from senHub import SenHub
|
9 |
from datetime import datetime
|
10 |
-
from sentinelhub import SHConfig
|
11 |
import requests
|
12 |
import process
|
13 |
-
import joblib
|
14 |
from zipfile import ZipFile
|
15 |
-
import matplotlib.pyplot as plt
|
16 |
-
from plotly.subplots import make_subplots
|
17 |
-
import plotly.graph_objects as go
|
18 |
-
import pydeck as pdk
|
19 |
-
import pandas as pd
|
20 |
import plotly.express as px
|
21 |
|
22 |
def check_authentication():
|
@@ -87,7 +80,7 @@ def get_cuarted_df_for_field(df, field, date, metric, clientName):
|
|
87 |
|
88 |
|
89 |
def track(metric, field_name, src_df, client_name):
|
90 |
-
|
91 |
dates = []
|
92 |
date = -1
|
93 |
if 'dates' not in st.session_state:
|
@@ -147,38 +140,22 @@ def track(metric, field_name, src_df, client_name):
|
|
147 |
field_data = metric_data.merge(cloud_cover_data, on='geometry')
|
148 |
|
149 |
# Display the field data
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
152 |
|
153 |
#Get Avarage Cloud Cover
|
154 |
-
avg_clp = field_data[f'CLP_{date}'].mean() *100
|
155 |
|
156 |
# If the avarage cloud cover is greater than 80%, display a warning message
|
157 |
if avg_clp > 80:
|
158 |
st.warning(f'⚠️ The Avarage Cloud Cover is {avg_clp}%')
|
159 |
st.info('Please Select A Different Date')
|
160 |
|
161 |
-
|
162 |
-
|
163 |
-
#Title, Colormap and Legend
|
164 |
-
title = f'{metric} for selected field {field_name} (Field ID: {field_name}) in {date}'
|
165 |
-
cmap = 'RdYlGn'
|
166 |
-
|
167 |
-
# Create a map of the field data
|
168 |
-
# field_data_map = field_data.explore(
|
169 |
-
# column=f'{metric}_{date}',
|
170 |
-
# cmap=cmap,
|
171 |
-
# legend=True,
|
172 |
-
# vmin=0,
|
173 |
-
# vmax=1,
|
174 |
-
# marker_type='circle', marker_kwds={'radius':5.3, 'fill':True})
|
175 |
-
|
176 |
-
# Add Google Satellite as a base map
|
177 |
-
# google_map = utils.basemaps['Google Satellite']
|
178 |
-
# google_map.add_to(field_data_map)
|
179 |
|
180 |
-
# # Display the map
|
181 |
-
# st_folium(field_data_map, width = 725, key=f'Field Data Map - {metric}')
|
182 |
df = field_data.copy()
|
183 |
df['latitude'] = df['geometry'].y
|
184 |
df['longitude'] = df['geometry'].x
|
@@ -191,6 +168,8 @@ def track(metric, field_name, src_df, client_name):
|
|
191 |
color=f'{metric}_{date}',
|
192 |
color_continuous_scale='RdYlGn',
|
193 |
range_color=(0, 1),
|
|
|
|
|
194 |
size_max=15,
|
195 |
zoom=13,
|
196 |
)
|
@@ -251,32 +230,34 @@ def track(metric, field_name, src_df, client_name):
|
|
251 |
|
252 |
|
253 |
def monitor_fields():
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
|
261 |
-
|
262 |
-
with st.expander("Existing Fields List", expanded=False):
|
263 |
-
st.write(gdf)
|
264 |
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
else:
|
270 |
-
with st.expander("Metrics Explanation", expanded=False):
|
271 |
-
st.write("NDVI: Normalized Difference Vegetation Index, Mainly used to monitor the health of vegetation")
|
272 |
-
st.write("LAI: Leaf Area Index, Mainly used to monitor the productivity of vegetation")
|
273 |
-
st.write("CAB: Chlorophyll Absorption in the Blue band, Mainly used to monitor the chlorophyll content in vegetation")
|
274 |
-
# st.write("NDMI: Normalized Difference Moisture Index, Mainly used to monitor the moisture content in vegetation")
|
275 |
-
st.success("More metrics and analysis features will be added soon")
|
276 |
-
metric = st.radio("Select Metric to Monitor", ["NDVI", "LAI", "CAB"], key="metric", index=0, help="Select the metric to monitor")
|
277 |
-
st.write(f"Monitoring {metric} for {field_name}")
|
278 |
-
|
279 |
-
track(metric, field_name, gdf, current_user)
|
280 |
|
281 |
|
282 |
|
|
|
1 |
+
# monitor.py
|
2 |
import os
|
3 |
import utils
|
4 |
import streamlit as st
|
5 |
import geopandas as gpd
|
|
|
6 |
from authentication import greeting, check_password
|
|
|
7 |
from senHub import SenHub
|
8 |
from datetime import datetime
|
9 |
+
from sentinelhub import SHConfig
|
10 |
import requests
|
11 |
import process
|
|
|
12 |
from zipfile import ZipFile
|
|
|
|
|
|
|
|
|
|
|
13 |
import plotly.express as px
|
14 |
|
15 |
def check_authentication():
|
|
|
80 |
|
81 |
|
82 |
def track(metric, field_name, src_df, client_name):
|
83 |
+
st.title(":green[Select Date and Start Monitoring]")
|
84 |
dates = []
|
85 |
date = -1
|
86 |
if 'dates' not in st.session_state:
|
|
|
140 |
field_data = metric_data.merge(cloud_cover_data, on='geometry')
|
141 |
|
142 |
# Display the field data
|
143 |
+
avg_clp = field_data[f'CLP_{date}'].mean() *100
|
144 |
+
avg_metric = field_data[f'{metric}_{date}'].mean()
|
145 |
+
st.write(f'Field Data for (Field ID: {field_name}) on {date}')
|
146 |
+
col1,col3,col5,col2,col4 = st.columns(5)
|
147 |
+
col1.metric(f":orange[Average {metric}]", value=f"{avg_metric :.2f}")
|
148 |
+
col2.metric(":green[Cloud Cover]", value=f"{avg_clp :.2f}%")
|
149 |
|
150 |
#Get Avarage Cloud Cover
|
|
|
151 |
|
152 |
# If the avarage cloud cover is greater than 80%, display a warning message
|
153 |
if avg_clp > 80:
|
154 |
st.warning(f'⚠️ The Avarage Cloud Cover is {avg_clp}%')
|
155 |
st.info('Please Select A Different Date')
|
156 |
|
157 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
|
|
|
|
|
159 |
df = field_data.copy()
|
160 |
df['latitude'] = df['geometry'].y
|
161 |
df['longitude'] = df['geometry'].x
|
|
|
168 |
color=f'{metric}_{date}',
|
169 |
color_continuous_scale='RdYlGn',
|
170 |
range_color=(0, 1),
|
171 |
+
width= 800,
|
172 |
+
height=600,
|
173 |
size_max=15,
|
174 |
zoom=13,
|
175 |
)
|
|
|
230 |
|
231 |
|
232 |
def monitor_fields():
|
233 |
+
row1,row2 = st.columns([1,2])
|
234 |
+
with row1:
|
235 |
+
st.title(":orange[Field Monitoring]")
|
236 |
+
|
237 |
+
current_user = greeting("Let's take a look how these fields are doing")
|
238 |
+
if os.path.exists(f"fields_{current_user}.parquet"):
|
239 |
+
gdf = gpd.read_parquet(f"fields_{current_user}.parquet")
|
240 |
+
field_name = select_field(gdf)
|
241 |
+
if field_name == "Select Field":
|
242 |
+
st.info("No Field Selected Yet!")
|
243 |
+
else:
|
244 |
+
metric = st.radio("Select Metric to Monitor", ["NDVI", "LAI", "CAB"], key="metric", index=0, help="Select the metric to monitor")
|
245 |
+
st.success(f"Monitoring {metric} for {field_name}")
|
246 |
+
with st.expander("Metrics Explanation", expanded=False):
|
247 |
+
st.write("NDVI: Normalized Difference Vegetation Index, Mainly used to monitor the health of vegetation")
|
248 |
+
st.write("LAI: Leaf Area Index, Mainly used to monitor the productivity of vegetation")
|
249 |
+
st.write("CAB: Chlorophyll Absorption in the Blue band, Mainly used to monitor the chlorophyll content in vegetation")
|
250 |
+
# st.write("NDMI: Normalized Difference Moisture Index, Mainly used to monitor the moisture content in vegetation")
|
251 |
+
st.info("More metrics and analysis features will be added soon")
|
252 |
+
else:
|
253 |
+
st.info("No Fields Added Yet!")
|
254 |
+
return
|
255 |
|
256 |
+
|
|
|
|
|
257 |
|
258 |
+
with row2:
|
259 |
+
if field_name != "Select Field":
|
260 |
+
track(metric, field_name, gdf, current_user)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
|
262 |
|
263 |
|