import streamlit as st import requests import json import pandas as pd import folium from streamlit_folium import st_folium import plotly.graph_objects as go import numpy as np from datetime import datetime # Set page layout to wide st.set_page_config(layout="wide", page_title="Real-Time Temperature Data Dashboard") # Function to fetch JSON data with caching and expiration @st.cache_data(ttl=300) # Cache data for 5 minutes (300 seconds) def fetch_data(): url = 'https://csdi.vercel.app/weather/temp' response = requests.get(url) return json.loads(response.text) # Fetch the JSON data data = fetch_data() # Create a Pandas DataFrame from the JSON data features = data['features'] df = pd.json_normalize(features) # Rename columns for easier access df.rename(columns={ 'properties.Automatic Weather Station': 'Station', 'properties.Air Temperature(degree Celsius)': 'Temperature', 'geometry.coordinates': 'Coordinates' }, inplace=True) # Split Coordinates into separate Longitude and Latitude columns df[['Longitude', 'Latitude']] = pd.DataFrame(df['Coordinates'].tolist(), index=df.index) # Extract temperature data temps = df['Temperature'].dropna().tolist() # Create three columns col1, col2, col3 = st.columns([1.65, 2, 1.15]) # Column 1: Histogram and statistics with two-sigma analysis with col1: # Row 1: Histogram with st.container(): # Convert list to pandas Series temps_series = pd.Series(temps) # Calculate histogram data hist_data = np.histogram(temps_series, bins=10) bin_edges = hist_data[1] counts = hist_data[0] # Create a color gradient from blue to red def get_color(value, min_value, max_value): ratio = (value - min_value) / (max_value - min_value) r = int(255 * ratio) # Red component b = int(255 * (1 - ratio)) # Blue component return f'rgb({r}, 0, {b})' # Create histogram with Plotly Graph Objects fig = go.Figure() # Add histogram bars with gradient colors for i in range(len(bin_edges) - 1): bin_center = (bin_edges[i] + bin_edges[i + 1]) / 2 color = get_color(bin_center, bin_edges.min(), bin_edges.max()) fig.add_trace(go.Bar( x=[f'{bin_edges[i]:.1f} - {bin_edges[i + 1]:.1f}'], y=[counts[i]], marker_color=color, name=f'{bin_edges[i]:.1f} - {bin_edges[i + 1]:.1f}' )) # Customize layout fig.update_layout( xaxis_title='Temperature (°C)', yaxis_title='Count', title='Temperature Distribution', bargap=0.2, # Adjust gap between bars title_font_size=20, xaxis_title_font_size=14, yaxis_title_font_size=14, height=350, # Set plot height xaxis=dict(title_font_size=14), yaxis=dict(title_font_size=14) ) # Display the plot in Streamlit st.plotly_chart(fig, use_container_width=True) # Row 2: Statistics with st.container(): col_1, col_2 = st.columns([1, 1]) with col_1: if temps: avg_temp = np.mean(temps) std_temp = np.std(temps) max_temp = np.max(temps) min_temp = np.min(temps) two_sigma_range = (avg_temp - 2 * std_temp, avg_temp + 2 * std_temp) st.metric(label="Average Temperature (°C)", value=f"{avg_temp:.2f}") st.metric(label="Minimum Temperature (°C)", value=f"{min_temp:.2f}") with col_2: st.metric(label="Maximum Temperature (°C)", value=f"{max_temp:.2f}") st.metric(label="Std. Dev (°C)", value=f"{std_temp:.2f}") # Column 2: Map def temperature_to_color(temp, min_temp, max_temp): """Convert temperature to a color based on the gradient from blue (low) to red (high).""" norm_temp = (temp - min_temp) / (max_temp - min_temp) red = int(255 * norm_temp) blue = int(255 * (1 - norm_temp)) return f'rgb({red}, 0, {blue})' with col2: # Create the base map m = folium.Map(location=[22.3547, 114.1483], zoom_start=11, tiles='CartoDB positron') # Determine min and max temperatures for color scaling min_temp = df['Temperature'].min() max_temp = df['Temperature'].max() # Create a color scale legend colormap = folium.LinearColormap( colors=['blue', 'white', 'red'], index=[min_temp, (min_temp + max_temp) / 2, max_temp], vmin=min_temp, vmax=max_temp, caption='Temperature (°C)' ) colormap.add_to(m) # Iterate through each row in the DataFrame for _, row in df.iterrows(): lat = row['Latitude'] lon = row['Longitude'] station = row['Station'] temp = row['Temperature'] # Determine the color based on the temperature color = temperature_to_color(temp, min_temp, max_temp) if pd.notna(temp) else 'gray' # Create a marker with temperature data folium.Marker( location=[lat, lon], popup=f"

{station}: {temp:.1f}°C

", icon=folium.DivIcon( html=f'
' f'{temp:.1f}°C
' ) ).add_to(m) # Render the map in Streamlit st_folium(m, width=500, height=600) # Column 3: Data table with col3: # Set the table height using CSS st.markdown( """ """, unsafe_allow_html=True ) # Display the DataFrame with the custom CSS class st.dataframe(df[['Station', 'Temperature', 'Latitude', 'Longitude']], height=600) # Add a refresh button if st.button("Refresh Data"): st.experimental_rerun() # Automatically rerun every 5 minutes if 'last_ran' not in st.session_state or (datetime.now() - st.session_state.last_ran).seconds > 300: st.session_state.last_ran = datetime.now() st.experimental_rerun()