Spaces:
Sleeping
Sleeping
| 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"<p style='text-align: center; font-style: italic;'>Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>", 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) |