CommencerCommencer gratuitement

Enhancing the sales dashboard

The e-commerce company is thrilled with your work and keeps coming up with creative new ideas. This time, they want a powerful dashboard that combines everything you’ve built so far into one interactive interface.

Now they wish to have:

  • A line chart of monthly sales filtered by major and minor categories.
  • A dropdown for each category, where the minor options update based on the major selection.
  • A table showing aggregated stats for those categories.
  • A bar chart of total sales by country.
  • Another bar chart showing minor category sales that updates when hovering over the country chart.

You've already built all the parts - now it's time to bring them together!

Cet exercice fait partie du cours

Building Dashboards with Dash and Plotly

Afficher le cours

Instructions

  • Turn on pagination for the grid by setting the pagination parameter below line 23.
  • Limit each page to show 6 rows by setting the paginationPageSize parameter below line 26.
  • Insert the grid object into the app.layout list below line 49.

Exercice interactif pratique

Essayez cet exercice en complétant cet exemple de code.

from dash import Dash, dcc, html, Input, Output, callback
import plotly.express as px
import pandas as pd
from dash_ag_grid import AgGrid
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'
major_categories = list(ecom_sales['Major Category'].unique())
large_tb = ecom_sales.groupby(['Major Category', 'Minor Category'])['OrderValue'].agg(['sum', 'count', 'mean']).reset_index().rename(columns={'count':'Sales Volume', 'sum':'Total Sales ($)', 'mean':'Average Order Value ($)'})
ecom_country = ecom_sales.groupby('Country')['OrderValue'].agg('sum').reset_index(name='Total Sales ($)')
bar_fig_country = px.bar(ecom_country, x='Total Sales ($)', y='Country', width=500, height=450, title='Total Sales by Country (Hover to filter the Minor Category bar chart!)', custom_data=['Country'], color='Country', color_discrete_map={'United Kingdom':'lightblue', 'Germany':'orange', 'France':'darkblue', 'Australia':'green', 'Hong Kong':'red'})
money_fmt = {"function": ("params.value.toLocaleString('en-US', {style: 'currency', currency: 'USD'})")}

column_defs = [
  {"field": "Major Category"},
  {"field": "Total Sales ($)", "valueFormatter": money_fmt},
  {"field": "Average Order Value ($)", "valueFormatter": money_fmt},
  {"field": "Sales Volume"}
]

grid = AgGrid(
  columnDefs=column_defs,
  rowData=large_tb.to_dict("records"),
  # Turn on pagination
  dashGridOptions={
    "____": ____,        
    # Show 6 rows per page
    "____": ____}       
)

app = Dash()
app.layout = [
  html.Img(src=logo_link, style={'margin':'30px 0px 0px 0px' }),
  html.H1('Sales breakdowns'),
  html.Div([
    html.H2('Controls'),
    html.Br(),
    html.H3('Major Category Select'),
    dcc.Dropdown(id='major_cat_dd',
                 options=[{'label':category, 'value':category} for category in major_categories],
                 style={'width':'200px', 'margin':'0 auto'}),
    html.Br(),
    html.H3('Minor Category Select'),
    dcc.Dropdown(id='minor_cat_dd', style={'width':'200px', 'margin':'0 auto'})],
    style={'width':'350px', 'height':'360px', 'display':'inline-block', 'vertical-align':'top', 'border':'1px solid black', 'padding':'20px'}),
  html.Div([
    html.H3(id='chosen_major_cat_title'),
    dcc.Graph(id='sales_line')],
    style={'width':'700px', 'height':'380px','display':'inline-block', 'margin-bottom':'5px'}),
  # Insert the AG Grid
  ____,
  html.Div([
    html.Div(dcc.Graph(id='major_cat', figure=bar_fig_country), style={'display':'inline-block'}),
    html.Div(dcc.Graph(id='minor_cat'), style={'display':'inline-block'})],
    style={'width':'1000px', 'height':'650px','display':'inline-block'})
]

@callback(
   Output('minor_cat_dd', 'options'),
   Output('chosen_major_cat_title', 'children'),
   Input('major_cat_dd', 'value'))

def update_dd(major_cat_dd):
    major_minor = ecom_sales[['Major Category', 'Minor Category']].drop_duplicates()
    relevant_minor = major_minor[major_minor['Major Category'] == major_cat_dd]['Minor Category'].values.tolist()
    minor_options = [dict(label=x, value=x) for x in relevant_minor]
    if not major_cat_dd:
        major_cat_dd = 'ALL'
    major_cat_title = f'This is in the Major Category of : {major_cat_dd}'
    return minor_options, major_cat_title

@callback(
    Output('sales_line', 'figure'),
    Input('minor_cat_dd', 'value'))

def update_line(minor_cat):
    minor_cat_title = 'All'
    ecom_line = ecom_sales.copy()
    if minor_cat:
        minor_cat_title = minor_cat
        ecom_line = ecom_line[ecom_line['Minor Category'] == minor_cat]
    ecom_line = ecom_line.groupby('Year-Month')['OrderValue'].agg('sum').reset_index(name='Total Sales ($)')
    line_graph = px.line(ecom_line, x='Year-Month',  y='Total Sales ($)', title=f'Total Sales by Month for Minor Category: {minor_cat_title}', height=350)
    return line_graph

@callback(
    Output('minor_cat', 'figure'),
    Input('major_cat', 'hoverData'))

def update_min_cat_hover(hoverData):
    hover_country = 'Australia'
    if hoverData:
        hover_country = hoverData['points'][0]['customdata'][0]
    minor_cat_df = ecom_sales[ecom_sales['Country'] == hover_country]
    minor_cat_agg = minor_cat_df.groupby('Minor Category')['OrderValue'].agg('sum').reset_index(name='Total Sales ($)')
    ecom_bar_minor_cat = px.bar(minor_cat_agg, x='Total Sales ($)', y='Minor Category', orientation='h', height=450, width=480,title=f'Sales by Minor Category for: {hover_country}')
    ecom_bar_minor_cat.update_layout({'yaxis':{'dtick':1, 'categoryorder':'total ascending'}, 'title':{'x':0.5}})
    return ecom_bar_minor_cat


if __name__ == '__main__':
    app.run(debug=True)
Modifier et exécuter le code