Dash Python: функция @Callback в макете не вызывается

У меня есть простой фрейм данных:

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). Почему это работает для одного, а не для другого?

Привет, я исправил несколько опечаток в коде (отредактировал его в вопросе), затем протестировал ваш код, и он работает нормально. При посещении 127.0.0.1:8050/tabs я вижу две таблицы - одну с Class1, другую с Class2.

Johnny Cheesecutter 30.07.2024 12:18

Спасибо за редактирование, я далеко от редактора и не могу получить доступ к ссылке. Но решит ли это проблему обратного вызова с get_layout(1)? . Мой исходный код отображал две таблицы, но обратный вызов для get_layout(1) не работал, поэтому print(data) не работала на вкладке 1, когда Numberinput был >0.

Dinks123 30.07.2024 12:33

Я говорил, что не могу воспроизвести ошибку. Не могли бы вы еще раз проверить свой код? Или, может быть, я что-то упускаю.

Johnny Cheesecutter 30.07.2024 12:55

На вкладке 1, если вы установите числовой ввод выше 0, активируется ли строка кода печати (данных) в окне редактора? Он работает для вкладки 2, но не для вкладки 1. Я написал «print(data)», чтобы проверить, работает ли функция обратного вызова. На вкладке 2 работает, на вкладке 1 нет.

Dinks123 30.07.2024 13:02

Вот что я вижу в браузере: postimg.cc/0zs4Qzk3 Вы этого ожидали?

Johnny Cheesecutter 30.07.2024 13:15

Это макет, который я получил в своем исходном коде. Мой вопрос конкретно касается полей Numricinput над каждой таблицей и того, работают ли они. Функция обратного вызова работает для таблицы 2 на вкладке 2, но не для таблицы 1 на вкладке 1. Сегодня вечером я запущу отредактированный вами код, но просто хочу убедиться, что проблема полностью понята. Я также добавил print('CALLBACK WORKING!') к обратному вызову.

Dinks123 30.07.2024 13:22

Это было бы здорово, спасибо. Я не вижу, где updateTableTest подключен к интерфейсу.

Johnny Cheesecutter 30.07.2024 13:30
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
7
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что у вас дублируются 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)
...

Спасибо, это работает, легко ли сложить эти таблицы вместе? Я знаю, как создать новую вкладку под названием «Итого». Это что-то простое, например get_layout(1) + get_layout(2).

Dinks123 31.07.2024 10:37

Другие вопросы по теме