У меня есть простой фрейм данных:
import pandas as pd
df = pd.DataFrame({'Class1': [1, 2, 3, 4, 5],
'Class2': [6, 7, 8, 9, 10]}
)
Я создал функцию извлечения данных, которая разбивает данные в зависимости от положения столбца.
data_extraction.py
def dataExtraction(arg1):
df = pd.DataFrame({'Class1': [1, 2, 3, 4, 5],
'Class2': [6, 7, 8, 9, 10]}) ## <-- or Import df from somewhere
df = df[[f'Class{arg1}']]
return df
макет.py
import dash_bootstrap_components as dbc
from dash import dcc, html, Input, Output, callback
from dash import Dash, dash_table, State
import dash_daq as daq
import pandas as pd
def update_page(arg1, arg2):
layout = html.Div(children=[
html.H1(f'Class {arg1}'),
daq.NumericInput(
id='numericinput1',
min=0,
max=100,
value=0, ),
html.Br(),
dash_table.DataTable(
id='tableTest',
data=arg2.to_dict('records'),
columns=[{"name": i, "id": i} for i in arg2.columns]),
])
return layout
@callback(
Output('tableTest', 'data'),
Input('numericinput1', 'value'),
State('tableTest', 'data'),
)
def updateTableTest(x,data):
data = pd.DataFrame(data)
if x > 0:
**print(data) # Indicator that shows callback is working**
print("CALLBACK WORKING!!!")
return data.to_dict('records')
return data.to_dict('records')
Я также создал страницу вкладок следующим образом, состоящую из страницы с двумя вкладками. На странице tab_page отображаются вкладки с соответствующим столбцом данных (например, вкладка 1 для столбца 1). Я написал «печать (данные)», чтобы проверить, работает ли обратный вызов в функции макета. На одной вкладке работает, на другой нет.
tab_page.py
import layout as lay
import data_extraction as de
import dash_bootstrap_components as dbc
from dash import html, Dash
import dash
app = Dash()
dash.register_page(__name__,
path='/tabs')
def get_layout(position):
df = de.dataExtraction(position)
layout = lay.update_page(position, df)
return layout
tab1_content = dbc.Card(
dbc.CardBody(
[
**get_layout(1)#<--- CALLBACK NOT WORKING HERE The print(data) is NOT working**
]
),
className = "mt-1",
)
tab2_content = dbc.Card(
dbc.CardBody(
[
get_layout(2) #<--- The print(data) is working
]
),
className = "mt-2",
)
layout = html.Div(children = [
dbc.Tabs(
[
dbc.Tab(tab1_content, label = "1",activeLabelClassName = "text-success"),
dbc.Tab(tab2_content, label = "2",activeLabelClassName = "text-success"),
]
)])
app.layout = [layout]
if __name__ == '__main__':
app.run(debug=True)
Обратный вызов в макете работает для get_layout(2), но не для get_layout(1). Почему это работает для одного, а не для другого?
🤔 А знаете ли вы, что...
Python поддерживает многозадачность и многопоточность.
Проблема в том, что у вас дублируются id в макете. И один обратный вызов не может быть связан с двумя объектами с одинаковыми идентификаторами:
Исправление 1 – удалить повторяющиеся идентификаторы
# layout.py
def update_page(arg1, arg2):
layout = html.Div(children=[
html.H1(f'Class {arg1}'),
daq.NumericInput(
id=f"numericinput{arg1}",
min=0,
max=100,
value=0, ),
html.Br(),
dash_table.DataTable(
id=f"tableTest{arg1}",
data=arg2.to_dict('records'),
columns=[{"name": i, "id": i} for i in arg2.columns]),
])
return layout
Исправление 2 – сделать два обратных вызова, по одному для каждой таблицы.
# layout.py
def create_callback(i):
@callback(
Output(f'tableTest{i}', 'data'),
Input(f'numericinput{i}', 'value'),
State(f'tableTest{i}', 'data'),
)
def updateTableTest(x, data):
data = pd.DataFrame(data)
print(x)
if x > 0:
print(data) # Indicator that shows callback is working
return data.to_dict('records')
return data.to_dict('records')
return updateTableTest
Исправление 3 — инициировать обратные вызовы
# tab_page.py
...
# initiate callbacks:
app.layout = [layout]
lay.create_callback(1)
lay.create_callback(2)
if __name__ == '__main__':
app.run(debug=True)
...