import dash
from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from helper import create_pop_info
# Get data for the example plots
data = pd.read_csv("https://raw.githubusercontent.com/plotly/Figure-Friday/refs/heads/main/2024/week-49/megawatt_demand_2024.csv")
# Rename columns from index 5 to 13
data.columns = [col for col in data.columns[:5]] + \
[ (' ').join(name.split(' ')[:2]) if len(name.split(' ')) > 4 else name.split(' ')[0] for name in data.columns[5:] ]
# Convert the "Local Timestamp" column to a datetime format
data['Local Timestamp'] = pd.to_datetime(data['Local Timestamp Eastern Time (Interval Beginning)'])
data['Month_name'] = data['Local Timestamp'].dt.month_name()
data['Day'] = data['Local Timestamp'].dt.day
data['Day_name'] = data['Local Timestamp'].dt.day_name()
data['Hour'] = data['Local Timestamp'].dt.hour
# Create app object=================================================================
app = Dash(__name__, external_stylesheets=[dbc.themes.CERULEAN, dbc.icons.FONT_AWESOME])
#===================================================================================
# Get list all named color scales
named_colorscales = px.colors.named_colorscales()
#Create dropdown with options for color scales
dropdown_color_scale = dcc.Dropdown(
id='dropdown-color-scale',
options=[{'label': c, 'value': c} for c in named_colorscales],
clearable=False,
optionHeight=22,
value='balance')
#Create dropdown with options for region
dropdown_region = dcc.Dropdown(
id='dropdown-region',
options=[{'label': c, 'value': c} for c in data.columns[5:13]],
clearable=False,
optionHeight=22,
value='Connecticut')
#Create dropdown with options for month
dropdown_month = dcc.Dropdown(
id='dropdown-month',
options=[{'label': m, 'value': m} for m in data['Month_name'].unique()],
clearable=False, maxHeight=250,
optionHeight=22,
value='October')
#Create dropdown with options for template
dropdown_template = dcc.Dropdown(
id='dropdown-template',
options=[{'label': t.split('_')[-1], 'value': t} for t in ['plotly_dark', 'plotly_white'] ],
clearable=False,
optionHeight=22,
value='plotly_white')
# Create popovers
pop_info = create_pop_info(
id='info-data',
popover_content=dcc.Markdown("""
Data not available for the period from 5 February 2024 to 17 February 2024.
"""))
color_info = create_pop_info(
id='info-color',
popover_content=[
dcc.Markdown("""
Color scale and background color are based on the built-in color scales and themes in Plotly.
"""),
html.Hr(),
html.A('Plotly Colorscales Reference.', href='https://plotly.com/python/colorscales/#continuous-vs-discrete-color', target='_blank'),
html.Br(),
html.A('View all Colorscale Swatches.', href='https://app.py.cafe/app/nataliatsyporkin/dash-color-scales-swatches', target='_blank'),
html.Br(),
html.A('View available Themes.', href='https://plotly.com/python/templates', target='_blank'),],
popover_style={'maxHeight': '300px'})
# Create app layout=================================================================
app.layout = dbc.Container([
dbc.Row([
dbc.Col(
dbc.Card([
html.Div([
html.H2('Contour Plot for Challenge Figure Friday 2024 week-49', className='me-3'),
html.A('More Information', href='https://community.plotly.com/t/figure-friday-2024-week-49/89206', target='_blank')],
className='d-flex align-items-center justify-content-between')],
body=True),
width=12, className='my-3')
]),
dbc.Row([
dbc.Col([
html.Label('Select a Region and Month',
style={'fontSize': '18px','text-align': 'center', 'padding': '10px',}),
pop_info], width=6, className='d-flex align-items-center justify-content-center'),
dbc.Col([
html.Label('Select a Color Scale and Background Color',
style={'fontSize': '18px','text-align': 'center', 'padding': '10px',}),
color_info], width=6, className='d-flex align-items-center justify-content-center'),
]),
dbc.Row([
dbc.Col(dropdown_region, width=3),
dbc.Col(dropdown_month, width=3),
dbc.Col(dropdown_color_scale, width=3),
dbc.Col(dropdown_template, width=3),
]),
dbc.Row(dbc.Col(dbc.Card(dcc.Graph(id='contour-plot'), body=True), width=12, class_name='mt-3')),
dbc.Row([
dbc.Col(html.Label('Learn more about'), width=2, className='offset-1 text-end'),
dbc.Col(html.A('Contour Plots', href='https://plotly.com/python/contour-plots/', target='_blank '), width=2),
dbc.Col(html.Label('Source of Data'), width=2, className='text-end'),
dbc.Col(html.A('US Energy Information Administration (EIA)', href='https://www.eia.gov/electricity/wholesalemarkets/index.php', target='_blank '), width=3),
], className='my-3') ,
])
#Callback for updating the contour plot
@app.callback(
Output('contour-plot', 'figure'),
[Input('dropdown-region', 'value'),
Input('dropdown-color-scale', 'value'),
Input('dropdown-month', 'value'),
Input('dropdown-template', 'value')
])
def update_graph(region, colorscale, month, template):
# Filter data by selected month
dff = data[data['Month_name'] == month]
z = dff[region]
# Create the contour plot with a selected colorscale
fig = go.Figure(data=go.Contour(
x=dff['Day'],
y=dff['Hour'],
z=z,
colorscale=colorscale,
customdata=dff['Day_name'],
hovertemplate='%{customdata}<br>Day: %{x}<br>Hour: %{y}<br>Load: %{z:,.0f} MWh<extra></extra>',
contours=dict(
showlabels = True,
start=z.min(),
end=z.max()),
colorbar=dict(title='(MWh)', tickformat=',.0f')
))
# Update layout for better presentation
fig.update_layout(
height=600, margin=dict(l=20, t=50, r=50, b=20),
title=f'Hourly Actual Demand for Electricity in {region} in {month} 2024', title_font_size=20,
xaxis_title='Day',
yaxis_title='Hour',
template=template )
return fig
if __name__ == '__main__':
app.run_server(debug=False)