Skip to content

Create Your Own Interactive Data Dashboards (Tutorial and Python Code)

    You won’t get noticed unless you are solving real-world business problems.

    • find a problem
    • create a solution
    • share your work
    • land your dream job

    Pretty simple.

    The hard part is knowing where to start.

    It can be super easy though.

    Right now, millions of businesses are getting flooded with retail transaction data. Why? Because it’s “Black Friday” and “Cyber Monday” — the busiest shopping period of the entire year. And this can be your golden opportunity.

    If you have the expertise.

    Follow these exact steps to get noticed

    This tutorial walks you through creating an interactive dashboard with Python and Dash.

    It’s the perfect solution to the problem that so many business owners are facing today. And you can be the person that solves that painful problem for them. Which all but guarantees your promotion.

    Here’s what we’re building today (click here if you can’t see the gif below)

    Alright, let’s create this thing.

    Step 1: Set Up Your Environment and Load Your Data

    First, set up your environment, load your data, and take a peek at what’s inside. This step is crucial to understand the structure of your dataset.

    Paste this code into a new Google Collab notebook cell and run it.

    You can use my notebook to help you get started.

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    !pip install dash
    !pip install dash-bootstrap-components
    from dash import Dash, html, dcc, Input, Output
    import dash_bootstrap_components as dbc
    import pandas as pd
    import plotly.express as px
    # Better image quality
    %config InlineBackend.figure_formats = 'retina'
    # Load the CSV file
    data = pd.read_csv('https://query.data.world/s/iulzaqbyt4hklmha6clwp4yl3fhczl?dws=00000')
    # Display the first few rows of the dataframe
    print(data.head())
    !pip install dash !pip install dash-bootstrap-components from dash import Dash, html, dcc, Input, Output import dash_bootstrap_components as dbc import pandas as pd import plotly.express as px # Better image quality %config InlineBackend.figure_formats = 'retina' # Load the CSV file data = pd.read_csv('https://query.data.world/s/iulzaqbyt4hklmha6clwp4yl3fhczl?dws=00000') # Display the first few rows of the dataframe print(data.head())
    !pip install dash
    !pip install dash-bootstrap-components
    
    from dash import Dash, html, dcc, Input, Output
    import dash_bootstrap_components as dbc
    import pandas as pd
    import plotly.express as px
    
    # Better image quality
    %config InlineBackend.figure_formats = 'retina'
    
    # Load the CSV file
    data = pd.read_csv('https://query.data.world/s/iulzaqbyt4hklmha6clwp4yl3fhczl?dws=00000')
    
    # Display the first few rows of the dataframe
    print(data.head())

    Step 2: Clean and Prepare Your Data

    Data cleaning is vital. Next, ensure your data is in the right format, handling any missing or incorrect values.

    • Update the ‘order_amt’ column to remove the $ symbol and set it to numeric so that we can sum the values later on in the analysis
    • Fill any empty records with data instead of just blank values
    • Convert the ‘transaction_date’ column to a datetime so we can process it and sort
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    # Convert 'order_amt' to numerical values and handle missing values
    data['order_amt'] = data['order_amt'].replace('[\$,]', '', regex=True).astype(float)
    data.fillna({'rewards_member': False, 'coupon_flag': 'No', 'discount_amt': 0}, inplace=True)
    # Convert 'transaction_date' to datetime and sort
    data['transaction_date'] = pd.to_datetime(data['transaction_date'])
    data.sort_values(by='transaction_date', inplace=True)
    # Convert 'order_amt' to numerical values and handle missing values data['order_amt'] = data['order_amt'].replace('[\$,]', '', regex=True).astype(float) data.fillna({'rewards_member': False, 'coupon_flag': 'No', 'discount_amt': 0}, inplace=True) # Convert 'transaction_date' to datetime and sort data['transaction_date'] = pd.to_datetime(data['transaction_date']) data.sort_values(by='transaction_date', inplace=True)
    # Convert 'order_amt' to numerical values and handle missing values
    data['order_amt'] = data['order_amt'].replace('[\$,]', '', regex=True).astype(float)
    data.fillna({'rewards_member': False, 'coupon_flag': 'No', 'discount_amt': 0}, inplace=True)
    
    # Convert 'transaction_date' to datetime and sort
    data['transaction_date'] = pd.to_datetime(data['transaction_date'])
    data.sort_values(by='transaction_date', inplace=True)
    

    Step 3: Quickly Visualize Your Data

    Next, let’s take a look at the data we have visually. This helps to see what might be interesting or if there are any problems with the data set before moving on to build the dashboard.

    Here are some ideas:

    1. Sales over time
    2. Sales by location
    3. Customer demographics
    4. Discounts over time

    And here’s the code:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    # Summarize data by month
    data['month'] = data['transaction_date'].dt.to_period('M').dt.to_timestamp()
    monthly_data = data.groupby('month').sum().reset_index()
    # Sales Over Time Line Chart (Monthly Summary)
    fig1 = px.line(monthly_data, x='month', y='order_amt', title='Monthly Sales Over Time')
    # Sales by Location Bar Chart
    fig2 = px.bar(data, x='location_city', y='order_amt', title='Sales by Location')
    # Customer Demographics Pie Chart
    fig3 = px.pie(data, names='rewards_member', title='Customer Demographics')
    # Average Discount Amount Over Time (Monthly Summary)
    fig4 = px.line(monthly_data, x='month', y='discount_amt', title='Average Discount Amount Over Time')
    # Display the figures
    fig1.show()
    fig2.show()
    fig3.show()
    fig4.show()
    # Summarize data by month data['month'] = data['transaction_date'].dt.to_period('M').dt.to_timestamp() monthly_data = data.groupby('month').sum().reset_index() # Sales Over Time Line Chart (Monthly Summary) fig1 = px.line(monthly_data, x='month', y='order_amt', title='Monthly Sales Over Time') # Sales by Location Bar Chart fig2 = px.bar(data, x='location_city', y='order_amt', title='Sales by Location') # Customer Demographics Pie Chart fig3 = px.pie(data, names='rewards_member', title='Customer Demographics') # Average Discount Amount Over Time (Monthly Summary) fig4 = px.line(monthly_data, x='month', y='discount_amt', title='Average Discount Amount Over Time') # Display the figures fig1.show() fig2.show() fig3.show() fig4.show()
    # Summarize data by month
    data['month'] = data['transaction_date'].dt.to_period('M').dt.to_timestamp()
    monthly_data = data.groupby('month').sum().reset_index()
    
    # Sales Over Time Line Chart (Monthly Summary)
    fig1 = px.line(monthly_data, x='month', y='order_amt', title='Monthly Sales Over Time')
    
    # Sales by Location Bar Chart
    fig2 = px.bar(data, x='location_city', y='order_amt', title='Sales by Location')
    
    # Customer Demographics Pie Chart
    fig3 = px.pie(data, names='rewards_member', title='Customer Demographics')
    
    # Average Discount Amount Over Time (Monthly Summary)
    fig4 = px.line(monthly_data, x='month', y='discount_amt', title='Average Discount Amount Over Time')
    
    # Display the figures
    fig1.show()
    fig2.show()
    fig3.show()
    fig4.show()
    

    Step 4: Build the Interactive Dashboard with Dash

    Now that we’re comfortable with the data, let’s combine the visualizations into a comprehensive and interactive dashboard using Dash.

    There’s a lot of code here, but let’s break it down.

    1. Set up the Dash ‘app’ (this is the actual dashboard)
    2. Set up the structure of the dashboard
    3. Create some ‘callbacks’ to add the interactivity
    4. Fill in the dashboard with the charts

    I’ve added comments to make it easier to follow.

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    # Initialize the Dash app
    app = Dash(__name__)
    # Unique list of states for the dropdown
    states = data['location_state'].unique()
    # Define the layout
    app.layout = html.Div([
    # Dropdown for selecting a state
    html.H1("Retail Analytics Dashboard",
    style={'text-align': 'center', 'margin-top': '20px', 'font-family': 'Arial'}),
    html.Div([
    dcc.Dropdown(
    id='state-dropdown',
    options=[{'label': state, 'value': state} for state in states],
    value=states[0] # Default value
    )
    ], style={'padding': '20px', 'font-family': 'Arial'}),
    # Row for the first two graphs
    html.Div([
    html.Div([dcc.Graph(id='sales-over-time')],
    style={'width': '50%', 'display': 'inline-block'}),
    html.Div([dcc.Graph(id='sales-by-location')],
    style={'width': '50%', 'display': 'inline-block'}),
    ], style={'width': '100%', 'display': 'flex'}),
    # Row for the next two graphs
    html.Div([
    html.Div([dcc.Graph(id='customer-demographics')],
    style={'width': '50%', 'display': 'inline-block'}),
    html.Div([dcc.Graph(id='average-discount-over-time')],
    style={'width': '50%', 'display': 'inline-block'}),
    ], style={'width': '100%', 'display': 'flex'})
    ])
    # Callbacks for updating the graphs based on selected state
    @app.callback(
    Output('sales-over-time', 'figure'),
    Input('state-dropdown', 'value')
    )
    def update_sales_over_time(selected_state):
    filtered_data = data[data['location_state'] == selected_state]
    filtered_data['month'] = filtered_data['transaction_date'].dt.to_period('M').dt.to_timestamp()
    monthly_filtered_data = filtered_data.groupby('month').sum().reset_index()
    fig = px.line(monthly_filtered_data, x='month', y='order_amt',
    title=f'Monthly Sales Over Time in {selected_state}',
    labels={'month': 'Month', 'order_amt': 'Total Sales ($)'})
    return fig
    @app.callback(
    Output('sales-by-location', 'figure'),
    Input('state-dropdown', 'value')
    )
    def update_sales_by_location(selected_state):
    filtered_data = data[data['location_state'] == selected_state]
    filtered_data.sort_values(by='order_amt', inplace=True)
    fig = px.bar(filtered_data, x='location_city', y='order_amt',
    title=f'Total Sales by Location in {selected_state}',
    labels={'location_city': 'City', 'order_amt': 'Total Sales ($)'})
    return fig
    @app.callback(
    Output('customer-demographics', 'figure'),
    Input('state-dropdown', 'value')
    )
    def update_customer_demographics(selected_state):
    filtered_data = data[data['location_state'] == selected_state]
    fig = px.pie(filtered_data, names='rewards_member',
    title=f'Customer Demographics in {selected_state}',
    labels={'rewards_member': 'Rewards Member'})
    return fig
    @app.callback(
    Output('average-discount-over-time', 'figure'),
    Input('state-dropdown', 'value')
    )
    def update_average_discount_over_time(selected_state):
    filtered_data = data[data['location_state'] == selected_state]
    filtered_data['month'] = filtered_data['transaction_date'].dt.to_period('M').dt.to_timestamp()
    monthly_filtered_data = filtered_data.groupby('month').mean().reset_index()
    fig = px.line(monthly_filtered_data, x='month', y='discount_amt',
    title=f'Average Discount Amount Over Time in {selected_state}',
    labels={'month': 'Month', 'discount_amt': 'Average Discount Amount ($)'})
    return fig
    # Initialize the Dash app app = Dash(__name__) # Unique list of states for the dropdown states = data['location_state'].unique() # Define the layout app.layout = html.Div([ # Dropdown for selecting a state html.H1("Retail Analytics Dashboard", style={'text-align': 'center', 'margin-top': '20px', 'font-family': 'Arial'}), html.Div([ dcc.Dropdown( id='state-dropdown', options=[{'label': state, 'value': state} for state in states], value=states[0] # Default value ) ], style={'padding': '20px', 'font-family': 'Arial'}), # Row for the first two graphs html.Div([ html.Div([dcc.Graph(id='sales-over-time')], style={'width': '50%', 'display': 'inline-block'}), html.Div([dcc.Graph(id='sales-by-location')], style={'width': '50%', 'display': 'inline-block'}), ], style={'width': '100%', 'display': 'flex'}), # Row for the next two graphs html.Div([ html.Div([dcc.Graph(id='customer-demographics')], style={'width': '50%', 'display': 'inline-block'}), html.Div([dcc.Graph(id='average-discount-over-time')], style={'width': '50%', 'display': 'inline-block'}), ], style={'width': '100%', 'display': 'flex'}) ]) # Callbacks for updating the graphs based on selected state @app.callback( Output('sales-over-time', 'figure'), Input('state-dropdown', 'value') ) def update_sales_over_time(selected_state): filtered_data = data[data['location_state'] == selected_state] filtered_data['month'] = filtered_data['transaction_date'].dt.to_period('M').dt.to_timestamp() monthly_filtered_data = filtered_data.groupby('month').sum().reset_index() fig = px.line(monthly_filtered_data, x='month', y='order_amt', title=f'Monthly Sales Over Time in {selected_state}', labels={'month': 'Month', 'order_amt': 'Total Sales ($)'}) return fig @app.callback( Output('sales-by-location', 'figure'), Input('state-dropdown', 'value') ) def update_sales_by_location(selected_state): filtered_data = data[data['location_state'] == selected_state] filtered_data.sort_values(by='order_amt', inplace=True) fig = px.bar(filtered_data, x='location_city', y='order_amt', title=f'Total Sales by Location in {selected_state}', labels={'location_city': 'City', 'order_amt': 'Total Sales ($)'}) return fig @app.callback( Output('customer-demographics', 'figure'), Input('state-dropdown', 'value') ) def update_customer_demographics(selected_state): filtered_data = data[data['location_state'] == selected_state] fig = px.pie(filtered_data, names='rewards_member', title=f'Customer Demographics in {selected_state}', labels={'rewards_member': 'Rewards Member'}) return fig @app.callback( Output('average-discount-over-time', 'figure'), Input('state-dropdown', 'value') ) def update_average_discount_over_time(selected_state): filtered_data = data[data['location_state'] == selected_state] filtered_data['month'] = filtered_data['transaction_date'].dt.to_period('M').dt.to_timestamp() monthly_filtered_data = filtered_data.groupby('month').mean().reset_index() fig = px.line(monthly_filtered_data, x='month', y='discount_amt', title=f'Average Discount Amount Over Time in {selected_state}', labels={'month': 'Month', 'discount_amt': 'Average Discount Amount ($)'}) return fig
    # Initialize the Dash app
    app = Dash(__name__)
    
    # Unique list of states for the dropdown
    states = data['location_state'].unique()
    
    # Define the layout
    app.layout = html.Div([
        # Dropdown for selecting a state
        html.H1("Retail Analytics Dashboard", 
                style={'text-align': 'center', 'margin-top': '20px', 'font-family': 'Arial'}),
        html.Div([
            dcc.Dropdown(
                id='state-dropdown',
                options=[{'label': state, 'value': state} for state in states],
                value=states[0]  # Default value
            )
        ], style={'padding': '20px', 'font-family': 'Arial'}),
    
        # Row for the first two graphs
        html.Div([
            html.Div([dcc.Graph(id='sales-over-time')], 
                     style={'width': '50%', 'display': 'inline-block'}),
            html.Div([dcc.Graph(id='sales-by-location')], 
                     style={'width': '50%', 'display': 'inline-block'}),
        ], style={'width': '100%', 'display': 'flex'}),
    
        # Row for the next two graphs
        html.Div([
            html.Div([dcc.Graph(id='customer-demographics')], 
                     style={'width': '50%', 'display': 'inline-block'}),
            html.Div([dcc.Graph(id='average-discount-over-time')], 
                     style={'width': '50%', 'display': 'inline-block'}),
        ], style={'width': '100%', 'display': 'flex'})
    ])
    
    # Callbacks for updating the graphs based on selected state
    @app.callback(
        Output('sales-over-time', 'figure'),
        Input('state-dropdown', 'value')
    )
    def update_sales_over_time(selected_state):
        filtered_data = data[data['location_state'] == selected_state]
        filtered_data['month'] = filtered_data['transaction_date'].dt.to_period('M').dt.to_timestamp()
        monthly_filtered_data = filtered_data.groupby('month').sum().reset_index()
        fig = px.line(monthly_filtered_data, x='month', y='order_amt', 
                      title=f'Monthly Sales Over Time in {selected_state}',
                      labels={'month': 'Month', 'order_amt': 'Total Sales ($)'})
        return fig
    
    @app.callback(
        Output('sales-by-location', 'figure'),
        Input('state-dropdown', 'value')
    )
    def update_sales_by_location(selected_state):
        filtered_data = data[data['location_state'] == selected_state]
        filtered_data.sort_values(by='order_amt', inplace=True)
        fig = px.bar(filtered_data, x='location_city', y='order_amt', 
                     title=f'Total Sales by Location in {selected_state}',
                     labels={'location_city': 'City', 'order_amt': 'Total Sales ($)'})
        return fig
    
    @app.callback(
        Output('customer-demographics', 'figure'),
        Input('state-dropdown', 'value')
    )
    def update_customer_demographics(selected_state):
        filtered_data = data[data['location_state'] == selected_state]
        fig = px.pie(filtered_data, names='rewards_member', 
                     title=f'Customer Demographics in {selected_state}',
                     labels={'rewards_member': 'Rewards Member'})
        return fig
    
    @app.callback(
        Output('average-discount-over-time', 'figure'),
        Input('state-dropdown', 'value')
    )
    def update_average_discount_over_time(selected_state):
        filtered_data = data[data['location_state'] == selected_state]
        filtered_data['month'] = filtered_data['transaction_date'].dt.to_period('M').dt.to_timestamp()
        monthly_filtered_data = filtered_data.groupby('month').mean().reset_index()
        fig = px.line(monthly_filtered_data, x='month', y='discount_amt', 
                      title=f'Average Discount Amount Over Time in {selected_state}',
                      labels={'month': 'Month', 'discount_amt': 'Average Discount Amount ($)'})
        return fig
    
    

    Step 5: Start up the Dashboard

    Finally, let’s run the Dash app to see our interactive dashboard and share it with the world!

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    # Run the app
    if __name__ == '__main__':
    app.run_server(debug=True)
    # Run the app if __name__ == '__main__': app.run_server(debug=True)
    # Run the app
    if __name__ == '__main__':
        app.run_server(debug=True)

    Here’s what you’ll see in Google Colab: (click here if you can’t see the gif below)

    Looks great!

    Try it on your own:

    If you made it this far, congratulations! Share a copy with me via email or on x/Twitter.

    • Try different chart types
    • Use the same chart types but use different columns
    • Try it with a data set from your work or another project

    Did this tutorial help? Hit reply and let me know or fill out this quick survey.

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    The Analytics in Action Newsletter

    Join thousands of subscribers getting free SQL code and solving real business problems.
    Build data analysis skills by solving real business problems with SQL (even if you’ve never written a line of code before.)

    Unsubscribe any time. I hate spam as much as you do.