Dash Plotly 根据日期值更新卡片
Dash Plotly Update Cards Based on Date Value
我刚刚问了一个关于在 Plotly Dash 中更新卡片的类似问题,但出于某种原因,这种略有不同的情况让我很困惑。我的仪表板上有一些卡片,我想通过日期滑块的移动来更新它们。使用带有字符串类型变量的下拉菜单工作得很好,但现在我们在滑块中有一个日期值,这给我带来了一些麻烦。
这是我的一些代码:
#Import packages
import pandas as pd
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import time
who_data = pd.read_csv("https://covid19.who.int/WHO-COVID-19-global-data.csv")
pops = pd.read_csv("https://gist.githubusercontent.com/curran/0ac4077c7fc6390f5dd33bf5c06cb5ff/raw/605c54080c7a93a417a3cea93fd52e7550e76500/UN_Population_2019.csv")
who_data.rename(columns={'New_cases': 'New Cases', 'Cumulative_cases': 'Cumulative Cases', 'New_deaths': 'New Deaths','Cumulative_deaths': 'Cumulative Deaths'}, inplace=True)
daterange = pd.date_range(start=who_data['Date_reported'].min(),
end=who_data['Date_reported'].max(),
freq='D')
def unixTimeMillis(dt):
''' Convert datetime to unix timestamp '''
return int(time.mktime(dt.timetuple()))
def unixToDatetime(unix):
''' Convert unix timestamp to datetime. '''
return pd.to_datetime(unix,unit='s')
def getMarks(start, end, Nth=50):
''' Returns the marks for labeling.
Every Nth value will be used.
'''
result = {}
for i, date in enumerate(daterange):
if(i%Nth == 1):
# Append value to dict
result[unixTimeMillis(date)] = str(date.strftime('%Y-%m-%d'))
return result
card1_body = dbc.CardBody([html.H4("Card title", className="card-title",id="card_num1"),
html.P("Cumulative Cases for Date", className="card-text",id="card_text1")
],
style={'display': 'inline-block',
'text-align': 'center',
'color':'white',
'background-color': 'rgba(37, 150, 190)'})
card2_body = dbc.CardBody([html.H4("Card title", className="card-title",id="card_num2"),
html.P("Cumulative Deaths for Date", className="card-text",id="card_text2")
],
style={'display': 'inline-block',
'text-align': 'center',
'color':'white',
'background-color': 'rgba(37, 150, 190)'})
card1 = dbc.Card(card1_body,outline=True)
card2 = dbc.Card(card2_body,outline=True)
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div([
dcc.Tabs([
dcc.Tab(label='Spread',
children=[
html.Div([
dcc.RangeSlider(id='slider',
min = unixTimeMillis(daterange.min()),
max = unixTimeMillis(daterange.max()),
value = [unixTimeMillis(daterange.min())],
marks=getMarks(daterange.min(),daterange.max())
),
dbc.Row(id="card_row",children=[dbc.Col(card1),
dbc.Col(card2)
])
])
]),
dcc.Tab(label="Top 10",
children=[
html.P('Some stuff will go here eventually.')
])
])
])
@app.callback(
Output('card_row','children'),
Input('slider','value')
)
def update_cards(date_select):
date_df = who_data[(who_data.Date_reported<=date_select)]
tot_cases = f"{date_df['New Cases'].sum():,.0f}"
tot_deaths = f"{date_df['New Deaths'].sum():,.0f}"
card1 = dbc.Card([
dbc.CardBody([
html.H4(tot_cases, className="card-title"),
html.P(f"Cumulative Cases on {date_select}")
])
],
style={'display': 'inline-block',
'width': '50%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'fontWeight': 'bold',
'fontSize':20},
outline=True)
card2 = dbc.Card([
dbc.CardBody([
html.H4(tot_deaths, className="card-title"),
html.P(f"Cumulative Deaths on {date_select}")
])
],
style={'display': 'inline-block',
'width': '50%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'fontWeight': 'bold',
'fontSize':20},
outline=True)
return (card1, card2)
app.run_server(host='0.0.0.0',port='8050')
当我 运行 这样做时,两张卡没有更新,我收到一条错误消息,内容为“ValueError:长度必须匹配才能比较”。这是指我尝试在 update_cards 函数中创建“date_df”的行。在 Whosebug 上做了一些研究,我发现了一些例子表明 date_select 是一系列 1 值,我需要在它的末尾粘贴一个 .values[0] 到 select 一个值- 但这也没有用。不确定如何进行,如有任何帮助,我们将不胜感激!
谢谢!
你的错误是因为你将数据框对象与非标量进行比较,而该非标量与你的数据框对象的长度不同。
这就是我认为你认为正在发生的事情
In [79]: df = pd.DataFrame(np.random.randint(5, 15, (10, 3)), columns=list('abc'))
In [80]: df
Out[80]:
a b c
0 6 11 11
1 14 7 8
2 13 5 11
3 13 7 11
4 13 5 9
5 5 11 9
6 9 8 6
7 5 11 10
8 8 10 14
9 7 14 13
In [81]: df[df.b > 10]
Out[81]:
a b c
0 6 11 11
5 5 11 9
7 5 11 10
9 7 14 13
但实际上你在做这样的事情
df[df.b > [1,2,3,4,5,6]]
所以首先你需要找出 date_select
实际上是。这些只是我的假设,但您的数据格式化方式肯定存在问题。
其次,您真的应该仔细阅读情节回调文档。您正试图在回调函数中重新创建整个 HTML div。回调功能的功能只是更新图形。如果您将图表与 HTML 隔离开来并只更新图表,这会让您的生活变得更轻松。
我刚刚问了一个关于在 Plotly Dash 中更新卡片的类似问题,但出于某种原因,这种略有不同的情况让我很困惑。我的仪表板上有一些卡片,我想通过日期滑块的移动来更新它们。使用带有字符串类型变量的下拉菜单工作得很好,但现在我们在滑块中有一个日期值,这给我带来了一些麻烦。
这是我的一些代码:
#Import packages
import pandas as pd
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import time
who_data = pd.read_csv("https://covid19.who.int/WHO-COVID-19-global-data.csv")
pops = pd.read_csv("https://gist.githubusercontent.com/curran/0ac4077c7fc6390f5dd33bf5c06cb5ff/raw/605c54080c7a93a417a3cea93fd52e7550e76500/UN_Population_2019.csv")
who_data.rename(columns={'New_cases': 'New Cases', 'Cumulative_cases': 'Cumulative Cases', 'New_deaths': 'New Deaths','Cumulative_deaths': 'Cumulative Deaths'}, inplace=True)
daterange = pd.date_range(start=who_data['Date_reported'].min(),
end=who_data['Date_reported'].max(),
freq='D')
def unixTimeMillis(dt):
''' Convert datetime to unix timestamp '''
return int(time.mktime(dt.timetuple()))
def unixToDatetime(unix):
''' Convert unix timestamp to datetime. '''
return pd.to_datetime(unix,unit='s')
def getMarks(start, end, Nth=50):
''' Returns the marks for labeling.
Every Nth value will be used.
'''
result = {}
for i, date in enumerate(daterange):
if(i%Nth == 1):
# Append value to dict
result[unixTimeMillis(date)] = str(date.strftime('%Y-%m-%d'))
return result
card1_body = dbc.CardBody([html.H4("Card title", className="card-title",id="card_num1"),
html.P("Cumulative Cases for Date", className="card-text",id="card_text1")
],
style={'display': 'inline-block',
'text-align': 'center',
'color':'white',
'background-color': 'rgba(37, 150, 190)'})
card2_body = dbc.CardBody([html.H4("Card title", className="card-title",id="card_num2"),
html.P("Cumulative Deaths for Date", className="card-text",id="card_text2")
],
style={'display': 'inline-block',
'text-align': 'center',
'color':'white',
'background-color': 'rgba(37, 150, 190)'})
card1 = dbc.Card(card1_body,outline=True)
card2 = dbc.Card(card2_body,outline=True)
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div([
dcc.Tabs([
dcc.Tab(label='Spread',
children=[
html.Div([
dcc.RangeSlider(id='slider',
min = unixTimeMillis(daterange.min()),
max = unixTimeMillis(daterange.max()),
value = [unixTimeMillis(daterange.min())],
marks=getMarks(daterange.min(),daterange.max())
),
dbc.Row(id="card_row",children=[dbc.Col(card1),
dbc.Col(card2)
])
])
]),
dcc.Tab(label="Top 10",
children=[
html.P('Some stuff will go here eventually.')
])
])
])
@app.callback(
Output('card_row','children'),
Input('slider','value')
)
def update_cards(date_select):
date_df = who_data[(who_data.Date_reported<=date_select)]
tot_cases = f"{date_df['New Cases'].sum():,.0f}"
tot_deaths = f"{date_df['New Deaths'].sum():,.0f}"
card1 = dbc.Card([
dbc.CardBody([
html.H4(tot_cases, className="card-title"),
html.P(f"Cumulative Cases on {date_select}")
])
],
style={'display': 'inline-block',
'width': '50%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'fontWeight': 'bold',
'fontSize':20},
outline=True)
card2 = dbc.Card([
dbc.CardBody([
html.H4(tot_deaths, className="card-title"),
html.P(f"Cumulative Deaths on {date_select}")
])
],
style={'display': 'inline-block',
'width': '50%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'fontWeight': 'bold',
'fontSize':20},
outline=True)
return (card1, card2)
app.run_server(host='0.0.0.0',port='8050')
当我 运行 这样做时,两张卡没有更新,我收到一条错误消息,内容为“ValueError:长度必须匹配才能比较”。这是指我尝试在 update_cards 函数中创建“date_df”的行。在 Whosebug 上做了一些研究,我发现了一些例子表明 date_select 是一系列 1 值,我需要在它的末尾粘贴一个 .values[0] 到 select 一个值- 但这也没有用。不确定如何进行,如有任何帮助,我们将不胜感激!
谢谢!
你的错误是因为你将数据框对象与非标量进行比较,而该非标量与你的数据框对象的长度不同。
这就是我认为你认为正在发生的事情
In [79]: df = pd.DataFrame(np.random.randint(5, 15, (10, 3)), columns=list('abc'))
In [80]: df
Out[80]:
a b c
0 6 11 11
1 14 7 8
2 13 5 11
3 13 7 11
4 13 5 9
5 5 11 9
6 9 8 6
7 5 11 10
8 8 10 14
9 7 14 13
In [81]: df[df.b > 10]
Out[81]:
a b c
0 6 11 11
5 5 11 9
7 5 11 10
9 7 14 13
但实际上你在做这样的事情
df[df.b > [1,2,3,4,5,6]]
所以首先你需要找出 date_select
实际上是。这些只是我的假设,但您的数据格式化方式肯定存在问题。
其次,您真的应该仔细阅读情节回调文档。您正试图在回调函数中重新创建整个 HTML div。回调功能的功能只是更新图形。如果您将图表与 HTML 隔离开来并只更新图表,这会让您的生活变得更轻松。