Py.Cafe

nataliatsyporkin/

commodity_price_index

World Bank Commodity Price Indices Dashboard - Dash

DocsPricing
  • assets/
  • CMO_Monthly_Indices.xlsx
  • aggrid_def.py
  • app.py
  • cpi_chart_function.py
  • data_preprocessing.py
  • 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
import dash
from dash import Dash, dcc, html, Input, Output, State
import dash_bootstrap_components as dbc
import pandas as pd
from cpi_chart_function import *
from data_preprocessing import df
from aggrid_def import aggrid_table


# Create link button for header
link_btn = html.A( href='https://github.com/natatsypora/commodity_price_index', 
                  children=[ html.I(className="fab fa-github fa-2x")], 
                  target='_blank', style={'textDecoration':'none', 'color':'rgba(31,119,180,0.7)',} )


# Create modal with line and area graphs
modal_with_table = dbc.Modal([ 
    dbc.ModalBody([aggrid_table]),
    dbc.ModalFooter(dbc.Button("Close", id="close-modal-button", 
                               n_clicks=0, class_name='ms-auto btn-secondary'), 
                    className='p-0'),
        ],
        id="modal-with-table",
        size="xl",
        centered=True,
        is_open=False)


# Create app object===========================================================================
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP, 
                                           dbc.icons.FONT_AWESOME, 'assets/style.css'])
#============================================================================================= 


# Create app layout=================================================
app.layout = dbc.Container([
    # Header
    dbc.Row([
        dbc.Col(html.Img(src="./assets/Globe.png", alt="Globe", style={'height': '50px'}), 
             width=1, className='d-flex align-items-center justify-content-center'),
        dbc.Col(html.H2("World Bank Commodity Price Indices",  
                        className='text-center my-3', 
                        style={'color': 'rgba(31,119,180,0.8)'}), width=10),
        dbc.Col(link_btn,  width=1, className='d-flex align-items-center justify-content-center')
        ], class_name='mb-3 border-bottom bg-light'),
    # Control Panel
    dbc.Row([
        dbc.Col(html.Label('Select Index', className='me-3'), 
                width=2, className='d-flex align-items-center justify-content-end'),
        dbc.Col(
            dcc.Dropdown(
                id='index-group-dropdown',
                options=[{'label': i, 'value': i} for i in df.columns[2:-2]],
                value='Beverages',  # Default value
                clearable=False, 
                optionHeight=20), width=4),
        dbc.Col(html.Label('Select Year', className='me-3'), 
                width=2, className='offset-1 d-flex align-items-center justify-content-end'),
        dbc.Col(
            dcc.Dropdown(
                id='year-dropdown',
                options=[{'label': i, 'value': i} for i in df['year'].unique()[1:]],
                value=2023,  # Default value
                clearable=False, 
                optionHeight=20 ), width=1),
        dbc.Col([
            dbc.Button("View Table", id="open-modal-button", n_clicks=0, 
                       style={'background': '#8FBBD9', 'border': '1px solid #8FBBD9'}), 
            modal_with_table,          
        ], width=2, className='d-flex align-items-center justify-content-end'),
        ], class_name='mb-3'),    
     # Graphs
     dbc.Row([         
         dbc.Col([
             dbc.Card(dcc.Graph(id='area-graph', figure={}, config=config_dict), body=True, class_name='mb-3'),
             dbc.Card(dcc.Graph(id='mom-rate-graph', figure={}, config=config_dict), body=True)], 
             width=7),
         dbc.Col(dbc.Card([
                 dcc.Graph(id='scatter-graph', figure={}, config=config_dict),                 
                 dcc.Graph(id='yoy-graph', figure={}, config={'displayModeBar': False}),
                 dcc.Graph(id='mom-change-graph', figure={}, config=config_dict),                  
                 ], body=True, class_name='mb-3'), 
                 width=5),
         ]),           
    #Footer
    dbc.Row([                   
         dbc.Col(html.Label('Source of Data'), width=2, className='my-3 offset-1 text-end'),
         dbc.Col(html.A('World Bank Group', 
                        href='https://www.worldbank.org/en/research/commodity-markets#1', target='_blank '), 
                        width=2, className='my-3'),         
         dbc.Col([
             html.Label('Created with'), 
             html.A('Plotly', href='https://plotly.com/python/', target='_blank ', className='me-3'), 
             html.A('Dash', href='https://dash.plotly.com/', target='_blank '), 
        ], width=3, className='offset-3 my-3 d-flex align-items-center justify-content-around'),
], className='mb-3 border-top bg-light'),
])

# Callbacks==========================================================
@app.callback(    
    Output('area-graph', 'figure'),
    Output('yoy-graph', 'figure'),
    Output('scatter-graph', 'figure'),
    Output('mom-rate-graph', 'figure'),
    Output('mom-change-graph', 'figure'),
    Input('index-group-dropdown', 'value'),
    Input('year-dropdown', 'value'),
)
def update_graph(index, selected_year):
    # Filter data by selected year
    last_year = int(selected_year)
    prev_year = last_year - 1
    dff = df[['Date', index, 'year', 'month_3']].copy()
    ct_df =pd.crosstab(dff['month_3'], dff['year'], values=dff[index], aggfunc='max')
    
    area_graph = create_area_fillgradient(dff, 'Date', index, col_scale, line_color, 
        title=f'Commodity {index} Index Monthly Price<br><sub>Historical Data for 2010-2024, US$ (2010=100)</sub>') 
    
    title= f"YoY Change {last_year} vs {prev_year}" #for {index} Commodity Group"
    yoy_graph = create_bar_chart_with_changes(ct_df, last_year, prev_year, title=None)
    
    scatter_graph = create_scatter_plot_with_prc_changes(ct_df, last_year, prev_year, title)

    mom_rate_graph = line_chart_with_pos_and_neg_colors(dff, 'Date', index, pos_color, neg_col, 
                                                        title='MoM Growth Rate Across Years (%)')
    
    mom_change_graph = mom_changes_subplots(ct_df, y_col_name=last_year, title=f'MoM Change {last_year}')  
    
    return  area_graph, yoy_graph, scatter_graph, mom_rate_graph, mom_change_graph


# Callback for toggle modal
@app.callback(    
    Output("modal-with-table", "is_open"),
    Input("open-modal-button", "n_clicks"),
    Input("close-modal-button", "n_clicks"),
    State("modal-with-table", "is_open"),
)
def toggle_modal(n1, n2, is_open):
    if n1 or n2:
        return not is_open
    return is_open


if __name__ == '__main__':
    app.run_server(debug=False)