Py.Cafe

rishi-wqd190004/

dash-electricity-gen-emissions

Electricity Generation and Emissions Visualization

DocsPricing
  • app.py
  • data.csv.gz
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import pandas as pd
import dash
from dash import dcc, html
import plotly.express as px
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc

# Load your dataset
df = pd.read_csv("data.csv.gz", compression="gzip")

# Use Electricity demand (TWh) as proxy for generation
gen_df = df[(df['Category'] == 'Electricity demand') & (df['Unit'] == 'TWh')].copy()
gen_df['Year'] = pd.to_datetime(gen_df['Date']).dt.year

countries = sorted(gen_df['Area'].unique())
units = sorted(df['Unit'].unique())
years = sorted(gen_df['Year'].unique())

min_gen = gen_df['Value'].min()
max_gen = gen_df['Value'].max()

# External stylesheet for Bootstrap and icons
external_stylesheets = [dbc.themes.BOOTSTRAP, dbc.icons.FONT_AWESOME]

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# DBC Filter Card
filter_card = dbc.Card([
    dbc.CardHeader([
        html.H5([
            html.I(className="fas fa-cogs me-2"),
            "Control Panel"
        ], className="mb-0 text-primary")
    ]),
    dbc.CardBody([
        dbc.Row([
            dbc.Col([
                html.Label([
                    html.I(className="fas fa-flag me-2"),
                    "Countries to Compare"
                ], className="fw-bold mb-2"),
                dcc.Dropdown(
                    id='country_dd',
                    options=[{'label': f"{c}", 'value': c} for c in countries],
                    value=countries[0] if countries else None,
                    clearable=False,
                    className="mb-2"
                ),
                html.Small(f"Available: {len(countries)} countries", className="text-muted"),
            ], md=3),

            dbc.Col([
                html.Label([
                    html.I(className="fas fa-balance-scale me-2"),
                    "Unit of Measure"
                ], className="fw-bold mb-2"),
                dcc.Dropdown(
                    id='unit-selector',
                    options=[{'label': u, 'value': u} for u in units],
                    value='TWh' if 'TWh' in units else units[0],
                    clearable=False,
                    className="mb-2"
                ),
                html.Small(f"Units: {', '.join(units)}", className="text-muted"),
            ], md=2),

            dbc.Col([
                html.Label([
                    html.I(className="fas fa-calendar me-2"),
                    "Analysis Year"
                ], className="fw-bold mb-2"),
                dcc.Dropdown(
                    id='year-selector',
                    options=[{'label': str(y), 'value': y} for y in years],
                    value=years[-2] if len(years) > 1 else (years[-1] if years else None),
                    placeholder="Select year...",
                    className="mb-2"
                ),
                html.Small(f"Range: {min(years)}-{max(years)}", className="text-muted"),
            ], md=2),

            dbc.Col([
                html.Label([
                    html.I(className="fas fa-plug me-2"),
                    "Generation Range"
                ], className="fw-bold mb-2"),
                dcc.RangeSlider(
                    id='gen_slider',
                    min=min_gen,
                    max=max_gen,
                    step=0.1,
                    marks={int(min_gen): f'{int(min_gen)}', int(max_gen): f'{int(max_gen)}'},
                    value=[min_gen, max_gen],
                    tooltip={"placement": "bottom", "always_visible": False}
                ),
            ], md=5),
        ])
    ])
], className="mb-4 shadow-sm")

app.layout = dbc.Container([
    html.H1("Electricity Generation and Emissions by Country", className="mb-3"),
    filter_card,
    html.Div(id='top_country_info', className="mb-4"),
    dcc.Graph(id='generation_bar'),
    html.H3("Change in Electricity-related Emissions Over Time", className="mt-4"),
    dcc.Graph(id="emissions_time")
], fluid=True)

@app.callback(
    [Output('generation_bar', 'figure'),
     Output('emissions_time', 'figure'),
     Output('top_country_info', 'children')],
    [Input('country_dd', 'value'),
     Input('unit-selector', 'value'),
     Input('year-selector', 'value'),
     Input('gen_slider', 'value')]
)
def update_graph(selected_country, selected_unit, selected_year, gen_range):
    filtered_df = gen_df[
        (gen_df['Area'] == selected_country) &
        (gen_df['Unit'] == selected_unit) &
        (gen_df['Year'] == selected_year) &
        (gen_df['Value'] >= gen_range[0]) &
        (gen_df['Value'] <= gen_range[1])
    ]
    if not filtered_df.empty:
        top_value = filtered_df['Value'].max()
        top_info = html.H2(f"{selected_country}: {top_value} {selected_unit} in {selected_year}")
    else:
        top_info = html.H2("No data for selection.")

    # For the bar, also show a trend for this country (across years and unit)
    trend_df = gen_df[(gen_df['Area'] == selected_country) & (gen_df['Unit'] == selected_unit)]
    bar_fig = px.bar(trend_df, x="Year", y="Value", title=f"Generation Over Time - {selected_country}",
                     labels={"Value": f"Generation ({selected_unit})", "Year": "Year"})

    # Emissions chart (if emissions data available)
    emissions_df = df[
        ((df['Category'].str.contains('emission', case=False, na=False)) |
         (df['Variable'].str.contains('emission', case=False, na=False))) &
        (df['Area'] == selected_country)
    ].copy()
    if not emissions_df.empty:
        emissions_df['Year'] = pd.to_datetime(emissions_df['Date']).dt.year
        emissions_fig = px.line(
            emissions_df, x='Year', y='Value', color='Area',
            labels={"Value": "Emissions (as reported)", "Year": "Year", "Area": "Country"},
            title=f"Emissions for {selected_country} Over Time"
        )
    else:
        emissions_fig = {}

    return bar_fig, emissions_fig, top_info

if __name__ == "__main__":
    app.run(debug=True)