import streamlit as st import pandas as pd import numpy as np from bokeh.plotting import figure from bokeh.layouts import column, layout from bokeh.models import ColumnDataSource, HoverTool, NumeralTickFormatter, Range1d, Div from bokeh.palettes import Category20, RdYlGn from bokeh.themes import Theme from datetime import datetime # Function to generate Bokeh plots def generate_dashboard(): # Read and process the data data = pd.read_csv("data.csv") data['Date'] = pd.to_datetime(data['Date']) # Sort the data by date data = data.sort_values('Date') # Get the latest two dates latest_date = data['Date'].max() previous_date = data[data['Date'] < latest_date]['Date'].max() # Filter data for the latest two dates latest_data = data[data['Date'] == latest_date] previous_data = data[data['Date'] == previous_date] # Define the metrics for percentage change calculation change_metrics = [ 'Installation Status', 'Inspection Approved Status', 'Application Status', 'Inspection Rejected Status', 'Subsidy Redeem Status (Amount)' ] # Calculate percentage change def calculate_percentage_change(state, metric): latest_value = latest_data[latest_data['State'] == state][metric].values[0] previous_value = previous_data[previous_data['State'] == state][metric].values[0] if previous_value == 0 and latest_value == 0: return 0 elif previous_value == 0: return 100 if latest_value > 0 else 0 return ((latest_value - previous_value) / previous_value) * 100 # Create DataFrames with percentage changes change_data = {} for metric in change_metrics: change_data[metric] = pd.DataFrame({ 'State': latest_data['State'], 'Percentage_Change': latest_data['State'].apply(lambda x: calculate_percentage_change(x, metric)) }) change_data[metric] = change_data[metric].sort_values('Percentage_Change', ascending=False) def create_percentage_change_figure(title, data, metric): source = ColumnDataSource(data) colors = [RdYlGn[11][5] if x == 0 else RdYlGn[11][0] if x > 0 else RdYlGn[11][10] for x in data['Percentage_Change']] source.add(colors, 'color') p = figure(title=title, x_range=data['State'].tolist(), height=400, width=1000, toolbar_location="above", tools="pan,wheel_zoom,box_zoom,reset,save") p.vbar(x='State', top='Percentage_Change', width=0.9, source=source, line_color='white', fill_color='color') p.xgrid.grid_line_color = None max_change = max(abs(data['Percentage_Change'].max()), abs(data['Percentage_Change'].min())) p.y_range = Range1d(-max_change * 1.1, max_change * 1.1) p.xaxis.axis_label = "State" p.yaxis.axis_label = "Percentage Change" p.xaxis.major_label_orientation = 0.7 p.yaxis.formatter = NumeralTickFormatter(format="0,0.00") p.title.text_font_size = "12pt" p.xaxis.axis_label_text_font_size = "10pt" p.yaxis.axis_label_text_font_size = "10pt" p.xaxis.major_label_text_font_size = "8pt" p.yaxis.major_label_text_font_size = "8pt" hover = HoverTool(tooltips=[("State", "@State"), ("Percentage Change", "@Percentage_Change{0.00}%")]) p.add_tools(hover) return p def create_state_figure(title, x_range, source, metric): p = figure(title=title, x_range=x_range, height=400, width=900, toolbar_location="above", tools="pan,wheel_zoom,box_zoom,reset,save") p.vbar(x='State', top=metric, width=0.9, source=source, line_color='white', fill_color='color') p.xgrid.grid_line_color = None p.y_range.start = 0 p.xaxis.axis_label = "State" p.yaxis.axis_label = "Count" p.xaxis.major_label_orientation = 0.7 p.yaxis.formatter = NumeralTickFormatter(format="0,0") p.title.text_font_size = "12pt" p.xaxis.axis_label_text_font_size = "10pt" p.yaxis.axis_label_text_font_size = "10pt" p.xaxis.major_label_text_font_size = "8pt" p.yaxis.major_label_text_font_size = "8pt" hover = HoverTool(tooltips=[("State", "@State"), (metric, f"@{{{metric}}}")]) p.add_tools(hover) return p # Create percentage change figures change_figures = {} for metric in change_metrics: change_figures[metric] = create_percentage_change_figure(f"Day-on-Day Percentage Change - {metric}", change_data[metric], metric) # Create state figures state_metrics = [ 'Application Status', 'Installation Status', 'Inspection Approved Status', 'Subsidy Redeem Status' ] figures = {} for metric in state_metrics: sorted_data = latest_data.sort_values(by=metric, ascending=False) top_states = sorted_data.head(10)['State'].tolist() bottom_states = sorted_data.tail(10)['State'].tolist()[::-1] for suffix, states in [('top', top_states), ('bottom', bottom_states)]: source = ColumnDataSource(latest_data[latest_data['State'].isin(states)]) source.data['color'] = Category20[20][:10] if suffix == 'top' else Category20[20][10:] key = f"{metric}_{suffix}" figures[key] = create_state_figure(f"{'Top' if suffix == 'top' else 'Bottom'} 10 States - {metric}", states, source, metric) return figures, change_figures # Streamlit application st.set_page_config(page_title="State Statistics Dashboard", layout="wide") st.title("State Statistics Dashboard") st.markdown(f"
Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
", unsafe_allow_html=True) # Generate the dashboard figures figures, change_figures = generate_dashboard() # Display the Bokeh plots in Streamlit for metric in figures: st.bokeh_chart(figures[metric], use_container_width=True) for metric in change_figures: st.bokeh_chart(change_figures[metric], use_container_width=True)