import dash
from dash import Dash, dcc, html, Input, Output, Patch, ctx
import dash_bootstrap_components as dbc
import dash_daq as daq
import plotly.graph_objects as go
from chart_function import create_sankey, config_dict
from data_cleaning import (sources, targets, values, colors,
nodes, node_colors)
# Create app object======================================================================
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.FONT_AWESOME])
#========================================================================================
# Create Sankey diagram
sankey = create_sankey(nodes, sources, targets, values, colors, node_colors)
# Create slider
slider_pad = dcc.Slider(id='slider-pad', min=0, max=25, step=5, value=20,
marks={str(i): str(i) for i in range(0, 26, 5)},
tooltip={"placement": "bottom", "always_visible": True})
# Create popover for information
popover_info = dbc.Popover([
dbc.PopoverHeader("World Bank Commodity Price Indexes: Groups and Weights"),
dbc.PopoverBody(html.Img(src="./assets/CPI_groups_weights.png", alt="Groups and Weights"))
],
target="info-button",
trigger="hover",
placement="bottom",
style={"max-width": "600px"})
# Create app layout=================================================================
app.layout = dbc.Container([
# Header
dbc.Row([
dbc.Col([
html.H2('Sankey Diagram for Non-Energy Commodity Group',
className='text-center my-4', style={'color': 'dimgray'}),
], width=11,),
dbc.Col( [dbc.Button(
html.I(className="fas fa-info-circle color-secondary", style={'color': 'dimgray'}),
id="info-button", color='fff',
n_clicks=0), popover_info], width=1, className='align-content-center'),
], class_name='mb-4 border-bottom bg-light'),
# Control Panel
dbc.Row([
dbc.Col([
html.Label('Node Alignment', className='me-3'),
dcc.RadioItems(options=['left', 'right'], value='left', id='radio-items', inline=True,
labelStyle={'margin-right': '10px'}, inputStyle={'margin-right': '10px'}),],
width=3,class_name='d-flex justify-content-center'),
dbc.Col(html.Label('Node Padding', className='d-flex justify-content-end'), width=2 ),
dbc.Col(slider_pad, width=3),
dbc.Col([html.Label('Use Default Colorscheme', className='me-3'),
daq.BooleanSwitch(on=False, id='boolean-switch')], width=4, className='d-flex justify-content-center')
], class_name='mb-3'),
# Sankey Diagram
dbc.Row(dbc.Col(dbc.Card(dcc.Graph(id='sankey-diagram',figure=sankey, config=config_dict), body=True), width=12)),
# Footer
dbc.Row([
dbc.Col(html.Label('Learn more about'), width=2, className='text-end'),
dbc.Col([html.A('Sankey Diagram', href='https://plotly.com/python/sankey-diagram/', target='_blank ', className='me-3'),
html.A('Sankey Traces', href='https://plotly.com/python/reference/sankey/', target='_blank ')],
width=3, className='d-flex'),
dbc.Col(html.Label('Source of Data'), width=2, className='text-end'),
dbc.Col(html.A('World Bank Group', href='https://www.worldbank.org/en/research/commodity-markets#1', target='_blank '), width=2),
dbc.Col(html.A('Figure Friday 2024 - week 50', href='https://community.plotly.com/t/figure-friday-2024-week-50/89366', target='_blank '), width=3)
], className='my-4') ,
])
# Callbacks==========================================================================
@app.callback(
Output('sankey-diagram', 'figure'),
Input('radio-items', 'value'),
Input('slider-pad', 'value'),
Input('boolean-switch', 'on'),
prevent_initial_call=True
)
def update_sankey(radio_items, slider_pad, boolean_switch):
patch_sankey = Patch()
if ctx.triggered_id == 'radio-items':
patch_sankey['data'][0]['node']['align'] = radio_items
return patch_sankey
if ctx.triggered_id == 'slider-pad':
patch_sankey['data'][0]['node']['pad'] = slider_pad
return patch_sankey
if boolean_switch:
sankey_no_color = create_sankey(nodes, sources, targets, values, link_colors=None, node_colors=None
).update_traces(node_align=radio_items, node_pad=slider_pad)
return sankey_no_color
else:
return sankey.update_traces(node_align=radio_items, node_pad=slider_pad)
if __name__ == '__main__':
app.run_server(debug=False)