import streamlit as st import pandas as pd import plotly.express as px #import bar_chart_race as bcr from raceplotly.plots import barplot # Configuration and Constants COUNTRY_MAPPING = { "Italy, San Marino and the Holy See": "Italy", "France and Monaco": "France", "Belgium and Luxembourg": "Belgium", "China (mainland)": "China", "United States of America": "United States", "United Kingdom of Great Britain and Northern Ireland": "United Kingdom", "Spain and Andorra": "Spain" } DEFAULT_COUNTRIES = ["Italy", "France", "Germany"] YEAR_RANGE = (2000, 2020) # Data Loading and Processing Functions @st.cache_data def load_data(sheet_name, year_range = (2000, 2020), sector=None): df = pd.read_excel("dati/fossilco2emission.xlsx", sheet_name=sheet_name) df_mapped = df.copy() df_mapped['Country'] = df_mapped['Country'].replace(COUNTRY_MAPPING) year_cols = list(range(year_range[0], year_range[1] + 1)) if sector: selected_cols = ['Country', 'Sector'] + year_cols else: selected_cols = ['Country'] + year_cols return df_mapped[selected_cols].copy() def process_data_for_line_plot(df, selected_countries, year_range): mask = df['Country'].isin(selected_countries) filtered_df = df[mask] df_melted = filtered_df.melt( id_vars=['Country'], value_vars=range(year_range[0], year_range[1] + 1), var_name='Year', value_name='Emissions' ) df_melted['Year'] = pd.to_numeric(df_melted['Year']) return df_melted # Visualization Functions def create_line_plot(data): fig = px.line( data, x='Year', y='Emissions', color='Country', title='CO2 Emissions Over Time', labels={'Emissions': 'CO2 Emissions per Capita (Mton)'}, hover_data={'Year': True, 'Emissions': ':.2f'} ) fig.update_layout(height=600, hovermode='x unified') return fig def create_animated_choropleth(data, start_year, end_year): df_map = data.melt( id_vars=['Country'], value_vars=range(start_year, end_year + 1), var_name='Year', value_name='Emissions' ) fig_map = px.choropleth( df_map, locations='Country', locationmode='country names', color='Emissions', animation_frame='Year', title='CO2 Emissions per Capita Over Time', color_continuous_scale='Reds', range_color=[0, df_map['Emissions'].quantile(0.95)], labels={'Emissions': 'CO2 Emissions per Capita (Mton)'} ) fig_map.update_layout( height=600, margin=dict(l=0, r=0, t=30, b=0), updatemenus=[{ 'type': 'buttons', 'showactive': False, 'buttons': [ dict(label='Play', method='animate', args=[None, {'frame': {'duration': 500, 'redraw': True}, 'fromcurrent': True}]), dict(label='Pause', method='animate', args=[[None], {'frame': {'duration': 0, 'redraw': False}, 'mode': 'immediate', 'transition': {'duration': 0}}]) ] }] ) return fig_map def create_race_plot(df, year_range): # Prepare data for race plot # Convert year columns to rows for raceplotly format df_race = df.melt( id_vars=['Country'], value_vars=range(year_range[0], year_range[1] + 1), var_name='Year', value_name='Emissions' ) # Create the race plot race_plot = barplot( df_race, item_column='Country', value_column='Emissions', time_column='Year', top_entries=10, ) # Plot with custom settings fig = race_plot.plot( title='Top 10 Countries by CO2 Emissions', orientation='horizontal', item_label='Country', value_label='CO2 Emissions (Mton)', time_label='Year: ', frame_duration=800 ) # fig.update_layout( # height=700, # Make plot taller # font=dict(size=12), # Increase base font size # title_font_size=20, # Larger title # xaxis_title_font_size=16, # Larger axis titles # yaxis_title_font_size=16, # yaxis_tickfont_size=14, # Larger tick labels # xaxis_tickfont_size=14 # ) return fig def create_covid_impact_plot(df1, df2): # Create tabs for different COVID analyses tab1, tab2 = st.tabs(["Global Impact", "Sectoral Impact"]) print(df2.head()) with tab1: # Global emissions around COVID years_covid = range(2017, 2023) global_emissions = df1[df1['Country'] == 'GLOBAL TOTAL'] emissions_covid = global_emissions[list(years_covid)].values[0] fig_global = px.line( x=years_covid, y=emissions_covid, title='Global CO2 Emissions Around COVID-19', labels={'x': 'Year', 'y': 'CO2 Emissions (Mt CO2)'} ) fig_global.add_vline(x=2020, line_dash="dash", line_color="red", annotation_text="COVID-19") st.plotly_chart(fig_global, use_container_width=True) # Calculate and display percentage changes col1, col2 = st.columns(2) with col1: change_2020 = ((emissions_covid[3] - emissions_covid[2])/emissions_covid[2]*100) st.metric("2020 Emissions Change", f"{change_2020:.1f}%") with col2: change_2021 = ((emissions_covid[4] - emissions_covid[3])/emissions_covid[3]*100) st.metric("2021 Recovery", f"{change_2021:.1f}%") with tab2: # Sectoral analysis sectors = ['Power Industry', 'Industrial Combustion', 'Transport', 'Processes'] sector_data = {} for sector in sectors: sector_emissions = df2[(df2['Sector'] == sector) & (df2['Country'] == 'GLOBAL TOTAL')] sector_data[sector] = sector_emissions[list(years_covid)].values[0] # Create DataFrame for plotly df_sectors = pd.DataFrame(sector_data, index=years_covid).reset_index() df_sectors_melted = df_sectors.melt('index', var_name='Sector', value_name='Emissions') fig_sectors = px.line( df_sectors_melted, x='index', y='Emissions', color='Sector', title='CO2 Emissions by Sector Around COVID-19' ) fig_sectors.add_vline(x=2020, line_dash="dash", line_color="red", annotation_text="COVID-19") st.plotly_chart(fig_sectors, use_container_width=True) # Display sector-specific impacts st.subheader("Sector Impact (2019-2020)") cols = st.columns(len(sectors)) for i, sector in enumerate(sectors): change = ((sector_data[sector][3] - sector_data[sector][2])/ sector_data[sector][2]*100) cols[i].metric(sector, f"{change:.1f}%") def create_agreements_timeline(df1): # Get the global total data global_data = df1[df1['Country'] == 'GLOBAL TOTAL'].iloc[0] # Get only the year columns (1970 to 2023) year_columns = [col for col in df1.columns if str(col).isdigit()] years = [int(col) for col in year_columns] values = [global_data[year] for year in years] # Create the plot using plotly fig = px.line( x=years, y=values, title='Global CO2 Emissions and Key Climate Agreements', labels={'x': 'Year', 'y': 'CO2 Emissions (Mt CO2)'} ) # Add vertical lines for key agreements agreements = { 1997: 'Kyoto Protocol Adopted', 2005: 'Kyoto Protocol Enforced', 2015: 'Paris Agreement' } colors = {'1997': 'red', '2005': 'green', '2015': 'orange'} for year, agreement in agreements.items(): fig.add_vline( x=year, line_dash="dash", line_color=colors[str(year)], annotation_text=agreement, annotation_position="top" ) # Customize layout fig.update_layout( hovermode='x unified', showlegend=False, height=600 ) return fig # Main App Function def main(): st.set_page_config(page_title="CO2 Emissions Dashboard", layout="wide") st.title("Global CO2 Emissions Dashboard") # Load Data df1 = load_data("fossil_CO2_per_capita_by_countr") df2 = load_data("fossil_CO2_totals_by_country") df3 = load_data("fossil_CO2_by_sector_country_su", year_range=(2017, 2023), sector="Sector") df_covid = load_data("fossil_CO2_totals_by_country", year_range=(2017, 2023)) df_poliicy = load_data("fossil_CO2_totals_by_country", year_range=(1970,2023)) df2 = df2[df2['Country'] != 'International Shipping'] df_only_countries = df2.copy()[:210] # Sidebar Controls #st.sidebar.header("Controls") #st.sidebar.markdown("---") st.sidebar.image("dati/SIAM-logo.jpg", width=150) visualization_type = st.sidebar.radio( "Choose Visualization", ["Time Series Plot", "Animated World Map", "Bar Chart Race", "COVID-19 Impact", "Climate Agreements Timeline"] ) # Year range selector (common to both visualizations) year_range = st.sidebar.slider( "Select Year Range", min_value=YEAR_RANGE[0], max_value=YEAR_RANGE[1], value=YEAR_RANGE ) # Conditional controls and display if visualization_type == "Time Series Plot": st.subheader("CO2 Emissions Time Series") # Show country selector only for time series countries = df1['Country'].unique().tolist() selected_countries = st.sidebar.multiselect( "Select countries to compare", options=countries, default=DEFAULT_COUNTRIES ) # Process and display time series plot df_processed = process_data_for_line_plot(df1, selected_countries, year_range) fig = create_line_plot(df_processed) st.plotly_chart(fig, use_container_width=True) elif visualization_type == "Animated World Map": st.subheader("Global Emissions Map (Animated)") fig_map = create_animated_choropleth(df1, year_range[0], year_range[1]) st.plotly_chart(fig_map, use_container_width=True) elif visualization_type == "Climate Agreements Timeline": st.subheader("Global Emissions and Climate Agreements") # Add some context about the agreements with st.expander("About the Climate Agreements"): st.markdown(""" - **Kyoto Protocol (1997)**: First legally binding agreement to reduce greenhouse gases - **Kyoto Protocol Enforcement (2005)**: The protocol came into force - **Paris Agreement (2015)**: Global agreement to limit temperature rise to well below 2°C """) # Create and display the plot fig = create_agreements_timeline(df_poliicy) st.plotly_chart(fig, use_container_width=True) # Add some analysis st.markdown("### Key Observations") col1, col2, col3 = st.columns(3) # Calculate some metrics kyoto_change = ((float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][2005]) - float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][1997])) / float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][1997]) * 100) paris_change = ((float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][2023]) - float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][2015])) / float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][2015]) * 100) with col1: st.metric("Emissions Change 1997-2005", f"{kyoto_change:.1f}%") with col2: st.metric("Emissions Change 2015-2023", f"{paris_change:.1f}%") with col3: latest_emissions = float(df_poliicy[df_poliicy['Country'] == 'GLOBAL TOTAL'][2023]) st.metric("Current Emissions (Mt CO2)", f"{latest_emissions:.1f}") elif visualization_type == "COVID-19 Impact": st.subheader("COVID-19 Impact Analysis") create_covid_impact_plot(df_covid, df3) else: st.subheader("Top 10 CO2 Emitters Race") fig_race = create_race_plot(df_only_countries, year_range) st.plotly_chart(fig_race, use_container_width=True) st.sidebar.markdown("---") st.sidebar.markdown(""" GRUPPO 5 (EMANUELA, FULVIO, MARCO, TINSAE) """) if __name__ == "__main__": main()