Click to update another plot

The hover-to-update plot was very well received. What magic! Your work is making experiences out of tired, static visuals.

There has been a request to change the dashboard you created in the last lesson. The reporting hierarchy of the e-commerce company begins at country, then major category, then minor category. Therefore, they would prefer if the hover didn't update the bottom bar chart.

Instead, they wonder if you could click on the major category bar chart and have that update the bar chart below. This has been requested because there is a desire to understand how the proportion of sales by major category differs between countries.

From your recent work in clicks and hovers, you know just the way to implement it!

Este exercício faz parte do curso

Building Dashboards with Dash and Plotly

Ver Curso

Instruções de exercício

  • Ensure the major category is going to be available in the click data by adding it to the major category bar chart below line 52.
  • Set up a callback below line 61 that will be triggered by clicking on a bar of the major category bar chart and will update the bar chart.
  • If the major category bar chart is clicked on, extract the category clicked on for usage in the proportional bar chart construction below line 71.
  • Use the clicked-on major category to subset the DataFrame for usage in bar chart creation below line 75.

Exercício interativo prático

Experimente este exercício preenchendo este código de exemplo.

import dash
from dash import dcc, html
import plotly.express as px
import pandas as pd
from dash.dependencies import Input, Output
ecom_sales = pd.read_csv('/usr/local/share/datasets/ecom_sales.csv')
logo_link = 'https://assets.datacamp.com/production/repositories/5893/datasets/fdbe0accd2581a0c505dab4b29ebb66cf72a1803/e-comlogo.png'
ecom_country = ecom_sales.groupby('Country')['OrderValue'].agg(['sum', 'count']).reset_index().rename(columns={'count':'Sales Volume', 'sum':'Total Sales ($)'})
ecom_scatter = px.scatter(ecom_country, x='Total Sales ($)', y='Sales Volume', color='Country', width=350, height=550, custom_data=['Country'])
ecom_scatter.update_layout({'legend':dict(orientation='h', y=-0.7,x=1, yanchor='bottom', xanchor='right')})

app = dash.Dash(__name__)

app.layout = html.Div([
  html.Img(src=logo_link, 
        style={'margin':'30px 0px 0px 0px' }),
  html.H1('Sales breakdowns'),
  html.Div(
    children=[
    html.Div(
        children=[
          html.H3('Sales Volume vs Sales Amount by Country'),
          dcc.Graph(id='scatter', figure=ecom_scatter),
        ],
        style={'width':'350px', 'height':'650px', 'display':'inline-block', 
               'vertical-align':'top', 'border':'1px solid black', 'padding':'20px'}),
    html.Div(
      children=[
        dcc.Graph(id='major_cat'),
        dcc.Graph(id='minor_cat'),
      ],
      style={'width':'700px', 'height':'650px','display':'inline-block'})
    ]),], 
  style={'text-align':'center', 'display':'inline-block', 'width':'100%'}
  )

@app.callback(
    Output('major_cat', 'figure'),
    Input('scatter', 'hoverData'))

def update_major_cat_hover(hoverData):
    hover_country = 'Australia'
    
    if hoverData:
        hover_country = hoverData['points'][0]['customdata'][0]

    major_cat_df = ecom_sales[ecom_sales['Country'] == hover_country]
    major_cat_agg = major_cat_df.groupby('Major Category')['OrderValue'].agg('sum').reset_index(name='Total Sales ($)')

    ecom_bar_major_cat = px.bar(major_cat_agg, x='Total Sales ($)',
                                # Ensure the Major category will be available
                                ____=['Major Category'], 
                                y='Major Category', height=300, 
                                title=f'Sales by Major Category for: {hover_country}', color='Major Category',
            color_discrete_map={'Clothes':'blue','Kitchen':'red', 'Garden':'green', 'Household':'yellow'})
    ecom_bar_major_cat.update_layout({'margin':dict(l=10,r=15,t=40,b=0), 'title':{'x':0.5}})

    return ecom_bar_major_cat

# Set up a callback for click data
@app.callback(
    ____('minor_cat', '____'),
    ____('major_cat', '____'))

def update_major_cat_click(clickData):
    click_cat = 'All'
    major_cat_df = ecom_sales.copy()
    total_sales = major_cat_df.groupby('Country')['OrderValue'].agg('sum').reset_index(name='Total Sales ($)')
    
    # Extract the major category clicked on for usage
    ____
        click_cat = clickData['points'][0]['____'][0]
        
        # Undetake a filter using the major category clicked on
        major_cat_df = ecom_sales[ecom_sales['Major Category'] == ____]
    
    country_mj_cat_agg = major_cat_df.groupby('Country')['OrderValue'].agg('sum').reset_index(name='Total Sales ($)')
    country_mj_cat_agg['Sales %'] = (country_mj_cat_agg['Total Sales ($)'] / total_sales['Total Sales ($)'] * 100).round(1)
    
    ecom_bar_country_mj_cat = px.bar(country_mj_cat_agg, x='Sales %', y='Country', 
                                orientation='h', height=450, range_x = [0,100], text='Sales %', 
                                     title=f'Global Sales % by Country for Major Category: {click_cat}')
    ecom_bar_country_mj_cat.update_layout({'yaxis':{'dtick':1, 'categoryorder':'total ascending'}, 'title':{'x':0.5}})

    return ecom_bar_country_mj_cat  
  

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