python - 在 plotly 上创建具有多个回调的过滤器
问题描述
我最近开始使用 plotly 来创建交互式仪表板。我仍在学习它,所以我想知道最佳实践,以便创建影响我的应用程序中多个数字的过滤器。
这就是我的app.py
样子:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
from datetime import datetime
from pandas import Timestamp
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors = {
'background': '#111111',
'text': '#7FDBFF'
}
data = {'Id Incidencia': {0: 'INC000006722157',
1: 'INC000006722000',
2: 'INC000006721939',
3: 'INC000006708347',
4: 'INC000006723090',
5: 'INC000006736601',
6: 'INC000006736721',
7: 'INC000006724926',
8: 'INC000006725331',
9: 'INC000006725229',
10: 'INC000006722542',
11: 'INC000006722729',
12: 'INC000006723246',
13: 'INC000006722574',
14: 'INC000006741563',
15: 'INC000006722571',
16: 'INC000006741632',
17: 'INC000006741568',
18: 'INC000006741636',
19: 'INC000006741640'},
'Fecha Apertura': {0: Timestamp('2020-12-07 12:28:30'),
1: Timestamp('2020-12-07 09:52:06'),
2: Timestamp('2020-12-07 10:13:06'),
3: Timestamp('2020-12-02 09:02:45'),
4: Timestamp('2020-12-07 20:37:53'),
5: Timestamp('2020-12-12 00:35:16'),
6: Timestamp('2020-12-12 00:46:48'),
7: Timestamp('2020-12-08 15:21:15'),
8: Timestamp('2020-12-08 20:04:14'),
9: Timestamp('2020-12-08 18:33:54'),
10: Timestamp('2020-12-07 15:52:59'),
11: Timestamp('2020-12-07 18:33:22'),
12: Timestamp('2020-12-07 23:56:08'),
13: Timestamp('2020-12-07 17:11:05'),
14: Timestamp('2020-12-14 13:31:05'),
15: Timestamp('2020-12-07 17:06:55'),
16: Timestamp('2020-12-14 13:44:35'),
17: Timestamp('2020-12-14 13:33:40'),
18: Timestamp('2020-12-14 13:46:38'),
19: Timestamp('2020-12-14 13:51:34')}}
df = pd.DataFrame(data)
df["Fecha Apertura"] = pd.to_datetime(df["Fecha Apertura"])
df = df.set_index('Fecha Apertura')
periods = [('D', '%Y-%m-%d'), ('M', '%Y-%m'), ('Y', '%Y')]
grouped_data = df.groupby(df.index.to_period(periods[0][0]))["Id Incidencia"].count()
fig2 = px.line(
x=grouped_data.index.strftime(periods[0][1]),
y=grouped_data.values,
title='Distribución temporal de las incidencias',
labels={
'x': 'Fecha',
'y': 'Nº incidencias'
}
)
app.layout = html.Div(children=[
dcc.Dropdown(
id='groupby-period',
options=[
{'label': 'Día', 'value': 0},
{'label': 'Mes', 'value': 1},
{'label': 'Año', 'value': 2}
],
value=0,
clearable=False,
searchable=False
),
dcc.DatePickerRange(
id='date-picker-range',
start_date_placeholder_text="Fecha Inicio",
end_date_placeholder_text="Fecha Fin",
calendar_orientation='horizontal',
),
dcc.Graph(
id='line-chart-apertura',
figure=fig2
)
])
@app.callback(
Output('line-chart-apertura', 'figure'),
Input('groupby-period', 'value')
)
def update_graphs_by_period(period):
periods = [('D', '%Y-%m-%d'), ('M', '%Y-%m'), ('Y', '%Y')]
grouped_data = df.groupby(df.index.to_period(periods[period][0]))["Id Incidencia"].count()
fig = px.line(
x=grouped_data.index.strftime(periods[period][1]),
y=grouped_data.values,
title='Distribución temporal de las incidencias',
labels={
'x': 'Fecha',
'y': 'Nº incidencias'
}
)
fig.update_layout(transition_duration=500)
return fig
@app.callback(
Output('line-chart-apertura', 'figure'),
[
Input('date-picker-range', 'start_date'),
Input('date-picker-range', 'end_date')
],
prevent_initial_call=True
)
def filter_by_date_range(start_date, end_date):
if start_date is None or end_date is None:
return dash.no_update
start_date_object = datetime.fromisoformat(start_date)
end_date_object = datetime.fromisoformat(end_date)
mask = (df.index >= start_date_object) & (df.index <= end_date_object)
df_range = df.loc[mask]
periods = [('D', '%Y-%m-%d'), ('M', '%Y-%m'), ('Y', '%Y')]
grouped_data = df_range.groupby(df_range.index.to_period(periods[0][0]))["Id Incidencia"].count()
fig = px.line(
x=grouped_data.index.strftime(periods[0][1]),
y=grouped_data.values,
title='Distribución temporal de las incidencias',
labels={
'x': 'Fecha',
'y': 'Nº incidencias'
}
)
fig.update_layout(transition_duration=500)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
我稍微解释一下:
- 我上传了一个简单的
df
示例,其中仅包含我在示例中使用的列:日期列和唯一标识符列。部署时,数据将从云环境中检索,因此保留原始数据很重要。 - 有两个过滤器可以控制相同的折线图图形(想法是稍后将它们应用于更多不同的图形):
- Dropdown:定义折线图的粒度。它只是根据用户下拉选择按日、月或年对时间戳进行分组。
- 日期选择器范围:用户可以在其中选择要在图中显示的日期范围。它必须与其他过滤器兼容:如果我们选择一个日期范围,它必须根据下拉列表中选择的日期粒度显示。
到目前为止,我已经实现了让两个过滤器独立工作,但我正在努力让它们同时工作。我知道我的实际方法是不可能的,因为一个数字只能受到一个回调的影响,所以我需要将它们组合成一个。但是,我不知道最干净和最佳实践方法是什么。
- 将两种回调方法合并为一个的最干净的方法是什么?
- 我的按日期范围过滤
df_range = df.loc[mask]
的方法是我应该做的,还是有一个像全局 df 对象df_to_show = df.copy()
并使用它来代替它会更好? - 关于#2:如果回调函数修改了全局变量,我怎么能做到这一点
df_to_show
,所有使用它的数字都会注意到它,以便他们重绘自己?
解决方案
推荐阅读
- flutter - generated_plugin_registrant.dart 中的导入不完整
- flutter - 更新时 Flutter SqfliteDatabaseException
- reactjs - 无法与 firebase 实时数据库模拟器交互
- html - 如何防止内容显示在 div 面板下
- python - Pandas:根据另一列中存在的组对一列中的所有值进行归一化,介于 0 和 10 之间
- javascript - 曾经工作的 Google App 脚本现在在 UrlfetchApp 上获得“访问权限未授予或过期”。在 Chrome 浏览器中工作的获取获取
- reactjs - id 为“sc-iseJRi”的组件 styled.p 已动态创建
- azure - 了解 Azure B2C 中即时迁移自定义策略的响应
- android - 我们如何使用 Google Pay 测试错误和失败案例?
- c - 如何在 C 中将 dns 名称转换为主机名字符串?