Interactieve verkooptabellen in het dashboard
Het overkoepelende verkoopdashboard is al een heel eind gekomen sinds je begon.
Het dashboard is binnen het bedrijf breed gedeeld en krijgt veel positieve reacties. Er zijn echter verzoeken om het tabelonderdeel interactiever te maken. Zo is er gevraagd om de mogelijkheid toe te voegen om een bepaalde kolom te selecteren en daarmee de as op de scatterplot hieronder aan te passen.
Deze oefening maakt deel uit van de cursus
Dashboards bouwen met Dash en Plotly
Oefeninstructies
- Schakel selectie van één rij in de
gridin door de parameterrowSelectiononder regel25in te stellen. - Maak onder regel
63een callback die deselectedRowsvanmy_gridgebruikt om descatter_compare-figure bij te werken, waarbij het geselecteerde land wordt uitgelicht als een grote rode stip.
Interactieve oefening met praktijkervaring
Probeer deze oefening door deze voorbeeldcode aan te vullen.
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(['Country'])['OrderValue'].agg(['sum', 'count', 'mean', 'median']).reset_index().rename(columns={'count':'Sales Volume', 'sum':'Total Sales ($)', 'mean':'Average Order Value ($)', 'median':'Median 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':'pink'})
money_fmt = {"function": ("params.value.toLocaleString('en-US', {style: 'currency', currency: 'USD'})")}
column_defs = [
{"field": "Country"},
{"field": "Total Sales ($)", "valueFormatter": money_fmt},
{"field": "Average Order Value ($)", "valueFormatter": money_fmt},
{"field": "Median Order Value ($)", "valueFormatter": money_fmt},
{"field": "Sales Volume"},
]
grid = AgGrid(
id="my_grid",
columnDefs=column_defs,
rowData=large_tb.to_dict("records"),
# Enable single-row selection
dashGridOptions={"____": "____"},
defaultColDef={
"cellStyle": {
"textAlign": "left",
"backgroundColor": "black",
"color": "white"}}
)
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'}),
grid,
html.Br(),
html.Div([
dcc.Graph(id='scatter_compare'),
dcc.Graph(id='major_cat', figure=bar_fig_country, style={'display':'inline-block'}),
dcc.Graph(id='minor_cat', style={'display':'inline-block'})],
style={'width':'1000px', 'height':'650px','display':'inline-block'})
]
# Create a callback with the right input
@callback(
Output('scatter_compare', 'figure'),
Input('my_grid', '____')
)
def update_scatter(selected_rows):
fig = px.scatter(
large_tb,
x='Sales Volume',
y='Total Sales ($)',
color='Country',
title='Sales Volume vs Total Sales ($) — click a row to highlight')
if selected_rows:
sel_df = pd.DataFrame(selected_rows)
highlight = px.scatter(
sel_df,
x='Sales Volume',
y='Total Sales ($)',
color_discrete_sequence=['#ff0000'],
size=[15] * len(sel_df))
fig.add_trace(highlight.data[0])
return fig
@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)