ÎncepețiÎncepe gratuit

Tabele interactive în dashboardul de vânzări

Dashboardul general de vânzări a parcurs un drum lung de când ai început lucrul la el.

A fost distribuit pe scară largă în companie și a primit recenzii foarte pozitive. Au apărut însă și câteva solicitări pentru a face componenta tabelară mai interactivă. Una dintre acestea este posibilitatea de a selecta un anumit rând și de a actualiza astfel axa graficului scatter de mai jos.

Acest exercițiu face parte din cursul

Crearea dashboardurilor cu Dash și Plotly

Vezi cursul

Instrucțiuni pentru exercițiu

  • Activează selecția unui singur rând în grid prin setarea parametrului rowSelection sub linia 25.
  • Creează un callback sub linia 63 care va folosi selectedRows din my_grid pentru a actualiza figura scatter_compare, evidențiind țara selectată cu un punct roșu de dimensiuni mari.

Exercițiu interactiv practic

Încearcă acest exercițiu completând acest cod de exemplu.

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)
Editează și rulează codul