클릭해서 다른 플롯 업데이트하기
hover로 업데이트되는 플롯이 큰 호응을 얻었어요. 정말 대단하네요! 여러분의 작업 덕분에 지루한 정적 시각화가 생동감 있는 경험 으로 바뀌고 있어요.
지난 레슨에서 만든 대시보드를 조금 바꿔 달라는 요청이 들어왔어요. 이 전자상거래 회사의 리포팅 체계는 국가 → 대분류(major category) → 소분류(minor category) 순서로 이어집니다. 그래서 hover로는 아래쪽 막대 차트를 업데이트하지 않기를 원해요.
대신, 대분류 막대 차트를 클릭하면 그 결과가 아래 막대 차트에 반영되도록 해 달라고 합니다. 이는 국가별로 대분류 매출 비중이 어떻게 다른지 파악하고자 하는 요구 때문이에요.
최근에 클릭과 hover를 다뤘던 경험을 살려, 어떻게 구현할지 이미 감이 오시죠!
이 연습은 강의의 일부입니다
Dash와 Plotly로 대시보드 만들기
연습 안내
'Major Category'가 클릭 데이터에 포함되도록, 37번째 줄 아래의 대분류 막대 차트에custom_data매개변수를 추가하세요.- 45번째 줄 아래에 콜백을 설정하여,
major_cat차트의 막대를 클릭하면minor_cat차트가 업데이트되도록 하세요.
실습형 인터랙티브 연습
이 예제를 이 샘플 코드를 완성하여 풀어보세요.
from dash import Dash, dcc, html, Input, Output, callback
import plotly.express as px
import pandas as pd
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()
app.layout = [
html.Img(src=logo_link, style={'margin':'30px 0px 0px 0px'}),
html.H1('Sales breakdowns'),
html.Div([
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([
dcc.Graph(id='major_cat'),
dcc.Graph(id='minor_cat')],
style={'width':'700px', 'height':'650px','display':'inline-block'})
]
@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
@callback(
Output('minor_cat', 'figure'),
Input('____', '____'))
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 ($)')
if clickData:
click_cat = clickData['points'][0]['customdata'][0]
major_cat_df = ecom_sales[ecom_sales['Major Category'] == click_cat]
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(debug=True)