Creating Python Dashboard using Dash

Creating Python Dashboard using Dash

Check out other post about the dashboard

Building the New Layout

For the new layout of the dashboard, I wanted something more modular. The previous version felt like it was too cramped, so this time I wanted to make them more separate. I also wanted to separate the code into different files, making it easier to read.

First I created a new file called layout_functions.py, this file contains all components such as the date picker, graphs, and layout containers.

# Import libraries required for building the dashboard
import pandas as pd
import datetime
from dash import html
from dash import dcc
from dash.dependencies import Input, Output


def header():
    header_layout = html.Div(
        id='header',
        className='header',
        children=[
            html.Div(
                children=[
                    html.H1(
                        children='CPI DashBoard',
                        className='header-title'
                    ),
                    html.H2(children='Visualizing CPI and Different Commodity',
                            className='header-description')
                ],
            )
        ]
    )

    return header_layout


def date_picker(data):
    range_picker = html.Div(
        children=[
            dcc.DatePickerRange(
                id='date_range',
                className='date_picker_container',
                min_date_allowed=data['year_month'].min(),
                max_date_allowed=data['year_month'].max(),
                start_date=data['year_month'].min(),
                end_date=data['year_month'].max(),
                initial_visible_month=data['year_month'].max()
            )
        ]
    )

    return range_picker


def drop_down():
    menu = dcc.Dropdown(
        id='drop_down_menu',
        className='drop_down_menu',
        options=[
            {'label': 'Commodity Prices', 'value': 'Commodity Prices'},
            {'label': 'Crude Oil Spot Price', 'value': 'Crude Oil Spot Price'},
            {'label': 'Crude Oil Production', 'value': 'Crude Oil Production'},
            {'label': 'Crude Oil Consumption', 'value': 'Crude Oil Consumption'}
        ],
        value='Commodity Prices'
    )

    return menu


def cpi_line_graph():
    line_graph = dcc.Graph(
        id='cpi_chart',
        className='card',
        config={'displayModeBar': True},
    )

    return line_graph


def line_graph():
    line_graph = dcc.Graph(
        id='line_chart',
        className='card',
        config={'displayModeBar': True}
    )

    return line_graph

header is the top part of the dashboard, it contains the title and the description of the dashboard.

date_picker allows the ability to select the date range of the data to visualize.

drop_down is the drop down menu for selecting different data to visualize.

cpi_line_graph and line_graph are used for displaying the data via line graphs.

Now that I have the functions for the component, I can start to build the dashboard. The following visualization can help understand the layout of the dashboard.

black border: Contain everything
Red border: Header
Yellow border: Sidebar
Green border: Date picker, Drop down menu, Graphs

To achieve this, I created a new file layout.py that houses all the containers.

import dash
from layout_functions.layout_functions import *
from data.data_update.fetch_data import *

bls_data = pd.read_csv('./data/bls_data.csv')
eia_petroleum_spot = pd.read_csv('./data/eia_crude_price.csv')
eia_api_crude_production = pd.read_csv('./data/eia_crude_production.csv')
eia_api_crude_consumption = pd.read_csv('./data/eia_crude_consumption.csv')

external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
                "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    }
]

# Initialize the dash class
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
app.title = 'CPI Dashboard'

app.layout = html.Div(
    children=[
        html.Div(
            header()
        ),
        html.Div(
            children=[
                html.Div(
                    id='sidebar',
                    className='sidebar',
                    children=[
                        dcc.Markdown('''
                        ## About this Project
                        This project is a dashboard for visualizing the CPI levels and different
                        prices. 
                        
                        Full Code: [Github](https://github.com/thecodingmango/cpi_dashboard)
                        
                        Website: [TheCodingMango](https://thecodingmango.com/)
                    ''')
                    ]
                ),
                html.Div(
                    id='main',
                    className='card',
                    children=[
                        # Date picker section
                        html.Div(
                            className='main_top',
                            children=[
                                date_picker(bls_data),
                                drop_down()
                            ]
                        ),

                        # CPI chart
                        html.Div(
                            className='cpi_chart_container',
                            children=[cpi_line_graph()]

                        ),

                        # Other Charts
                        html.Div(
                            className='line_chart_container',
                            children=[line_graph()]

                        )
                    ]
                )
            ],
            className='content_wrapper'
        )
    ],
    className='wrapper'
)

However, there is still a missing piece to the dashboard, if I want the dashboard to update when user interacts with it, I have to put in an app.callback for the dashboard to update.

@app.callback(
    [Output('cpi_chart', 'figure'),
     Output('line_chart', 'figure')],
    [Input('date_range', 'start_date'),
     Input('date_range', 'end_date'),
     Input('drop_down_menu', 'value')]
)
def update_chart(start_date, end_date, value):
    temp_list = []
    filters_date_bls = ((bls_data['year_month'] >= start_date) & (bls_data['year_month'] <= end_date))
    filtered_data_bls = bls_data.loc[filters_date_bls, :]

    cpi_chart = {
        'data': [
            {
                'x': filtered_data_bls['year_month'],
                'y': filtered_data_bls['cpi_values'],
                'type': 'lines',
                'name': 'CPI_Values'
            }
        ],
        'layout': {
            'title': {
                'text': 'CPI Values Since' + ' ' + start_date,
                'x': 'center'
            },
            'xaxis': {
                'title': 'Year',
            },
            'yaxis': {
                'title': {'text': 'CPI Values',
                          'font-size': 'bold'
                          },
                'ticksuffix': '%',
                'font': 'bold'
            },
            'height': 400
        }
    }

    if value == 'Commodity Prices':

        for series in filtered_data_bls.columns[1:-2]:
            temp_list += [
                {'x': filtered_data_bls['year_month'], 'y': filtered_data_bls[series],
                 'type': 'lines',
                 'name': series
                 }
            ]

        line_chart = {
            'data':
                temp_list
            ,
            'layout': {
                'title': {
                    'text': 'Comparison of Different Commodity Prices' + ' Since ' + start_date,
                    'x': 'center'
                },
                'xaxis': {
                    'title': ' Year'
                },
                'yaxis': {
                    'title': ' Prices in USD'
                },
                'height': 400
            }
        }

        return [cpi_chart, line_chart]

    elif value == 'Crude Oil Spot Price':
        eia_filter = ((eia_petroleum_spot['year_month'] >= start_date) &
                      (eia_petroleum_spot['year_month'] <= end_date))

        eia_petro_price = eia_petroleum_spot.loc[eia_filter, :]

        for series in eia_petro_price.columns[1:-1]:
            temp_list += [
                {
                    'x': eia_petro_price['year_month'],
                    'y': eia_petro_price[series],
                    'type': 'lines',
                    'name': series
                }
            ]

        line_chart = {
            'data':
                temp_list,
            'layout': {
                'title': {
                    'text': 'Comparison of Crude Oil Spot Prices' + ' Since ' + start_date,
                    'x': 'center'
                },
                'xaxis': {
                    'title': ' Year'
                },
                'yaxis': {
                    'title': ' Prices USD'
                },
                'height': 400
            }
        }

        return [cpi_chart, line_chart]

    elif value == 'Crude Oil Production':
        eia_filter_production = ((eia_api_crude_production['year_month'] >= start_date) &
                                 (eia_api_crude_production['year_month'] <= end_date))

        eia_oil_production = eia_api_crude_production.loc[eia_filter_production, :]

        for series in eia_oil_production.columns[1:-1]:
            temp_list += [
                {
                    'x': eia_oil_production['year_month'],
                    'y': eia_oil_production[series],
                    'type': 'lines',
                    'name': series
                }
            ]

        line_chart = {
            'data':
                temp_list,
            'layout': {
                'title': {
                    'text': 'Comparison of Different Oil Production Level by Country' + ' Since ' + start_date,
                    'x': 'center'
                },
                'xaxis': {
                    'title': ' Year'
                },
                'yaxis': {
                    'title': ' Million of Barrel (s)'
                },
                'height': 400
            }
        }

        return [cpi_chart, line_chart]

    elif value == 'Crude Oil Consumption':

        eia_filter_consumption = ((eia_api_crude_consumption['year_month'] >= start_date) &

                                  (eia_api_crude_consumption['year_month'] <= end_date))

        eia_oil_consumption = eia_api_crude_production.loc[eia_filter_consumption, :]

        for series in eia_oil_consumption.columns[1:-1]:
            temp_list += [
                {
                    'x': eia_oil_consumption['year_month'],
                    'y': eia_oil_consumption[series],
                    'type': 'lines',
                    'name': series
                }
            ]

        line_chart = {
            'data':
                temp_list,
            'layout': {
                'title': {
                    'text': 'Comparison of Different Oil Consumption Level by Country' + ' Since ' + start_date,
                    'x': 'center'
                },
                'xaxis': {
                    'title': ' Year'
                },
                'yaxis': {
                    'title': ' Million of Barrel (s)'
                },
                'height': 400
            }
        }

        return [cpi_chart, line_chart]

Finally, I created cpi_dashboard.py to run everything.

# Import libraries
from layout import app


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