import streamlit as st import datetime import numpy as np today = datetime.date.today() def plot(df, n=10): import plotly.express as px # Order: prev pred, future pred, real line_colors = ['tomato', 'steelblue', 'limegreen'] # Extract the x-axis values (dates) from the dataframe x_values = df["date"] # Define your colors, labels, and ranges colors = ['green', 'yellow', 'orange', 'red', 'purple', 'darkred'] labels = ['Good', 'Moderate', 'Unhealthy for Some', 'Unhealthy', 'Very Unhealthy', 'Hazardous'] ranges = [(1, 49), (50, 99), (100, 149), (150, 199), (200, 299), (300, 500)] # Avoid 0 for log scale # Create the Plotly Express line chart for actual pm25 fig = px.line( df.iloc[:-n], # Exclude the last n points x="date", y="pm25", markers=True, line_shape='linear' ) fig.update_traces(line=dict(color=line_colors[2]), name='Actual', showlegend=True) # Add the predicted pm25 line in two segments fig.add_scatter( x=df["date"][:-n], y=df["predicted_pm25"][:-n], mode='lines+markers', name='Past prediction', line=dict(color=line_colors[0], width=3), marker=dict(size=10) ) fig.add_scatter( x=df["date"][-n:], y=df["predicted_pm25"][-n:], mode='lines+markers', name='Future prediction', line=dict(color=line_colors[1], width=3, dash='dot'), marker=dict(size=10) ) # Add a dotted line connecting past predicted pm25 to future predicted pm25 fig.add_scatter( x=[df["date"].iloc[-n-1], df["date"].iloc[-n]], y=[df["predicted_pm25"].iloc[-n-1], df["predicted_pm25"].iloc[-n]], mode='lines', name='Connecting Line', line=dict(color=line_colors[1], width=3, dash='dot'), showlegend=False # Remove from legend ) # Add background color rectangles using `shapes` shapes = [] for i, (start, end) in enumerate(ranges): shapes.append( dict( type="rect", # Add a rectangle xref="paper", # Extend the rectangle across the entire x-axis yref="y", # Anchor the rectangle to the y-axis x0=0, # Start from the left (x0 in paper coordinates) x1=1, # End at the right (x1 in paper coordinates) y0=start, # Start of the y-range y1=end, # End of the y-range fillcolor=colors[i], # Background color opacity=0.2, # Transparency level layer="below", # Place behind the data line_width=0 # No border ) ) label_font_size = 26 ticks_font_size = 20 # Update the layout and traces for customization fig.update_traces( marker=dict(size=10), # Increase marker size line=dict(width=3) # Make the line thicker ) # x range start BEFORE today k = 4 fig.update_layout( shapes=shapes, # Add the background rectangles xaxis=dict( range=[x_values.iloc[-n-k], x_values.iloc[-1]], # Dynamically set the range title=dict( text="Date", # Set x-axis label font=dict(size=label_font_size) # Increase font size for the x-axis label ), tickfont=dict(size=ticks_font_size) # Increase font size for x-axis numbers ), yaxis=dict( title=dict( text="log PM2.5", # Set y-axis label font=dict(size=label_font_size) # Increase font size for the y-axis label ), type="log", # Set y-axis to logarithmic scale fixedrange=True, # Disable vertical panning/zooming tickfont=dict(size=ticks_font_size), # Increase font size for y-axis numbers range=[1, np.log10(500)] # Set y-axis range to be positive ), autosize=True, width=2100, height=750, hoverlabel=dict( font_size=20 # Increase hover label font size ) ) return fig