从回调 Plotly Dash 设置列名
Set column names from callback Plotly Dash
我正在尝试创建一个数据 table,它显示来自核心 table (df) 的汇总结果。为此,我使用 Pandas、Dash 和 Plotly,如下所示:
import pandas as pd
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components import Div
from dash_table import DataTable
from dash.dependencies import Input, Output
df = pd.DataFrame([['1', '2021-01-31', 'category_1', 20],
['1', '2021-01-31', 'category_3', 12],
['1', '2021-02-28', 'category_1', 35],
['1', '2021-02-28', 'category_2', 17],
['1', '2021-02-28', 'category_3', 35],
['1','2021-03-31', 'category_1', 12],
['1','2021-03-31', 'category_2', 58],
['1','2021-03-31', 'category_3', 23],
['2', '2021-01-31', 'category_1', 29],
['2', '2021-01-31', 'category_2', 66],
['2', '2021-01-31', 'category_3', 22],
['2', '2021-02-28', 'category_1', 53],
['2', '2021-02-28', 'category_2', 71],
['2', '2021-02-28', 'category_3', 32],
['2','2021-03-31', 'category_1', 19],
['2','2021-03-31', 'category_2', 2],
['2','2021-03-31', 'category_3', 99],
['3', '2021-02-28', 'category_1', 53],
['3', '2021-02-28', 'category_2', 71],
['3','2021-03-31', 'category_1', 19],
['3','2021-03-31', 'category_2', 2],
['3','2021-03-31', 'category_3', 99],
['3','2021-03-31', 'category_4', 39]],
columns=['Account', 'Date', 'category', 'Amount'])
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id="account", type="string", placeholder="Enter Account"),
DataTable(id='figure_1',
style_cell_conditional=[{'if': {'column_id': c}, 'textAlign': 'center'} for c in [0, 1, 2, 3, 4]],
style_as_list_view=True,
fill_width=True,
style_cell={'font-size': '12px'},
style_header={'display': 'none'},
style_table={'height': '395px', 'overflowY': 'auto'})])
@app.callback(dash.dependencies.Output('figure_1', 'data'),
[dash.dependencies.Input('account', 'value')])
def update_figura_2(account):
df_query = df[df['Account'] == account].copy()
df_query = df_query.groupby(['Account', 'Date', 'category']).agg({'Amount': 'sum'}).reset_index().pivot(values='Amount', columns='Date')
df_query.index = df.loc[df['Account'] == account, 'category'].copy()
df_query.fillna(0, inplace=True)
return df_query.to_dict(orient='records')
if __name__ == '__main__':
app.run_server(debug=False)
所以我想要得到的输出:
但是,当我 运行 代码时,我得到一个空数据框:
我怀疑它必须与回调有关,但我不知道是什么!
我应该在数据表中定义列参数吗?如果是这样,我怎样才能得到回调的列?
如果您查看 DataTable
对象的 documentation,则有 columns
和 data
的参数,但我无法成功修改这两个属性使用回调(如果我弄明白了,我会编辑我的答案)。
我尝试使用以下回调来修改 DataTable 对象的列和数据:
@app.callback([Output('datatable', 'columns'), Output('datatable', 'data')],
[Input('account', 'value')])
def update_table(account):
...
return df_query
...但我无法使其正常工作:即使未引发任何错误,table 也不会显示。我的猜测是一旦创建了 DataTable
对象就无法修改 columns
,这就是回调无法按预期工作的原因。
相反,我们可以使用 作为模板从头构建 table,将整个 table 包装在 html.Div
容器中。
由于每个用户输入产生的 DataFrame df_query
是按类别索引的,因此我们需要注意如何使用 html.Tr
和 html.Th
构建 table dash_html_components 库中的对象。我们可以遍历 DataFrame 的每一行,添加索引值,然后是该行的剩余值。
import pandas as pd
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components import Div
import dash_table_experiments as dt
from dash_table import DataTable
from dash.dependencies import Input, Output
df = pd.DataFrame([['1', '2021-01-31', 'category_1', 20],
['1', '2021-01-31', 'category_3', 12],
['1', '2021-02-28', 'category_1', 35],
['1', '2021-02-28', 'category_2', 17],
['1', '2021-02-28', 'category_3', 35],
['1','2021-03-31', 'category_1', 12],
['1','2021-03-31', 'category_2', 58],
['1','2021-03-31', 'category_3', 23],
['2', '2021-01-31', 'category_1', 29],
['2', '2021-01-31', 'category_2', 66],
['2', '2021-01-31', 'category_3', 22],
['2', '2021-02-28', 'category_1', 53],
['2', '2021-02-28', 'category_2', 71],
['2', '2021-02-28', 'category_3', 32],
['2','2021-03-31', 'category_1', 19],
['2','2021-03-31', 'category_2', 2],
['2','2021-03-31', 'category_3', 99],
['3', '2021-02-28', 'category_1', 53],
['3', '2021-02-28', 'category_2', 71],
['3','2021-03-31', 'category_1', 19],
['3','2021-03-31', 'category_2', 2],
['3','2021-03-31', 'category_3', 99],
['3','2021-03-31', 'category_4', 39]],
columns=['Account', 'Date', 'category', 'Amount'])
## construct a table with variable number of columns
def generate_table(df, max_rows=100):
return html.Table(
# Header
[html.Tr([html.Th(df.columns.name)] + [html.Th(col) for col in df.columns])] +
# Body
[html.Tr([html.Th(df.index.name)])] +
[html.Tr([html.Td(df.index[i])] + [
html.Td(df.iloc[i][col]) for col in df.columns
]) for i in range(min(len(df), max_rows))]
)
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
children=[
dcc.Input(id="account", type="text", placeholder="Enter Account"),
html.Div(id='table-container')
])
@app.callback(Output('table-container', 'children'),
[Input('account', 'value')])
def update_table(account):
df_query = df[df['Account'] == account].copy()
df_query = df_query.groupby(['Account', 'Date', 'category']).agg({'Amount': 'sum'}).reset_index().pivot(values='Amount', columns='Date')
df_query.index = df.loc[df['Account'] == account, 'category'].copy()
df_query.fillna(0, inplace=True)
# print(df_query.to_dict(orient='records'))
return generate_table(df_query)
if __name__ == '__main__':
app.run_server(debug=True)
为了使 table 看起来更漂亮一些,您可以使用一些 css 来交替行颜色。在你 运行 你的 dash 应用程序 python 文件所在的同一目录中,创建一个名为 assets
的文件夹并创建一个名为 style.css
的新文件,其中包含以下内容:
tr:nth-child(even) {background: #CCC}
tr:nth-child(odd) {background: #FFF}
结果如下:
我找到了一个解决方法,您不必像 Derek 的回答那样通过它的 html 组件手动构建 table。
import pandas as pd
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components import Div
from dash_table import DataTable
from dash.dependencies import Input, Output
df = pd.DataFrame([['1', '2021-01-31', 'category_1', 20],
['1', '2021-01-31', 'category_3', 12],
['1', '2021-02-28', 'category_1', 35],
['1', '2021-02-28', 'category_2', 17],
['1', '2021-02-28', 'category_3', 35],
['1','2021-03-31', 'category_1', 12],
['1','2021-03-31', 'category_2', 58],
['1','2021-03-31', 'category_3', 23],
['2', '2021-01-31', 'category_1', 29],
['2', '2021-01-31', 'category_2', 66],
['2', '2021-01-31', 'category_3', 22],
['2', '2021-02-28', 'category_1', 53],
['2', '2021-02-28', 'category_2', 71],
['2', '2021-02-28', 'category_3', 32],
['2','2021-03-31', 'category_1', 19],
['2','2021-03-31', 'category_2', 2],
['2','2021-03-31', 'category_3', 99],
['3', '2021-02-28', 'category_1', 53],
['3', '2021-02-28', 'category_2', 71],
['3','2021-03-31', 'category_1', 19],
['3','2021-03-31', 'category_2', 2],
['3','2021-03-31', 'category_3', 99],
['3','2021-03-31', 'category_4', 39]],
columns=['Account', 'Date', 'category', 'Amount'])
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id="account", type="string", placeholder="Enter Account"),
html.Div(id='figure_1')
])
@app.callback(Output('figure_1', 'children'),
[Input('account', 'value')])
def update_figura_2(account):
df_query = df[df['Account'] == account].copy()
df_query = df_query.groupby(['Account', 'Date', 'category']).agg({'Amount': 'sum'}).reset_index().pivot(values='Amount', columns='Date')
df_query.index = df.loc[df['Account'] == account, 'category'].copy()
df_query.fillna(0, inplace=True)
return [DataTable(columns=[{"name": i, "id": i} for i in df_query.columns],
data=df_query.to_dict('records'),
style_as_list_view=True,
fill_width=True,
style_cell={'font-size': '12px'},
style_header={'display': 'none'},
style_table={'height': '395px', 'overflowY': 'auto'})]
if __name__ == '__main__':
app.run_server(debug=False)
其中的逻辑是在回调中创建 DataTable 图形并将其作为图形的子图形返回,因此返回的图形将按您需要的 columns/values 帐户进行过滤。
我正在尝试创建一个数据 table,它显示来自核心 table (df) 的汇总结果。为此,我使用 Pandas、Dash 和 Plotly,如下所示:
import pandas as pd
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components import Div
from dash_table import DataTable
from dash.dependencies import Input, Output
df = pd.DataFrame([['1', '2021-01-31', 'category_1', 20],
['1', '2021-01-31', 'category_3', 12],
['1', '2021-02-28', 'category_1', 35],
['1', '2021-02-28', 'category_2', 17],
['1', '2021-02-28', 'category_3', 35],
['1','2021-03-31', 'category_1', 12],
['1','2021-03-31', 'category_2', 58],
['1','2021-03-31', 'category_3', 23],
['2', '2021-01-31', 'category_1', 29],
['2', '2021-01-31', 'category_2', 66],
['2', '2021-01-31', 'category_3', 22],
['2', '2021-02-28', 'category_1', 53],
['2', '2021-02-28', 'category_2', 71],
['2', '2021-02-28', 'category_3', 32],
['2','2021-03-31', 'category_1', 19],
['2','2021-03-31', 'category_2', 2],
['2','2021-03-31', 'category_3', 99],
['3', '2021-02-28', 'category_1', 53],
['3', '2021-02-28', 'category_2', 71],
['3','2021-03-31', 'category_1', 19],
['3','2021-03-31', 'category_2', 2],
['3','2021-03-31', 'category_3', 99],
['3','2021-03-31', 'category_4', 39]],
columns=['Account', 'Date', 'category', 'Amount'])
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id="account", type="string", placeholder="Enter Account"),
DataTable(id='figure_1',
style_cell_conditional=[{'if': {'column_id': c}, 'textAlign': 'center'} for c in [0, 1, 2, 3, 4]],
style_as_list_view=True,
fill_width=True,
style_cell={'font-size': '12px'},
style_header={'display': 'none'},
style_table={'height': '395px', 'overflowY': 'auto'})])
@app.callback(dash.dependencies.Output('figure_1', 'data'),
[dash.dependencies.Input('account', 'value')])
def update_figura_2(account):
df_query = df[df['Account'] == account].copy()
df_query = df_query.groupby(['Account', 'Date', 'category']).agg({'Amount': 'sum'}).reset_index().pivot(values='Amount', columns='Date')
df_query.index = df.loc[df['Account'] == account, 'category'].copy()
df_query.fillna(0, inplace=True)
return df_query.to_dict(orient='records')
if __name__ == '__main__':
app.run_server(debug=False)
所以我想要得到的输出:
但是,当我 运行 代码时,我得到一个空数据框:
我怀疑它必须与回调有关,但我不知道是什么!
我应该在数据表中定义列参数吗?如果是这样,我怎样才能得到回调的列?
如果您查看 DataTable
对象的 documentation,则有 columns
和 data
的参数,但我无法成功修改这两个属性使用回调(如果我弄明白了,我会编辑我的答案)。
我尝试使用以下回调来修改 DataTable 对象的列和数据:
@app.callback([Output('datatable', 'columns'), Output('datatable', 'data')],
[Input('account', 'value')])
def update_table(account):
...
return df_query
...但我无法使其正常工作:即使未引发任何错误,table 也不会显示。我的猜测是一旦创建了 DataTable
对象就无法修改 columns
,这就是回调无法按预期工作的原因。
相反,我们可以使用 html.Div
容器中。
由于每个用户输入产生的 DataFrame df_query
是按类别索引的,因此我们需要注意如何使用 html.Tr
和 html.Th
构建 table dash_html_components 库中的对象。我们可以遍历 DataFrame 的每一行,添加索引值,然后是该行的剩余值。
import pandas as pd
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components import Div
import dash_table_experiments as dt
from dash_table import DataTable
from dash.dependencies import Input, Output
df = pd.DataFrame([['1', '2021-01-31', 'category_1', 20],
['1', '2021-01-31', 'category_3', 12],
['1', '2021-02-28', 'category_1', 35],
['1', '2021-02-28', 'category_2', 17],
['1', '2021-02-28', 'category_3', 35],
['1','2021-03-31', 'category_1', 12],
['1','2021-03-31', 'category_2', 58],
['1','2021-03-31', 'category_3', 23],
['2', '2021-01-31', 'category_1', 29],
['2', '2021-01-31', 'category_2', 66],
['2', '2021-01-31', 'category_3', 22],
['2', '2021-02-28', 'category_1', 53],
['2', '2021-02-28', 'category_2', 71],
['2', '2021-02-28', 'category_3', 32],
['2','2021-03-31', 'category_1', 19],
['2','2021-03-31', 'category_2', 2],
['2','2021-03-31', 'category_3', 99],
['3', '2021-02-28', 'category_1', 53],
['3', '2021-02-28', 'category_2', 71],
['3','2021-03-31', 'category_1', 19],
['3','2021-03-31', 'category_2', 2],
['3','2021-03-31', 'category_3', 99],
['3','2021-03-31', 'category_4', 39]],
columns=['Account', 'Date', 'category', 'Amount'])
## construct a table with variable number of columns
def generate_table(df, max_rows=100):
return html.Table(
# Header
[html.Tr([html.Th(df.columns.name)] + [html.Th(col) for col in df.columns])] +
# Body
[html.Tr([html.Th(df.index.name)])] +
[html.Tr([html.Td(df.index[i])] + [
html.Td(df.iloc[i][col]) for col in df.columns
]) for i in range(min(len(df), max_rows))]
)
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
children=[
dcc.Input(id="account", type="text", placeholder="Enter Account"),
html.Div(id='table-container')
])
@app.callback(Output('table-container', 'children'),
[Input('account', 'value')])
def update_table(account):
df_query = df[df['Account'] == account].copy()
df_query = df_query.groupby(['Account', 'Date', 'category']).agg({'Amount': 'sum'}).reset_index().pivot(values='Amount', columns='Date')
df_query.index = df.loc[df['Account'] == account, 'category'].copy()
df_query.fillna(0, inplace=True)
# print(df_query.to_dict(orient='records'))
return generate_table(df_query)
if __name__ == '__main__':
app.run_server(debug=True)
为了使 table 看起来更漂亮一些,您可以使用一些 css 来交替行颜色。在你 运行 你的 dash 应用程序 python 文件所在的同一目录中,创建一个名为 assets
的文件夹并创建一个名为 style.css
的新文件,其中包含以下内容:
tr:nth-child(even) {background: #CCC}
tr:nth-child(odd) {background: #FFF}
结果如下:
我找到了一个解决方法,您不必像 Derek 的回答那样通过它的 html 组件手动构建 table。
import pandas as pd
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components import Div
from dash_table import DataTable
from dash.dependencies import Input, Output
df = pd.DataFrame([['1', '2021-01-31', 'category_1', 20],
['1', '2021-01-31', 'category_3', 12],
['1', '2021-02-28', 'category_1', 35],
['1', '2021-02-28', 'category_2', 17],
['1', '2021-02-28', 'category_3', 35],
['1','2021-03-31', 'category_1', 12],
['1','2021-03-31', 'category_2', 58],
['1','2021-03-31', 'category_3', 23],
['2', '2021-01-31', 'category_1', 29],
['2', '2021-01-31', 'category_2', 66],
['2', '2021-01-31', 'category_3', 22],
['2', '2021-02-28', 'category_1', 53],
['2', '2021-02-28', 'category_2', 71],
['2', '2021-02-28', 'category_3', 32],
['2','2021-03-31', 'category_1', 19],
['2','2021-03-31', 'category_2', 2],
['2','2021-03-31', 'category_3', 99],
['3', '2021-02-28', 'category_1', 53],
['3', '2021-02-28', 'category_2', 71],
['3','2021-03-31', 'category_1', 19],
['3','2021-03-31', 'category_2', 2],
['3','2021-03-31', 'category_3', 99],
['3','2021-03-31', 'category_4', 39]],
columns=['Account', 'Date', 'category', 'Amount'])
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id="account", type="string", placeholder="Enter Account"),
html.Div(id='figure_1')
])
@app.callback(Output('figure_1', 'children'),
[Input('account', 'value')])
def update_figura_2(account):
df_query = df[df['Account'] == account].copy()
df_query = df_query.groupby(['Account', 'Date', 'category']).agg({'Amount': 'sum'}).reset_index().pivot(values='Amount', columns='Date')
df_query.index = df.loc[df['Account'] == account, 'category'].copy()
df_query.fillna(0, inplace=True)
return [DataTable(columns=[{"name": i, "id": i} for i in df_query.columns],
data=df_query.to_dict('records'),
style_as_list_view=True,
fill_width=True,
style_cell={'font-size': '12px'},
style_header={'display': 'none'},
style_table={'height': '395px', 'overflowY': 'auto'})]
if __name__ == '__main__':
app.run_server(debug=False)
其中的逻辑是在回调中创建 DataTable 图形并将其作为图形的子图形返回,因此返回的图形将按您需要的 columns/values 帐户进行过滤。