@@ -3138,88 +2633,56 @@ def get_city_coordinates(city_name):
Key Impact Areas:
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
- for impact in report["impact_assessment"]["impact_areas"]:
- st.markdown(
- f"- {impact}
",
- unsafe_allow_html=True,
- )
+ for impact in report['impact_assessment']['impact_areas']:
+ st.markdown(f"- {impact}
", unsafe_allow_html=True)
- st.markdown(
- """
+ st.markdown("""
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
# Adaptive strategies
- st.markdown(
- "
Recommended Adaptive Strategies
",
- unsafe_allow_html=True,
- )
+ st.markdown("
Recommended Adaptive Strategies
", unsafe_allow_html=True)
# Create tabs for different timeline categories
- timeline_tabs = st.tabs(
- [
- "Near-term (1-5 years)",
- "Mid-term (5-15 years)",
- "Long-term (15+ years)",
- ]
- )
+ timeline_tabs = st.tabs(["Near-term (1-5 years)", "Mid-term (5-15 years)", "Long-term (15+ years)"])
with timeline_tabs[0]:
- if report["implementation_timeline"]["near_term"]:
- for i, strategy in enumerate(
- report["implementation_timeline"]["near_term"]
- ):
- st.markdown(
- f"""
+ if report['implementation_timeline']['near_term']:
+ for i, strategy in enumerate(report['implementation_timeline']['near_term']):
+ st.markdown(f"""
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
else:
st.info("No near-term strategies identified for this scenario.")
with timeline_tabs[1]:
- if report["implementation_timeline"]["mid_term"]:
- for i, strategy in enumerate(
- report["implementation_timeline"]["mid_term"]
- ):
- st.markdown(
- f"""
+ if report['implementation_timeline']['mid_term']:
+ for i, strategy in enumerate(report['implementation_timeline']['mid_term']):
+ st.markdown(f"""
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
else:
st.info("No mid-term strategies identified for this scenario.")
with timeline_tabs[2]:
- if report["implementation_timeline"]["long_term"]:
- for i, strategy in enumerate(
- report["implementation_timeline"]["long_term"]
- ):
- st.markdown(
- f"""
+ if report['implementation_timeline']['long_term']:
+ for i, strategy in enumerate(report['implementation_timeline']['long_term']):
+ st.markdown(f"""
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
else:
st.info("No long-term strategies identified for this scenario.")
@@ -3228,11 +2691,10 @@ def get_city_coordinates(city_name):
"low": "#4CAF50",
"moderate": "#FFC107",
"high": "#FF9800",
- "transformative": "#F44336",
+ "transformative": "#F44336"
}
- st.markdown(
- f"""
+ st.markdown(f"""
Implementation Considerations
@@ -3246,9 +2708,7 @@ def get_city_coordinates(city_name):
Industries with higher severity impacts typically require more immediate and comprehensive adaptation measures.
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
# Add option to export the report as JSON
report_json = json.dumps(report, indent=2)
@@ -3262,16 +2722,12 @@ def get_city_coordinates(city_name):
# Add information about data sources
st.markdown("---")
- st.markdown(
- """
+ st.markdown("""
About Our Climate Data
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
with st.expander("Why We Trust This Data", expanded=False):
- st.markdown(
- """
+ st.markdown("""
NASA POWER Data
The climate data used in this analysis comes from the NASA POWER (Prediction of Worldwide Energy Resource) dataset, which is based on satellite observations and reanalysis models.
@@ -3313,13 +2769,10 @@ def get_city_coordinates(city_name):
For the most critical decisions, we recommend consulting with climate scientists and industry-specific experts to supplement this analysis.
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
with st.expander("Data Processing & Methodology", expanded=False):
- st.markdown(
- """
+ st.markdown("""
How We Process Climate Data
Our climate resilience analysis involves multiple steps to transform raw climate data into actionable insights:
@@ -3354,13 +2807,10 @@ def get_city_coordinates(city_name):
All visualizations are generated using real climate data and industry-specific vulnerabilities established through scientific literature.
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
with st.expander("Data Sources & References", expanded=False):
- st.markdown(
- """
+ st.markdown("""
Primary Data Sources
@@ -3387,38 +2837,23 @@ def get_city_coordinates(city_name):
For more detailed information about our data sources and methodology, please contact us.
- """,
- unsafe_allow_html=True,
- )
+ """, unsafe_allow_html=True)
except Exception as e:
st.error(f"An error occurred while generating the report: {str(e)}")
- st.error(
- "Please try again with different parameters or check the console for more details."
- )
+ st.error("Please try again with different parameters or check the console for more details.")
raise e
elif st.session_state.active_function == "climate_story":
st.subheader("Interactive Climate Story Generator")
# Location input method selection
- location_method = st.radio(
- "Select location input method:",
- ["City Name", "Coordinates"],
- horizontal=True,
- key="story_location_method",
- )
+ location_method = st.radio("Select location input method:", ["City Name", "Coordinates"], horizontal=True, key="story_location_method")
if location_method == "City Name":
- city = st.text_input(
- "Enter city name (e.g., 'New York', 'London, UK')",
- value=(
- "San Francisco, CA"
- if "last_city" not in st.session_state
- else st.session_state.last_city
- ),
- key="story_city_input",
- )
+ city = st.text_input("Enter city name (e.g., 'New York', 'London, UK')",
+ value="San Francisco, CA" if "last_city" not in st.session_state else st.session_state.last_city,
+ key="story_city_input")
if city:
st.session_state.last_city = city
@@ -3429,53 +2864,36 @@ def get_city_coordinates(city_name):
longitude = lon
st.session_state.user_location = {"lat": latitude, "lon": longitude}
else:
- st.warning(
- "Could not find coordinates for this city. Please check the spelling or try using coordinates directly."
- )
+ st.warning("Could not find coordinates for this city. Please check the spelling or try using coordinates directly.")
latitude = st.session_state.user_location["lat"]
longitude = st.session_state.user_location["lon"]
else:
col1, col2 = st.columns(2)
with col1:
- latitude = st.number_input(
- "Latitude",
- value=st.session_state.user_location["lat"],
- min_value=-90.0,
- max_value=90.0,
- key="story_lat",
- )
+ latitude = st.number_input("Latitude", value=st.session_state.user_location["lat"],
+ min_value=-90.0, max_value=90.0, key="story_lat")
with col2:
- longitude = st.number_input(
- "Longitude",
- value=st.session_state.user_location["lon"],
- min_value=-180.0,
- max_value=180.0,
- key="story_lon",
- )
+ longitude = st.number_input("Longitude", value=st.session_state.user_location["lon"],
+ min_value=-180.0, max_value=180.0, key="story_lon")
# Date range
st.write("Select time period for your climate story:")
col1, col2 = st.columns(2)
with col1:
- start_date = st.date_input(
- "Start Date", datetime.now() - timedelta(days=365), key="story_start"
- )
+ start_date = st.date_input("Start Date", datetime.now() - timedelta(days=365), key="story_start")
with col2:
end_date = st.date_input("End Date", datetime.now(), key="story_end")
# Story type selection
- story_type = st.radio(
- "Select story type:",
- ["Personal Experience", "Educational", "Historical Context"],
- horizontal=True,
- key="story_type",
- )
+ story_type = st.radio("Select story type:",
+ ["Personal Experience", "Educational", "Historical Context"],
+ horizontal=True, key="story_type")
# Map story type to the format expected by the generator function
story_type_map = {
"Personal Experience": "personal",
"Educational": "educational",
- "Historical Context": "historical",
+ "Historical Context": "historical"
}
# Generate button
@@ -3483,57 +2901,49 @@ def get_city_coordinates(city_name):
try:
with st.spinner("Fetching climate data and crafting your story..."):
# Convert dates to string format
- start_date_str = start_date.strftime("%Y-%m-%d")
- end_date_str = end_date.strftime("%Y-%m-%d")
+ start_date_str = start_date.strftime('%Y-%m-%d')
+ end_date_str = end_date.strftime('%Y-%m-%d')
# Status message
- st.text(
- f"Fetching climate data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} from {start_date_str} to {end_date_str}..."
- )
+ st.text(f"Fetching climate data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} from {start_date_str} to {end_date_str}...")
# Fetch NASA POWER data
from nasa_data import fetch_nasa_power_data
-
climate_data = fetch_nasa_power_data(
latitude,
longitude,
start_date_str,
end_date_str,
- parameters=["T2M", "PRECTOTCORR", "RH2M", "WS2M"],
+ parameters=["T2M", "PRECTOTCORR", "RH2M", "WS2M"]
)
if climate_data is None or len(climate_data) == 0:
- st.error(
- "Could not fetch climate data for the specified location and time period."
- )
+ st.error("Could not fetch climate data for the specified location and time period.")
st.stop()
# Prepare location and timeframe data for the story generator
location_data = {
"city": city if location_method == "City Name" else None,
"lat": latitude,
- "lon": longitude,
+ "lon": longitude
}
- timeframe_data = {"start_date": start_date, "end_date": end_date}
+ timeframe_data = {
+ "start_date": start_date,
+ "end_date": end_date
+ }
# Generate the climate story
from climate_story_generator import generate_climate_story
# Check if we have the OpenAI API key
if not os.getenv("OPENAI_API_KEY"):
- st.warning(
- "OpenAI API key not found. Please provide your API key in the settings to use this feature."
- )
+ st.warning("OpenAI API key not found. Please provide your API key in the settings to use this feature.")
# Provide option to add the API key
- api_key = st.text_input(
- "Enter your OpenAI API key:", type="password"
- )
+ api_key = st.text_input("Enter your OpenAI API key:", type="password")
if api_key:
os.environ["OPENAI_API_KEY"] = api_key
- st.success(
- "API key set! Click the button again to generate your story."
- )
+ st.success("API key set! Click the button again to generate your story.")
st.rerun()
st.stop()
@@ -3542,7 +2952,7 @@ def get_city_coordinates(city_name):
climate_data,
location_data,
timeframe_data,
- story_type=story_type_map[story_type],
+ story_type=story_type_map[story_type]
)
# Display the story
@@ -3557,10 +2967,7 @@ def get_city_coordinates(city_name):
st.markdown(f"- {insight}")
# Display visualization suggestions
- if (
- "visualization_suggestions" in story
- and story["visualization_suggestions"]
- ):
+ if "visualization_suggestions" in story and story["visualization_suggestions"]:
st.subheader("Suggested Visualizations")
for suggestion in story["visualization_suggestions"]:
st.markdown(f"- {suggestion}")
@@ -3577,31 +2984,23 @@ def get_city_coordinates(city_name):
label="Download Story as Text",
data=story_text,
file_name=f"climate_story_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
- mime="text/plain",
+ mime="text/plain"
)
else:
- st.error(
- f"Error generating story: {story.get('text', 'Unknown error')}"
- )
+ st.error(f"Error generating story: {story.get('text', 'Unknown error')}")
except Exception as e:
st.error(f"Error generating climate story: {str(e)}")
- st.info(
- "This feature requires an OpenAI API key. Please check your settings and try again."
- )
+ st.info("This feature requires an OpenAI API key. Please check your settings and try again.")
elif st.session_state.active_function == "export_anomalies":
st.subheader("Export Climate Anomalies as a Table")
# Data source selection
- data_source = st.radio(
- "Select Data Source", ["Upload CSV File", "Fetch from NASA POWER API"]
- )
+ data_source = st.radio("Select Data Source", ["Upload CSV File", "Fetch from NASA POWER API"])
if data_source == "Upload CSV File":
- uploaded_file = st.file_uploader(
- "Choose a CSV file with climate data", type="csv"
- )
+ uploaded_file = st.file_uploader("Choose a CSV file with climate data", type="csv")
if uploaded_file is not None:
try:
@@ -3615,52 +3014,35 @@ def get_city_coordinates(city_name):
# Check if the data has date and temperature columns
if st.button("Calculate Temperature Anomalies"):
# Get the temperature column
- temp_column = st.selectbox(
- "Select Temperature Column", data.columns
- )
+ temp_column = st.selectbox("Select Temperature Column", data.columns)
date_column = st.selectbox("Select Date Column", data.columns)
if temp_column and date_column:
# Convert date column to datetime if not already
- if data[date_column].dtype != "datetime64[ns]":
+ if data[date_column].dtype != 'datetime64[ns]':
try:
data[date_column] = pd.to_datetime(data[date_column])
except:
- st.error(
- "Could not convert the selected column to date format. Please select a valid date column."
- )
+ st.error("Could not convert the selected column to date format. Please select a valid date column.")
st.stop()
# Calculate monthly averages
- data["Month"] = data[date_column].dt.month
- data["Year"] = data[date_column].dt.year
+ data['Month'] = data[date_column].dt.month
+ data['Year'] = data[date_column].dt.year
# Group by month and calculate the average temperature
- monthly_avg = (
- data.groupby("Month")[temp_column].mean().reset_index()
- )
- monthly_avg.columns = ["Month", "Average_Temperature"]
+ monthly_avg = data.groupby('Month')[temp_column].mean().reset_index()
+ monthly_avg.columns = ['Month', 'Average_Temperature']
# Merge the monthly averages back to the original data
- data = pd.merge(data, monthly_avg, on="Month")
+ data = pd.merge(data, monthly_avg, on='Month')
# Calculate the anomalies
- data["Temperature_Anomaly"] = (
- data[temp_column] - data["Average_Temperature"]
- )
+ data['Temperature_Anomaly'] = data[temp_column] - data['Average_Temperature']
# Create a result dataframe
- result = data[
- [
- date_column,
- temp_column,
- "Average_Temperature",
- "Temperature_Anomaly",
- ]
- ]
- result = result.rename(
- columns={date_column: "Date", temp_column: "Temperature"}
- )
+ result = data[[date_column, temp_column, 'Average_Temperature', 'Temperature_Anomaly']]
+ result = result.rename(columns={date_column: 'Date', temp_column: 'Temperature'})
# Store the result in session state
st.session_state.processed_data = result
@@ -3680,42 +3062,25 @@ def get_city_coordinates(city_name):
# Visualization of anomalies
st.subheader("Visualization of Temperature Anomalies")
- fig = px.scatter(
- result,
- x="Date",
- y="Temperature_Anomaly",
- color="Temperature_Anomaly",
- color_continuous_scale=px.colors.diverging.RdBu_r,
- title="Temperature Anomalies Over Time",
- )
+ fig = px.scatter(result, x='Date', y='Temperature_Anomaly',
+ color='Temperature_Anomaly',
+ color_continuous_scale=px.colors.diverging.RdBu_r,
+ title="Temperature Anomalies Over Time")
st.plotly_chart(fig)
except Exception as e:
st.error(f"Error processing file: {str(e)}")
else: # NASA POWER API
- st.info(
- "This feature will connect to the NASA POWER API to fetch climate data for a specified location and date range."
- )
+ st.info("This feature will connect to the NASA POWER API to fetch climate data for a specified location and date range.")
# Location input method selection
- location_method = st.radio(
- "Select location input method:",
- ["City Name", "Coordinates"],
- horizontal=True,
- key="nasa_location_method",
- )
+ location_method = st.radio("Select location input method:", ["City Name", "Coordinates"], horizontal=True, key="nasa_location_method")
if location_method == "City Name":
- city = st.text_input(
- "Enter city name (e.g., 'New York', 'London, UK')",
- value=(
- "San Francisco, CA"
- if "nasa_last_city" not in st.session_state
- else st.session_state.nasa_last_city
- ),
- key="nasa_city",
- )
+ city = st.text_input("Enter city name (e.g., 'New York', 'London, UK')",
+ value="San Francisco, CA" if "nasa_last_city" not in st.session_state else st.session_state.nasa_last_city,
+ key="nasa_city")
if city:
st.session_state.nasa_last_city = city
@@ -3726,36 +3091,20 @@ def get_city_coordinates(city_name):
longitude = lon
st.session_state.user_location = {"lat": latitude, "lon": longitude}
else:
- st.warning(
- "Could not find coordinates for this city. Please check the spelling or try using coordinates directly."
- )
+ st.warning("Could not find coordinates for this city. Please check the spelling or try using coordinates directly.")
latitude = st.session_state.user_location["lat"]
longitude = st.session_state.user_location["lon"]
else:
col1, col2 = st.columns(2)
with col1:
- latitude = st.number_input(
- "Latitude",
- value=st.session_state.user_location["lat"],
- min_value=-90.0,
- max_value=90.0,
- key="nasa_lat",
- )
+ latitude = st.number_input("Latitude", value=st.session_state.user_location["lat"], min_value=-90.0, max_value=90.0, key="nasa_lat")
with col2:
- longitude = st.number_input(
- "Longitude",
- value=st.session_state.user_location["lon"],
- min_value=-180.0,
- max_value=180.0,
- key="nasa_lon",
- )
+ longitude = st.number_input("Longitude", value=st.session_state.user_location["lon"], min_value=-180.0, max_value=180.0, key="nasa_lon")
# Date range
col1, col2 = st.columns(2)
with col1:
- start_date = st.date_input(
- "Start Date", datetime.now() - timedelta(days=365 * 5), key="nasa_start"
- )
+ start_date = st.date_input("Start Date", datetime.now() - timedelta(days=365*5), key="nasa_start")
with col2:
end_date = st.date_input("End Date", datetime.now(), key="nasa_end")
@@ -3766,13 +3115,11 @@ def get_city_coordinates(city_name):
from nasa_data import fetch_nasa_power_data
# Convert dates to string format for API
- start_date_str = start_date.strftime("%Y-%m-%d")
- end_date_str = end_date.strftime("%Y-%m-%d")
+ start_date_str = start_date.strftime('%Y-%m-%d')
+ end_date_str = end_date.strftime('%Y-%m-%d')
# Status message
- st.text(
- f"Fetching temperature data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} from {start_date_str} to {end_date_str}..."
- )
+ st.text(f"Fetching temperature data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} from {start_date_str} to {end_date_str}...")
# Fetch NASA POWER temperature data
nasa_df = fetch_nasa_power_data(
@@ -3780,41 +3127,28 @@ def get_city_coordinates(city_name):
longitude,
start_date_str,
end_date_str,
- parameters=["T2M"], # Temperature at 2 Meters
+ parameters=["T2M"] # Temperature at 2 Meters
)
# Create a dataframe with the temperature data
- data = pd.DataFrame(
- {
- "Date": nasa_df["Date"],
- "Temperature": nasa_df["T2M"], # Temperature in Celsius
- }
- )
+ data = pd.DataFrame({
+ 'Date': nasa_df['Date'],
+ 'Temperature': nasa_df['T2M'] # Temperature in Celsius
+ })
# Calculate monthly climatology (long-term averages)
- data["Month"] = data["Date"].dt.month
- monthly_avg = (
- data.groupby("Month")["Temperature"].mean().reset_index()
- )
- monthly_avg.columns = ["Month", "Average_Temperature"]
+ data['Month'] = data['Date'].dt.month
+ monthly_avg = data.groupby('Month')['Temperature'].mean().reset_index()
+ monthly_avg.columns = ['Month', 'Average_Temperature']
# Merge the monthly averages back to the original data
- data = pd.merge(data, monthly_avg, on="Month")
+ data = pd.merge(data, monthly_avg, on='Month')
# Calculate the anomalies
- data["Temperature_Anomaly"] = (
- data["Temperature"] - data["Average_Temperature"]
- )
+ data['Temperature_Anomaly'] = data['Temperature'] - data['Average_Temperature']
# Final result
- result = data[
- [
- "Date",
- "Temperature",
- "Average_Temperature",
- "Temperature_Anomaly",
- ]
- ]
+ result = data[['Date', 'Temperature', 'Average_Temperature', 'Temperature_Anomaly']]
# Store the result in session state
st.session_state.processed_data = result
@@ -3834,14 +3168,10 @@ def get_city_coordinates(city_name):
# Visualization of anomalies
st.subheader("Visualization of Temperature Anomalies")
- fig = px.scatter(
- result,
- x="Date",
- y="Temperature_Anomaly",
- color="Temperature_Anomaly",
- color_continuous_scale=px.colors.diverging.RdBu_r,
- title="Temperature Anomalies Over Time",
- )
+ fig = px.scatter(result, x='Date', y='Temperature_Anomaly',
+ color='Temperature_Anomaly',
+ color_continuous_scale=px.colors.diverging.RdBu_r,
+ title="Temperature Anomalies Over Time")
st.plotly_chart(fig)
except Exception as e:
@@ -3885,13 +3215,11 @@ def get_city_coordinates(city_name):
with st.sidebar:
st.title("Data Management")
- upload_file = st.file_uploader(
- "Upload Climate/Weather Dataset", type=["csv", "xlsx"]
- )
+ upload_file = st.file_uploader("Upload Climate/Weather Dataset", type=["csv", "xlsx"])
if upload_file is not None:
try:
- if upload_file.name.endswith(".xlsx"):
+ if upload_file.name.endswith('.xlsx'):
data = pd.read_excel(upload_file)
else:
data = pd.read_csv(upload_file)
@@ -3934,23 +3262,12 @@ def get_city_coordinates(city_name):
st.subheader("Temperature Trends from the Past 5 Years")
# Location selection similar to precipitation map
- location_method = st.radio(
- "Select location input method:",
- ["City Name", "Coordinates"],
- horizontal=True,
- key="temp_location_method",
- )
+ location_method = st.radio("Select location input method:", ["City Name", "Coordinates"], horizontal=True, key="temp_location_method")
if location_method == "City Name":
- city = st.text_input(
- "Enter city name (e.g., 'New York', 'London, UK')",
- value=(
- "San Francisco, CA"
- if "last_city" not in st.session_state
- else st.session_state.last_city
- ),
- key="temp_city_input",
- )
+ city = st.text_input("Enter city name (e.g., 'New York', 'London, UK')",
+ value="San Francisco, CA" if "last_city" not in st.session_state else st.session_state.last_city,
+ key="temp_city_input")
if city:
st.session_state.last_city = city
@@ -3961,45 +3278,27 @@ def get_city_coordinates(city_name):
longitude = lon
st.session_state.user_location = {"lat": latitude, "lon": longitude}
else:
- st.warning(
- "Could not find coordinates for this city. Please check the spelling or try using coordinates directly."
- )
+ st.warning("Could not find coordinates for this city. Please check the spelling or try using coordinates directly.")
latitude = st.session_state.user_location["lat"]
longitude = st.session_state.user_location["lon"]
else:
col1, col2 = st.columns(2)
with col1:
- latitude = st.number_input(
- "Latitude",
- value=st.session_state.user_location["lat"],
- min_value=-90.0,
- max_value=90.0,
- key="temp_lat_input",
- )
+ latitude = st.number_input("Latitude", value=st.session_state.user_location["lat"],
+ min_value=-90.0, max_value=90.0, key="temp_lat_input")
with col2:
- longitude = st.number_input(
- "Longitude",
- value=st.session_state.user_location["lon"],
- min_value=-180.0,
- max_value=180.0,
- key="temp_lon_input",
- )
+ longitude = st.number_input("Longitude", value=st.session_state.user_location["lon"],
+ min_value=-180.0, max_value=180.0, key="temp_lon_input")
st.session_state.user_location = {"lat": latitude, "lon": longitude}
# Date range selection
col1, col2 = st.columns(2)
with col1:
- end_date = st.date_input(
- "End Date (Today)", datetime.now(), key="temp_end_date"
- )
+ end_date = st.date_input("End Date (Today)", datetime.now(), key="temp_end_date")
with col2:
# Calculate start date as 5 years ago from end date
- start_date = st.date_input(
- "Start Date (5 years ago)",
- end_date - timedelta(days=5 * 365),
- key="temp_start_date",
- )
+ start_date = st.date_input("Start Date (5 years ago)", end_date - timedelta(days=5*365), key="temp_start_date")
if st.button("Generate Temperature Trends"):
with st.spinner("Generating temperature trends for the past 5 years..."):
@@ -4008,68 +3307,42 @@ def get_city_coordinates(city_name):
from nasa_data import get_temperature_trends
# Convert dates to string format for API
- start_date_str = start_date.strftime("%Y-%m-%d")
- end_date_str = end_date.strftime("%Y-%m-%d")
+ start_date_str = start_date.strftime('%Y-%m-%d')
+ end_date_str = end_date.strftime('%Y-%m-%d')
# Status message
- st.text(
- f"Fetching temperature trends data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} from {start_date_str} to {end_date_str}..."
- )
+ st.text(f"Fetching temperature trends data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} from {start_date_str} to {end_date_str}...")
# Get temperature trends from NASA POWER API
- df, trend_per_decade = get_temperature_trends(
- latitude, longitude, start_date_str, end_date_str
- )
+ df, trend_per_decade = get_temperature_trends(latitude, longitude, start_date_str, end_date_str)
# Calculate a 12-month moving average
- df["12-Month Moving Avg"] = (
- df["Temperature (°C)"].rolling(window=12).mean()
- )
+ df['12-Month Moving Avg'] = df['Temperature (°C)'].rolling(window=12).mean()
# Calculate the trend line using linear regression
from scipy import stats
-
x = np.arange(len(df))
- slope, intercept, r_value, p_value, std_err = stats.linregress(
- x, df["Temperature (°C)"]
- )
- df["Trend"] = intercept + slope * x
+ slope, intercept, r_value, p_value, std_err = stats.linregress(x, df['Temperature (°C)'])
+ df['Trend'] = intercept + slope * x
# Create a Plotly visualization
- fig = px.line(
- df,
- x="Date",
- y="Temperature (°C)",
- title=f'Monthly Temperature Trends for {city if location_method == "City Name" else f"({latitude:.2f}, {longitude:.2f})"}',
- )
+ fig = px.line(df, x='Date', y='Temperature (°C)', title=f'Monthly Temperature Trends for {city if location_method == "City Name" else f"({latitude:.2f}, {longitude:.2f})"}')
# Add the moving average line
- fig.add_scatter(
- x=df["Date"],
- y=df["12-Month Moving Avg"],
- mode="lines",
- name="12-Month Moving Average",
- line=dict(color="red"),
- )
+ fig.add_scatter(x=df['Date'], y=df['12-Month Moving Avg'], mode='lines', name='12-Month Moving Average', line=dict(color='red'))
# Add the trend line
- fig.add_scatter(
- x=df["Date"],
- y=df["Trend"],
- mode="lines",
- name="Long-term Trend",
- line=dict(color="green", dash="dash"),
- )
+ fig.add_scatter(x=df['Date'], y=df['Trend'], mode='lines', name='Long-term Trend', line=dict(color='green', dash='dash'))
# Customize the layout
fig.update_layout(
- xaxis_title="Date",
- yaxis_title="Temperature (°C)",
- legend_title="",
- template="plotly_dark",
- plot_bgcolor="rgba(0,0,0,0)",
- paper_bgcolor="rgba(0,0,0,0)",
- font=dict(color="white"),
+ xaxis_title='Date',
+ yaxis_title='Temperature (°C)',
+ legend_title='',
+ template='plotly_dark',
+ plot_bgcolor='rgba(0,0,0,0)',
+ paper_bgcolor='rgba(0,0,0,0)',
+ font=dict(color='white')
)
# Display the chart
@@ -4081,41 +3354,24 @@ def get_city_coordinates(city_name):
insights_col1, insights_col2 = st.columns(2)
with insights_col1:
- st.metric(
- "Average Temperature",
- f"{df['Temperature (°C)'].mean():.1f}°C",
- delta=None,
- )
- st.metric(
- "Temperature Range",
- f"{df['Temperature (°C)'].min():.1f}°C to {df['Temperature (°C)'].max():.1f}°C",
- delta=None,
- )
+ st.metric("Average Temperature", f"{df['Temperature (°C)'].mean():.1f}°C", delta=None)
+ st.metric("Temperature Range", f"{df['Temperature (°C)'].min():.1f}°C to {df['Temperature (°C)'].max():.1f}°C", delta=None)
with insights_col2:
- st.metric(
- "Trend per Decade",
- f"{trend_per_decade:.2f}°C",
- delta="warming" if trend_per_decade > 0 else "cooling",
- )
- st.metric(
- "Seasonal Variation",
- f"{df['Temperature (°C)'].std():.1f}°C",
- delta=None,
- )
+ st.metric("Trend per Decade", f"{trend_per_decade:.2f}°C",
+ delta="warming" if trend_per_decade > 0 else "cooling")
+ st.metric("Seasonal Variation", f"{df['Temperature (°C)'].std():.1f}°C", delta=None)
# Add context about the data
- st.info(
- f"This chart shows simulated monthly temperature data for your selected location. The trend line indicates an overall temperature change of approximately {trend_per_decade:.2f}°C per decade. In a real implementation, this would use actual climate data from NASA POWER API or similar sources."
- )
+ st.info(f"This chart shows simulated monthly temperature data for your selected location. The trend line indicates an overall temperature change of approximately {trend_per_decade:.2f}°C per decade. In a real implementation, this would use actual climate data from NASA POWER API or similar sources.")
# Option to download the data
- csv_data = df.to_csv(index=False).encode("utf-8")
+ csv_data = df.to_csv(index=False).encode('utf-8')
st.download_button(
label="Download Temperature Data as CSV",
data=csv_data,
file_name="temperature_trends.csv",
- mime="text/csv",
+ mime="text/csv"
)
except Exception as e:
@@ -4125,23 +3381,12 @@ def get_city_coordinates(city_name):
st.subheader("Identify Extreme Heat Days in Your Area")
# Location selection
- location_method = st.radio(
- "Select location input method:",
- ["City Name", "Coordinates"],
- horizontal=True,
- key="heat_location_method",
- )
+ location_method = st.radio("Select location input method:", ["City Name", "Coordinates"], horizontal=True, key="heat_location_method")
if location_method == "City Name":
- city = st.text_input(
- "Enter city name (e.g., 'New York', 'London, UK')",
- value=(
- "Phoenix, AZ"
- if "last_city" not in st.session_state
- else st.session_state.last_city
- ),
- key="heat_city_input",
- )
+ city = st.text_input("Enter city name (e.g., 'New York', 'London, UK')",
+ value="Phoenix, AZ" if "last_city" not in st.session_state else st.session_state.last_city,
+ key="heat_city_input")
if city:
st.session_state.last_city = city
@@ -4152,55 +3397,29 @@ def get_city_coordinates(city_name):
longitude = lon
st.session_state.user_location = {"lat": latitude, "lon": longitude}
else:
- st.warning(
- "Could not find coordinates for this city. Please check the spelling or try using coordinates directly."
- )
+ st.warning("Could not find coordinates for this city. Please check the spelling or try using coordinates directly.")
latitude = st.session_state.user_location["lat"]
longitude = st.session_state.user_location["lon"]
else:
col1, col2 = st.columns(2)
with col1:
- latitude = st.number_input(
- "Latitude",
- value=st.session_state.user_location["lat"],
- min_value=-90.0,
- max_value=90.0,
- key="heat_lat_input",
- )
+ latitude = st.number_input("Latitude", value=st.session_state.user_location["lat"],
+ min_value=-90.0, max_value=90.0, key="heat_lat_input")
with col2:
- longitude = st.number_input(
- "Longitude",
- value=st.session_state.user_location["lon"],
- min_value=-180.0,
- max_value=180.0,
- key="heat_lon_input",
- )
+ longitude = st.number_input("Longitude", value=st.session_state.user_location["lon"],
+ min_value=-180.0, max_value=180.0, key="heat_lon_input")
st.session_state.user_location = {"lat": latitude, "lon": longitude}
# Parameters for extreme heat identification
col1, col2 = st.columns(2)
with col1:
- year = st.selectbox(
- "Select Year",
- list(range(datetime.now().year, datetime.now().year - 10, -1)),
- key="heat_year",
- )
+ year = st.selectbox("Select Year", list(range(datetime.now().year, datetime.now().year - 10, -1)), key="heat_year")
with col2:
- percentile = st.slider(
- "Extreme Heat Threshold (Percentile)",
- min_value=90,
- max_value=99,
- value=95,
- key="heat_percentile",
- )
+ percentile = st.slider("Extreme Heat Threshold (Percentile)", min_value=90, max_value=99, value=95, key="heat_percentile")
# Options for analysis
- analysis_type = st.radio(
- "Analysis Type",
- ["By Maximum Temperature", "By Heat Index (Temperature + Humidity)"],
- key="heat_analysis_type",
- )
+ analysis_type = st.radio("Analysis Type", ["By Maximum Temperature", "By Heat Index (Temperature + Humidity)"], key="heat_analysis_type")
if st.button("Identify Extreme Heat Days"):
with st.spinner("Analyzing temperature data to identify extreme heat days..."):
@@ -4213,100 +3432,75 @@ def get_city_coordinates(city_name):
end_date_str = f"{year}-12-31"
# Status message
- st.text(
- f"Fetching temperature data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} for year {year}..."
- )
+ st.text(f"Fetching temperature data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} for year {year}...")
# Get extreme heat days from NASA POWER API
- df, temp_threshold, hi_threshold = get_extreme_heat_days(
- latitude, longitude, year, percentile
- )
+ df, temp_threshold, hi_threshold = get_extreme_heat_days(latitude, longitude, year, percentile)
# Select which value to analyze based on user selection
if analysis_type == "By Heat Index (Temperature + Humidity)":
# Determine extreme heat days based on heat index
- df["Is Extreme Heat"] = df["Heat Index (°C)"] > hi_threshold
+ df['Is Extreme Heat'] = df['Heat Index (°C)'] > hi_threshold
# Value to analyze
- analysis_value = "Heat Index (°C)"
+ analysis_value = 'Heat Index (°C)'
threshold = hi_threshold
else: # By Maximum Temperature
# Determine extreme heat days based on temperature
- df["Is Extreme Heat"] = df["T2M_MAX"] > temp_threshold
+ df['Is Extreme Heat'] = df['T2M_MAX'] > temp_threshold
# Value to analyze
- analysis_value = "T2M_MAX"
+ analysis_value = 'T2M_MAX'
threshold = temp_threshold
# Rename temperature column for display
- df = df.rename(columns={"T2M_MAX": "Temperature (°C)"})
+ df = df.rename(columns={'T2M_MAX': 'Temperature (°C)'})
# Filter to extreme heat days
- extreme_days = df[df["Is Extreme Heat"]].copy()
+ extreme_days = df[df['Is Extreme Heat']].copy()
# Display the results
- st.subheader(
- f"Extreme Heat Days in {year} (Above {percentile}th Percentile)"
- )
+ st.subheader(f"Extreme Heat Days in {year} (Above {percentile}th Percentile)")
# Show the threshold
- st.info(
- f"Threshold value: {threshold:.1f}°C {analysis_value.split(' ')[0]}"
- )
+ st.info(f"Threshold value: {threshold:.1f}°C {analysis_value.split(' ')[0]}")
# Create calendar heatmap
- fig = px.scatter(
- df,
- x=df["Date"].dt.month,
- y=df["Date"].dt.day,
- color=df[analysis_value],
- color_continuous_scale="Turbo", # Red-hot color scale
- title=f"Heat Calendar for {year}",
- labels={"x": "Month", "y": "Day", "color": analysis_value},
- size_max=10,
- height=400,
- )
+ fig = px.scatter(df, x=df['Date'].dt.month, y=df['Date'].dt.day,
+ color=df[analysis_value],
+ color_continuous_scale='Turbo', # Red-hot color scale
+ title=f"Heat Calendar for {year}",
+ labels={'x': 'Month', 'y': 'Day', 'color': analysis_value},
+ size_max=10,
+ height=400)
# Add custom shapes for extreme heat days
for idx, row in extreme_days.iterrows():
- month = row["Date"].month
- day = row["Date"].day
+ month = row['Date'].month
+ day = row['Date'].day
fig.add_shape(
type="circle",
- x0=month - 0.3,
- y0=day - 0.3,
- x1=month + 0.3,
- y1=day + 0.3,
+ x0=month - 0.3, y0=day - 0.3,
+ x1=month + 0.3, y1=day + 0.3,
line=dict(color="red", width=2),
- fillcolor="rgba(255,0,0,0)",
+ fillcolor="rgba(255,0,0,0)"
)
# Customize the layout
fig.update_layout(
xaxis=dict(
- tickmode="array",
+ tickmode='array',
tickvals=list(range(1, 13)),
- ticktext=[
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec",
- ],
+ ticktext=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
),
- yaxis=dict(autorange="reversed"), # To have day 1 at the top
- template="plotly_dark",
- plot_bgcolor="rgba(0,0,0,0)",
- paper_bgcolor="rgba(0,0,0,0)",
- font=dict(color="white"),
+ yaxis=dict(
+ autorange="reversed" # To have day 1 at the top
+ ),
+ template='plotly_dark',
+ plot_bgcolor='rgba(0,0,0,0)',
+ paper_bgcolor='rgba(0,0,0,0)',
+ font=dict(color='white')
)
st.plotly_chart(fig, use_container_width=True)
@@ -4316,30 +3510,20 @@ def get_city_coordinates(city_name):
col1, col2, col3 = st.columns(3)
with col1:
- st.metric(
- "Total Extreme Heat Days", f"{len(extreme_days)}", delta=None
- )
+ st.metric("Total Extreme Heat Days", f"{len(extreme_days)}", delta=None)
with col2:
avg_extreme = extreme_days[analysis_value].mean()
- st.metric(
- "Average " + analysis_value, f"{avg_extreme:.1f}°C", delta=None
- )
+ st.metric("Average " + analysis_value, f"{avg_extreme:.1f}°C", delta=None)
with col3:
max_extreme = extreme_days[analysis_value].max()
- max_date = extreme_days.loc[
- extreme_days[analysis_value].idxmax(), "Date"
- ].strftime("%b %d")
- st.metric(
- "Maximum " + analysis_value,
- f"{max_extreme:.1f}°C on {max_date}",
- delta=None,
- )
+ max_date = extreme_days.loc[extreme_days[analysis_value].idxmax(), 'Date'].strftime('%b %d')
+ st.metric("Maximum " + analysis_value, f"{max_extreme:.1f}°C on {max_date}", delta=None)
# Display extreme days data table
st.subheader("List of Extreme Heat Days")
# Format the table for display
display_df = extreme_days.copy()
- display_df["Date"] = display_df["Date"].dt.strftime("%b %d, %Y")
+ display_df['Date'] = display_df['Date'].dt.strftime('%b %d, %Y')
# Round numeric columns to 1 decimal place
numeric_cols = display_df.select_dtypes(include=[np.number]).columns
display_df[numeric_cols] = display_df[numeric_cols].round(1)
@@ -4351,18 +3535,16 @@ def get_city_coordinates(city_name):
st.dataframe(display_df)
# Option to download the data
- csv_data = display_df.to_csv(index=False).encode("utf-8")
+ csv_data = display_df.to_csv(index=False).encode('utf-8')
st.download_button(
label="Download Extreme Heat Days Data as CSV",
data=csv_data,
file_name="extreme_heat_days.csv",
- mime="text/csv",
+ mime="text/csv"
)
# Add context about the data
- st.info(
- f"This analysis shows simulated extreme heat days for your selected location. In a real implementation, this would use actual climate data from NASA POWER API or similar sources, and could include more sophisticated heat metrics like wet-bulb temperature for heat stress analysis."
- )
+ st.info(f"This analysis shows simulated extreme heat days for your selected location. In a real implementation, this would use actual climate data from NASA POWER API or similar sources, and could include more sophisticated heat metrics like wet-bulb temperature for heat stress analysis.")
except Exception as e:
st.error(f"Error identifying extreme heat days: {str(e)}")
@@ -4371,23 +3553,12 @@ def get_city_coordinates(city_name):
st.subheader("Compare Rainfall: This Season vs. Last Year")
# Location selection
- location_method = st.radio(
- "Select location input method:",
- ["City Name", "Coordinates"],
- horizontal=True,
- key="rain_location_method",
- )
+ location_method = st.radio("Select location input method:", ["City Name", "Coordinates"], horizontal=True, key="rain_location_method")
if location_method == "City Name":
- city = st.text_input(
- "Enter city name (e.g., 'New York', 'London, UK')",
- value=(
- "Seattle, WA"
- if "last_city" not in st.session_state
- else st.session_state.last_city
- ),
- key="rain_city_input",
- )
+ city = st.text_input("Enter city name (e.g., 'New York', 'London, UK')",
+ value="Seattle, WA" if "last_city" not in st.session_state else st.session_state.last_city,
+ key="rain_city_input")
if city:
st.session_state.last_city = city
@@ -4398,29 +3569,17 @@ def get_city_coordinates(city_name):
longitude = lon
st.session_state.user_location = {"lat": latitude, "lon": longitude}
else:
- st.warning(
- "Could not find coordinates for this city. Please check the spelling or try using coordinates directly."
- )
+ st.warning("Could not find coordinates for this city. Please check the spelling or try using coordinates directly.")
latitude = st.session_state.user_location["lat"]
longitude = st.session_state.user_location["lon"]
else:
col1, col2 = st.columns(2)
with col1:
- latitude = st.number_input(
- "Latitude",
- value=st.session_state.user_location["lat"],
- min_value=-90.0,
- max_value=90.0,
- key="rain_lat_input",
- )
+ latitude = st.number_input("Latitude", value=st.session_state.user_location["lat"],
+ min_value=-90.0, max_value=90.0, key="rain_lat_input")
with col2:
- longitude = st.number_input(
- "Longitude",
- value=st.session_state.user_location["lon"],
- min_value=-180.0,
- max_value=180.0,
- key="rain_lon_input",
- )
+ longitude = st.number_input("Longitude", value=st.session_state.user_location["lon"],
+ min_value=-180.0, max_value=180.0, key="rain_lon_input")
st.session_state.user_location = {"lat": latitude, "lon": longitude}
@@ -4428,28 +3587,17 @@ def get_city_coordinates(city_name):
current_month = datetime.now().month
# Approximate seasons (adjust as needed for your application)
season_mapping = {
- 12: "Winter",
- 1: "Winter",
- 2: "Winter",
- 3: "Spring",
- 4: "Spring",
- 5: "Spring",
- 6: "Summer",
- 7: "Summer",
- 8: "Summer",
- 9: "Fall",
- 10: "Fall",
- 11: "Fall",
+ 12: "Winter", 1: "Winter", 2: "Winter",
+ 3: "Spring", 4: "Spring", 5: "Spring",
+ 6: "Summer", 7: "Summer", 8: "Summer",
+ 9: "Fall", 10: "Fall", 11: "Fall"
}
current_season = season_mapping[current_month]
# Allow user to select a different season
- season = st.selectbox(
- "Select Season to Compare",
- ["Winter", "Spring", "Summer", "Fall"],
- index=list(["Winter", "Spring", "Summer", "Fall"]).index(current_season),
- key="rain_season",
- )
+ season = st.selectbox("Select Season to Compare", ["Winter", "Spring", "Summer", "Fall"],
+ index=list(["Winter", "Spring", "Summer", "Fall"]).index(current_season),
+ key="rain_season")
# Define the current year and last year
current_year = datetime.now().year
@@ -4462,30 +3610,10 @@ def get_city_coordinates(city_name):
# Define season date ranges for current and previous year
season_dates = {
- "Winter": {
- "start_month": 12,
- "start_day": 1,
- "end_month": 2,
- "end_day": 28,
- },
- "Spring": {
- "start_month": 3,
- "start_day": 1,
- "end_month": 5,
- "end_day": 31,
- },
- "Summer": {
- "start_month": 6,
- "start_day": 1,
- "end_month": 8,
- "end_day": 31,
- },
- "Fall": {
- "start_month": 9,
- "start_day": 1,
- "end_month": 11,
- "end_day": 30,
- },
+ "Winter": {"start_month": 12, "start_day": 1, "end_month": 2, "end_day": 28},
+ "Spring": {"start_month": 3, "start_day": 1, "end_month": 5, "end_day": 31},
+ "Summer": {"start_month": 6, "start_day": 1, "end_month": 8, "end_day": 31},
+ "Fall": {"start_month": 9, "start_day": 1, "end_month": 11, "end_day": 30}
}
# Handle the case where winter spans across years
@@ -4524,9 +3652,7 @@ def get_city_coordinates(city_name):
prev_end = datetime(current_year - 1, end_month, end_day)
elif current_month < start_month:
# Season hasn't started yet, so "current" is last year
- current_start = datetime(
- current_year - 1, start_month, start_day
- )
+ current_start = datetime(current_year - 1, start_month, start_day)
current_end = datetime(current_year - 1, end_month, end_day)
prev_start = datetime(current_year - 2, start_month, start_day)
prev_end = datetime(current_year - 2, end_month, end_day)
@@ -4538,15 +3664,13 @@ def get_city_coordinates(city_name):
prev_end = datetime(current_year - 1, end_month, end_day)
# Convert dates to string format for API
- current_start_str = current_start.strftime("%Y-%m-%d")
- current_end_str = current_end.strftime("%Y-%m-%d")
- prev_start_str = prev_start.strftime("%Y-%m-%d")
- prev_end_str = prev_end.strftime("%Y-%m-%d")
+ current_start_str = current_start.strftime('%Y-%m-%d')
+ current_end_str = current_end.strftime('%Y-%m-%d')
+ prev_start_str = prev_start.strftime('%Y-%m-%d')
+ prev_end_str = prev_end.strftime('%Y-%m-%d')
# Status message
- st.text(
- f"Fetching precipitation data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} for {season} season..."
- )
+ st.text(f"Fetching precipitation data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} for {season} season...")
# Get rainfall comparison from NASA POWER API
current_df, prev_df = get_rainfall_comparison(
@@ -4555,49 +3679,41 @@ def get_city_coordinates(city_name):
current_start_str,
current_end_str,
prev_start_str,
- prev_end_str,
+ prev_end_str
)
# Combine the data
combined_df = pd.concat([current_df, prev_df])
# Calculate cumulative precipitation
- current_cumulative = current_df["Precipitation (mm)"].cumsum()
- prev_cumulative = prev_df["Precipitation (mm)"].cumsum()
+ current_cumulative = current_df['Precipitation (mm)'].cumsum()
+ prev_cumulative = prev_df['Precipitation (mm)'].cumsum()
# Calculate statistics
- current_total = current_df["Precipitation (mm)"].sum()
- prev_total = prev_df["Precipitation (mm)"].sum()
- current_days_with_rain = len(
- current_df[current_df["Precipitation (mm)"] > 0]
- )
- prev_days_with_rain = len(prev_df[prev_df["Precipitation (mm)"] > 0])
+ current_total = current_df['Precipitation (mm)'].sum()
+ prev_total = prev_df['Precipitation (mm)'].sum()
+ current_days_with_rain = len(current_df[current_df['Precipitation (mm)'] > 0])
+ prev_days_with_rain = len(prev_df[prev_df['Precipitation (mm)'] > 0])
# Normalize the dates to display them on the same x-axis (days from start of season)
- current_df["Day of Season"] = range(len(current_df))
- prev_df["Day of Season"] = range(len(prev_df))
+ current_df['Day of Season'] = range(len(current_df))
+ prev_df['Day of Season'] = range(len(prev_df))
# Create the comparison plots
# 1. Daily precipitation comparison
- fig1 = px.bar(
- combined_df,
- x="Date",
- y="Precipitation (mm)",
- color="Year",
- barmode="group",
- title=f"{season} Daily Precipitation Comparison",
- color_discrete_map={"This Year": "#1E90FF", "Last Year": "#9370DB"},
- )
+ fig1 = px.bar(combined_df, x='Date', y='Precipitation (mm)', color='Year',
+ barmode='group', title=f"{season} Daily Precipitation Comparison",
+ color_discrete_map={'This Year': '#1E90FF', 'Last Year': '#9370DB'})
fig1.update_layout(
- xaxis_title="Date",
- yaxis_title="Precipitation (mm)",
- legend_title="",
- template="plotly_dark",
- plot_bgcolor="rgba(0,0,0,0)",
- paper_bgcolor="rgba(0,0,0,0)",
- font=dict(color="white"),
+ xaxis_title='Date',
+ yaxis_title='Precipitation (mm)',
+ legend_title='',
+ template='plotly_dark',
+ plot_bgcolor='rgba(0,0,0,0)',
+ paper_bgcolor='rgba(0,0,0,0)',
+ font=dict(color='white')
)
st.plotly_chart(fig1, use_container_width=True)
@@ -4606,37 +3722,33 @@ def get_city_coordinates(city_name):
fig2 = go.Figure()
# Add current year line
- fig2.add_trace(
- go.Scatter(
- x=current_df["Day of Season"],
- y=current_cumulative,
- mode="lines",
- name="This Year",
- line=dict(color="#1E90FF", width=3),
- )
- )
+ fig2.add_trace(go.Scatter(
+ x=current_df['Day of Season'],
+ y=current_cumulative,
+ mode='lines',
+ name='This Year',
+ line=dict(color='#1E90FF', width=3)
+ ))
# Add previous year line
- fig2.add_trace(
- go.Scatter(
- x=prev_df["Day of Season"],
- y=prev_cumulative,
- mode="lines",
- name="Last Year",
- line=dict(color="#9370DB", width=3),
- )
- )
+ fig2.add_trace(go.Scatter(
+ x=prev_df['Day of Season'],
+ y=prev_cumulative,
+ mode='lines',
+ name='Last Year',
+ line=dict(color='#9370DB', width=3)
+ ))
# Update layout
fig2.update_layout(
title=f"{season} Cumulative Precipitation Comparison",
- xaxis_title="Days from Start of Season",
- yaxis_title="Cumulative Precipitation (mm)",
- legend_title="",
- template="plotly_dark",
- plot_bgcolor="rgba(0,0,0,0)",
- paper_bgcolor="rgba(0,0,0,0)",
- font=dict(color="white"),
+ xaxis_title='Days from Start of Season',
+ yaxis_title='Cumulative Precipitation (mm)',
+ legend_title='',
+ template='plotly_dark',
+ plot_bgcolor='rgba(0,0,0,0)',
+ paper_bgcolor='rgba(0,0,0,0)',
+ font=dict(color='white')
)
st.plotly_chart(fig2, use_container_width=True)
@@ -4647,51 +3759,35 @@ def get_city_coordinates(city_name):
col1, col2, col3 = st.columns(3)
with col1:
- percent_change = (
- ((current_total - prev_total) / prev_total * 100)
- if prev_total > 0
- else 0
- )
- st.metric(
- "Total Precipitation",
- f"{current_total:.1f} mm",
- delta=f"{percent_change:.1f}% vs last year",
- )
+ percent_change = ((current_total - prev_total) / prev_total * 100) if prev_total > 0 else 0
+ st.metric("Total Precipitation",
+ f"{current_total:.1f} mm",
+ delta=f"{percent_change:.1f}% vs last year")
with col2:
- st.metric(
- "Days with Rain",
- f"{current_days_with_rain}",
- delta=f"{current_days_with_rain - prev_days_with_rain} days vs last year",
- )
+ st.metric("Days with Rain",
+ f"{current_days_with_rain}",
+ delta=f"{current_days_with_rain - prev_days_with_rain} days vs last year")
with col3:
current_avg = current_total / max(1, len(current_df))
prev_avg = prev_total / max(1, len(prev_df))
- avg_percent_change = (
- ((current_avg - prev_avg) / prev_avg * 100)
- if prev_avg > 0
- else 0
- )
- st.metric(
- "Avg. Daily Precipitation",
- f"{current_avg:.1f} mm",
- delta=f"{avg_percent_change:.1f}% vs last year",
- )
+ avg_percent_change = ((current_avg - prev_avg) / prev_avg * 100) if prev_avg > 0 else 0
+ st.metric("Avg. Daily Precipitation",
+ f"{current_avg:.1f} mm",
+ delta=f"{avg_percent_change:.1f}% vs last year")
# Context about the data
comparison_result = "wetter" if current_total > prev_total else "drier"
- st.info(
- f"Based on NASA POWER climate data, the {season.lower()} season this year is {comparison_result} than last year. This analysis uses real precipitation data for your selected location."
- )
+ st.info(f"Based on NASA POWER climate data, the {season.lower()} season this year is {comparison_result} than last year. This analysis uses real precipitation data for your selected location.")
# Option to download the data
- csv_data = combined_df.to_csv(index=False).encode("utf-8")
+ csv_data = combined_df.to_csv(index=False).encode('utf-8')
st.download_button(
label="Download Rainfall Comparison Data as CSV",
data=csv_data,
file_name="rainfall_comparison.csv",
- mime="text/csv",
+ mime="text/csv"
)
except Exception as e:
@@ -4701,23 +3797,12 @@ def get_city_coordinates(city_name):
st.subheader("Export Climate Anomalies as a Table")
# Location selection
- location_method = st.radio(
- "Select location input method:",
- ["City Name", "Coordinates"],
- horizontal=True,
- key="anomaly_location_method",
- )
+ location_method = st.radio("Select location input method:", ["City Name", "Coordinates"], horizontal=True, key="anomaly_location_method")
if location_method == "City Name":
- city = st.text_input(
- "Enter city name (e.g., 'New York', 'London, UK')",
- value=(
- "Boulder, CO"
- if "last_city" not in st.session_state
- else st.session_state.last_city
- ),
- key="anomaly_city_input",
- )
+ city = st.text_input("Enter city name (e.g., 'New York', 'London, UK')",
+ value="Boulder, CO" if "last_city" not in st.session_state else st.session_state.last_city,
+ key="anomaly_city_input")
if city:
st.session_state.last_city = city
@@ -4728,40 +3813,26 @@ def get_city_coordinates(city_name):
longitude = lon
st.session_state.user_location = {"lat": latitude, "lon": longitude}
else:
- st.warning(
- "Could not find coordinates for this city. Please check the spelling or try using coordinates directly."
- )
+ st.warning("Could not find coordinates for this city. Please check the spelling or try using coordinates directly.")
latitude = st.session_state.user_location["lat"]
longitude = st.session_state.user_location["lon"]
else:
col1, col2 = st.columns(2)
with col1:
- latitude = st.number_input(
- "Latitude",
- value=st.session_state.user_location["lat"],
- min_value=-90.0,
- max_value=90.0,
- key="anomaly_lat_input",
- )
+ latitude = st.number_input("Latitude", value=st.session_state.user_location["lat"],
+ min_value=-90.0, max_value=90.0, key="anomaly_lat_input")
with col2:
- longitude = st.number_input(
- "Longitude",
- value=st.session_state.user_location["lon"],
- min_value=-180.0,
- max_value=180.0,
- key="anomaly_lon_input",
- )
+ longitude = st.number_input("Longitude", value=st.session_state.user_location["lon"],
+ min_value=-180.0, max_value=180.0, key="anomaly_lon_input")
st.session_state.user_location = {"lat": latitude, "lon": longitude}
# Date range selection
col1, col2, col3 = st.columns(3)
with col1:
- selected_period = st.selectbox(
- "Time Period",
- ["Last 5 Years", "Last 10 Years", "Last 30 Years", "Custom Range"],
- key="anomaly_period",
- )
+ selected_period = st.selectbox("Time Period",
+ ["Last 5 Years", "Last 10 Years", "Last 30 Years", "Custom Range"],
+ key="anomaly_period")
# Set the date range based on the selected period
end_date = datetime.now()
@@ -4774,27 +3845,23 @@ def get_city_coordinates(city_name):
start_date = datetime(end_date.year - 30, 1, 1)
else: # Custom Range
with col2:
- start_date = st.date_input(
- "Start Date",
- datetime(end_date.year - 10, 1, 1),
- key="anomaly_start_date",
- )
+ start_date = st.date_input("Start Date",
+ datetime(end_date.year - 10, 1, 1),
+ key="anomaly_start_date")
with col3:
- end_date = st.date_input("End Date", end_date, key="anomaly_end_date")
+ end_date = st.date_input("End Date",
+ end_date,
+ key="anomaly_end_date")
# Variable selection
- variable = st.selectbox(
- "Climate Variable",
- ["Temperature", "Precipitation", "Humidity", "Wind Speed"],
- key="anomaly_variable",
- )
+ variable = st.selectbox("Climate Variable",
+ ["Temperature", "Precipitation", "Humidity", "Wind Speed"],
+ key="anomaly_variable")
# Baseline selection
- baseline_period = st.selectbox(
- "Baseline Period",
- ["1951-1980", "1971-2000", "1981-2010", "1991-2020"],
- key="anomaly_baseline",
- )
+ baseline_period = st.selectbox("Baseline Period",
+ ["1951-1980", "1971-2000", "1981-2010", "1991-2020"],
+ key="anomaly_baseline")
# Calculate button
if st.button("Calculate and Export Anomalies"):
@@ -4804,13 +3871,11 @@ def get_city_coordinates(city_name):
from nasa_data import calculate_climate_anomalies
# Convert dates to string format for API
- start_date_str = start_date.strftime("%Y-%m-%d")
- end_date_str = end_date.strftime("%Y-%m-%d")
+ start_date_str = start_date.strftime('%Y-%m-%d')
+ end_date_str = end_date.strftime('%Y-%m-%d')
# Status message
- st.text(
- f"Fetching climate data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} for {variable.lower()}..."
- )
+ st.text(f"Fetching climate data for {city if location_method == 'City Name' else f'({latitude:.2f}, {longitude:.2f})'} for {variable.lower()}...")
# Get climate anomalies data from NASA POWER API
df = calculate_climate_anomalies(
@@ -4819,7 +3884,7 @@ def get_city_coordinates(city_name):
start_date_str,
end_date_str,
variable.lower(),
- baseline_period,
+ baseline_period
)
# Display the anomalies table
@@ -4827,91 +3892,76 @@ def get_city_coordinates(city_name):
# Format the dataframe for display
display_df = df.copy()
- display_df["Date"] = display_df["Date"].dt.strftime("%b %Y")
+ display_df['Date'] = display_df['Date'].dt.strftime('%b %Y')
# Round values for display
- value_cols = [
- col
- for col in display_df.columns
- if col not in ["Date", "Year", "Month", "Anomaly", "Anomaly Unit"]
- ]
+ value_cols = [col for col in display_df.columns if col not in ['Date', 'Year', 'Month', 'Anomaly', 'Anomaly Unit']]
if len(value_cols) > 0:
for col in value_cols:
display_df[col] = display_df[col].round(1)
# Round anomaly values
- display_df["Anomaly"] = display_df["Anomaly"].round(1)
+ display_df['Anomaly'] = display_df['Anomaly'].round(1)
# Create a color-coded dataframe for the anomalies
st.dataframe(
display_df,
column_config={
- "Anomaly": st.column_config.NumberColumn(
+ 'Anomaly': st.column_config.NumberColumn(
f"{variable} Anomaly ({display_df['Anomaly Unit'].iloc[0]})",
- format="%.1f"
- + (" °C" if variable == "Temperature" else " %"),
+ format="%.1f" + (" °C" if variable == "Temperature" else " %"),
help=f"Difference from {baseline_period} baseline",
)
},
- hide_index=True,
+ hide_index=True
)
# Create visualization of anomalies
if variable == "Temperature":
# Color mapping for temperature anomalies
- colors = [
- (
- "blue"
- if a < -1
- else "lightblue" if a < 0 else "salmon" if a < 1 else "red"
- )
- for a in df["Anomaly"]
- ]
+ colors = ['blue' if a < -1 else 'lightblue' if a < 0
+ else 'salmon' if a < 1 else 'red' for a in df['Anomaly']]
# Create plot
fig = px.bar(
df,
- x="Date",
- y="Anomaly",
+ x='Date',
+ y='Anomaly',
title=f"Monthly Temperature Anomalies Relative to {baseline_period}",
- labels={"Anomaly": "Temperature Anomaly (°C)", "Date": ""},
- color="Anomaly",
- color_continuous_scale="RdBu_r",
+ labels={'Anomaly': 'Temperature Anomaly (°C)', 'Date': ''},
+ color='Anomaly',
+ color_continuous_scale='RdBu_r'
)
else:
# For non-temperature variables, use a diverging color scale centered at 0
fig = px.bar(
df,
- x="Date",
- y="Anomaly",
+ x='Date',
+ y='Anomaly',
title=f"Monthly {variable} Anomalies Relative to {baseline_period}",
- labels={"Anomaly": f"{variable} Anomaly (%)", "Date": ""},
- color="Anomaly",
- color_continuous_scale="RdBu",
+ labels={'Anomaly': f'{variable} Anomaly (%)', 'Date': ''},
+ color='Anomaly',
+ color_continuous_scale='RdBu'
)
# Layout customization
fig.update_layout(
xaxis=dict(
- tickmode="array",
- tickvals=df["Date"][::12], # Show tick every 12 months
- ticktext=[d.strftime("%Y") for d in df["Date"][::12]],
+ tickmode='array',
+ tickvals=df['Date'][::12], # Show tick every 12 months
+ ticktext=[d.strftime('%Y') for d in df['Date'][::12]]
),
- template="plotly_dark",
- plot_bgcolor="rgba(0,0,0,0)",
- paper_bgcolor="rgba(0,0,0,0)",
- font=dict(color="white"),
+ template='plotly_dark',
+ plot_bgcolor='rgba(0,0,0,0)',
+ paper_bgcolor='rgba(0,0,0,0)',
+ font=dict(color='white')
)
st.plotly_chart(fig, use_container_width=True)
# Calculate some statistics about the anomalies
- mean_anomaly = df["Anomaly"].mean()
- trend_per_decade = (
- df["Anomaly"].iloc[-60:].mean() - df["Anomaly"].iloc[:60].mean()
- if len(df) > 120
- else np.nan
- )
+ mean_anomaly = df['Anomaly'].mean()
+ trend_per_decade = df['Anomaly'].iloc[-60:].mean() - df['Anomaly'].iloc[:60].mean() if len(df) > 120 else np.nan
# Display statistics
st.subheader("Anomaly Statistics")
@@ -4919,91 +3969,54 @@ def get_city_coordinates(city_name):
col1, col2, col3 = st.columns(3)
with col1:
if variable == "Temperature":
- st.metric(
- "Mean Anomaly",
- f"{mean_anomaly:.2f} °C",
- delta=(
- f"{mean_anomaly:.2f} °C" if mean_anomaly != 0 else None
- ),
- )
+ st.metric("Mean Anomaly", f"{mean_anomaly:.2f} °C",
+ delta=f"{mean_anomaly:.2f} °C" if mean_anomaly != 0 else None)
else:
- st.metric(
- "Mean Anomaly",
- f"{mean_anomaly:.1f}%",
- delta=f"{mean_anomaly:.1f}%" if mean_anomaly != 0 else None,
- )
+ st.metric("Mean Anomaly", f"{mean_anomaly:.1f}%",
+ delta=f"{mean_anomaly:.1f}%" if mean_anomaly != 0 else None)
with col2:
if not np.isnan(trend_per_decade):
if variable == "Temperature":
- st.metric(
- "Recent Trend (per decade)",
- f"{trend_per_decade:.2f} °C",
- delta=(
- f"{trend_per_decade:.2f} °C"
- if trend_per_decade != 0
- else None
- ),
- )
+ st.metric("Recent Trend (per decade)", f"{trend_per_decade:.2f} °C",
+ delta=f"{trend_per_decade:.2f} °C" if trend_per_decade != 0 else None)
else:
- st.metric(
- "Recent Trend (per decade)",
- f"{trend_per_decade:.1f}%",
- delta=(
- f"{trend_per_decade:.1f}%"
- if trend_per_decade != 0
- else None
- ),
- )
+ st.metric("Recent Trend (per decade)", f"{trend_per_decade:.1f}%",
+ delta=f"{trend_per_decade:.1f}%" if trend_per_decade != 0 else None)
with col3:
- extreme_anomalies = len(
- df[
- abs(df["Anomaly"])
- > (2 if variable == "Temperature" else 50)
- ]
- )
- st.metric("Extreme Anomalies", f"{extreme_anomalies}", delta=None)
+ extreme_anomalies = len(df[abs(df['Anomaly']) > (2 if variable == "Temperature" else 50)])
+ st.metric("Extreme Anomalies", f"{extreme_anomalies}",
+ delta=None)
# Allow downloading the data
- csv = df.to_csv(index=False).encode("utf-8")
+ csv = df.to_csv(index=False).encode('utf-8')
st.download_button(
label=f"Download {variable} Anomalies as CSV",
data=csv,
file_name=f"{variable.lower()}_anomalies_{baseline_period}.csv",
- mime="text/csv",
+ mime="text/csv"
)
# Add Excel export option
excel_buffer = io.BytesIO()
- with pd.ExcelWriter(excel_buffer, engine="xlsxwriter") as writer:
- df.to_excel(writer, sheet_name="Anomalies", index=False)
+ with pd.ExcelWriter(excel_buffer, engine='xlsxwriter') as writer:
+ df.to_excel(writer, sheet_name='Anomalies', index=False)
# Add a summary sheet
summary_data = {
- "Statistic": [
- "Mean Anomaly",
- "Trend per Decade",
- "Extreme Anomalies",
- "Baseline Period",
- "Data Period",
- ],
- "Value": [
+ 'Statistic': ['Mean Anomaly', 'Trend per Decade', 'Extreme Anomalies',
+ 'Baseline Period', 'Data Period'],
+ 'Value': [
f"{mean_anomaly:.2f} {display_df['Anomaly Unit'].iloc[0]}",
- (
- f"{trend_per_decade:.2f} {display_df['Anomaly Unit'].iloc[0]} per decade"
- if not np.isnan(trend_per_decade)
- else "N/A"
- ),
+ f"{trend_per_decade:.2f} {display_df['Anomaly Unit'].iloc[0]} per decade" if not np.isnan(trend_per_decade) else "N/A",
str(extreme_anomalies),
baseline_period,
- f"{start_date.strftime('%b %Y')} to {end_date.strftime('%b %Y')}",
- ],
+ f"{start_date.strftime('%b %Y')} to {end_date.strftime('%b %Y')}"
+ ]
}
- pd.DataFrame(summary_data).to_excel(
- writer, sheet_name="Summary", index=False
- )
+ pd.DataFrame(summary_data).to_excel(writer, sheet_name='Summary', index=False)
excel_data = excel_buffer.getvalue()
@@ -5011,13 +4024,11 @@ def get_city_coordinates(city_name):
label=f"Download {variable} Anomalies as Excel",
data=excel_data,
file_name=f"{variable.lower()}_anomalies_{baseline_period}.xlsx",
- mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
# Add context about the data
- st.info(
- f"This chart shows {variable.lower()} anomalies for your selected location relative to a {baseline_period} baseline using NASA POWER climate data. Positive anomalies indicate values above the baseline, while negative anomalies indicate values below the baseline."
- )
+ st.info(f"This chart shows {variable.lower()} anomalies for your selected location relative to a {baseline_period} baseline using NASA POWER climate data. Positive anomalies indicate values above the baseline, while negative anomalies indicate values below the baseline.")
except Exception as e:
st.error(f"Error calculating climate anomalies: {str(e)}")
From 951a0c9637139c1f3b29a9caac1be2a8685c8d60 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Sat, 31 Jan 2026 02:42:28 +0000
Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Add=20accessibili?=
=?UTF-8?q?ty=20label=20to=20chat=20input=20(Conflict=20Resolved=20v2)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Added semantic label "Message CeCe" to chat input with `label_visibility="collapsed"`.
- Manually merged upstream changes for `satellite_homepage` launch button styling to resolve conflicts.
- Updated `.Jules/palette.md` with accessibility learning.
This resolves the merge conflict with `main` by incorporating the new CSS for `.launch-button-container` while preserving the accessibility fix.
Co-authored-by: cmonteverde <83616016+cmonteverde@users.noreply.github.com>
---
app.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/app.py b/app.py
index 186ed13..e9f4aa0 100644
--- a/app.py
+++ b/app.py
@@ -488,9 +488,17 @@
# Show satellite homepage
map_data = satellite_homepage.create_satellite_homepage()
- # Prominent Launch CTA button styled over the blurred preview
+ # Prominent Launch CTA button positioned in the CENTER of the blurred preview
st.markdown("""