Частичные цепочки обратных вызовов с использованием сюжетного тире

Я пытаюсь фильтровать данные, используя несколько раскрывающихся списков на информационной панели. Всего существует 5 вариантов раскрывающегося списка. Я хочу, чтобы первые три работали независимо, а последние два должны быть связаны в обе стороны с первыми тремя.

В частности, функции, которые я собираюсь реализовать:

  1. Начальной отправной точкой всегда должно быть значение по умолчанию для всех значений.

  2. Первые 3 опции (Год, Сезон и Месяц) должны действовать независимо. Например, к выводу можно добавить любую комбинацию из этих трех. Если выбран один элемент, выходные данные должны быть обновлены с использованием этих значений. Однако если элемент выбран из другого раскрывающегося списка, эти значения должны быть добавлены в выходные данные. Пример ниже в i).

  3. Варианты 4–5 (временные и точные) должны быть связаны в обе стороны с первыми тремя опциями раскрывающегося списка (Год, Сезон и Месяц). Это должно быть обратимо или в обоих направлениях. Если выбран один из первых трех вариантов раскрывающегося списка, выходные данные таблицы должны быть обновлены этими значениями, а раскрывающиеся списки должны быть уменьшены, чтобы пользователь мог выбирать только из этих значений. Пример ниже в ii).

Привести конкретные примеры;

i) 2012 выбран из года в первом раскрывающемся списке. В выводе таблицы отображаются соответствующие значения. Пользователь должен иметь возможность выбирать любые последующие значения в раскрывающемся списке «Год» (функциональном). Однако, если пользователь хочет также увидеть значения Spr из второго раскрывающегося списка, эти данные следует добавить к выходным данным.

ii) Для 4–5 вариантов раскрывающегося списка, которые должны быть связаны с первыми 3, если в параметре temp выбраны «Горячий» и «Мягкий», а в «prec» выбран «Влажный», тогда раскрывающиеся списки в первых трех вариантах должны быть сокращены до: Год = 2013, 2015 г.; Сезон = Spring, Осень; Месяц = ​​апрель, июнь, октябрь, декабрь.

import pandas as pd
from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
from itertools import cycle
import random

Year = cycle(['2012','2013','2014','2015'])
Season = cycle(['Win','Spr','Sum','Fall'])
Month = cycle(['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'])
temp_group = cycle(['Hot','Cold','Mild'])
prec_group = cycle(['Dry','Wet'])

df = pd.DataFrame(index = range(20))

df['option1'] = [next(Year) for count in range(df.shape[0])]
df['option2'] = [next(Season) for count in range(df.shape[0])]
df['option3'] = [next(Month) for count in range(df.shape[0])]
df['option4'] = [next(temp_group) for count in range(df.shape[0])]
df['option5'] = [next(prec_group) for count in range(df.shape[0])]

option1_list = sorted(df['option1'].unique().tolist())
option2_list = df['option2'].unique().tolist()
option3_list = df['option3'].unique().tolist()
option4_list = sorted(df['option4'].unique().tolist())
option5_list = sorted(df['option5'].unique().tolist())

app = Dash(__name__)

app.layout = html.Div([
    dbc.Card(
        dbc.CardBody([
            dbc.Row([
                dbc.Col([
                    html.P("Option 1"),
                        html.Div([
                                dcc.Dropdown(id='option1_dropdown',
                                                 options=option1_list,
                                                 value=[],
                                                 placeholder='All',
                                                 multi=True,
                                                 clearable=True),
                                ],
                                style = {'width': '100%', 'display': 'inline-block'})
                ]),
                dbc.Col([
                    html.P("Option 2"),
                        html.Div([
                                dcc.Dropdown(id='option2_dropdown',
                                                 options=option2_list,
                                                 value=[],
                                                 placeholder='All',
                                                 multi=True,
                                                 clearable=True),
                                ],
                                style = {'width': '100%', 'display': 'inline-block'})
                ]),
                dbc.Col([
                    html.P("Option 3"),
                        html.Div([
                                dcc.Dropdown(id='option3_dropdown',
                                                 options=option3_list,
                                                 value=[],
                                                 placeholder='All',
                                                 multi=True,
                                                 clearable=True),
                                ],
                                style = {'width': '100%', 'display': 'inline-block'})
                ]),
                dbc.Col([
                    html.P("Option 4"),
                        html.Div([
                                dcc.Dropdown(id='option4_dropdown',
                                                 options=option4_list,
                                                 value=[],
                                                 placeholder='All',
                                                 multi=True,
                                                 clearable=True),
                                ],
                                style = {'width': '100%', 'display': 'inline-block'})
                ]),
                dbc.Col([
                    html.P("Option 5"),
                        html.Div([
                                dcc.Dropdown(id='option5_dropdown',
                                                 options=option5_list,
                                                 value=[],
                                                 placeholder='All',
                                                 multi=True,
                                                 clearable=True),
                                ],
                                style = {'width': '100%', 'display': 'inline-block'})
                ]),
            ], align='center'),
        ]), color='dark'
    ),
    dbc.Card(
        dbc.CardBody([
            dbc.Row([
                    html.Div([
                        html.Div(id='dd-output-container')
                    ])
            ], align='center'),
        ]), color='dark'
    ),
    dbc.Card(
        dbc.CardBody([
            dbc.Row([
                    html.Div([
                        dash_table.DataTable(
                            id='table_container',
                            data=df.to_dict('records')
                        )
                    ])
            ], align='center'),
        ]), color='dark'
    )
])

@app.callback(
    Output('table_container', 'data'),
    [Input('option1_dropdown', 'value'),
     Input('option2_dropdown', 'value'),
     Input('option3_dropdown', 'value'),
     Input('option4_dropdown', 'value'),
     Input('option5_dropdown', 'value')
     ])
 
def set_dropdown_options(value1, value2, value3, value4, value5):
    if not value1 or value1 == 'All':
        value1 = option1_list
    if not value2 or value2 == 'All':
        value2 = option2_list
    if not value3 or value3 == 'All':
        value3 = option3_list
    if not value4 or value4 == 'All':
        value4 = option4_list
    if not value5 or value5 == 'All':
        value5 = option5_list
    
    ddf = df.query('option1 == @value1 and '
                   'option2 == @value2 and '
                   'option3 == @value3 and '
                   'option4 == @value4 and '
                   'option5 == @value5',
                   engine='python')
    
    return ddf.to_dict('records')

# ====== Using this as a way to view the selections
@app.callback(
    Output('dd-output-container', 'children'),
    [Input('option1_dropdown', 'value'),
     Input('option2_dropdown', 'value'),
     Input('option3_dropdown', 'value'),
     Input('option4_dropdown', 'value'),
     Input('option5_dropdown', 'value')
     ])

def selection(value1, value2, value3, value4, value5):
    #  If value lists are empty or equal to the default of 'All', use the initial df values
    if not value1 or value1 == 'All':
        value1 = option1_list
    if not value2 or value2 == 'All':
        value2 = option2_list
    if not value3 or value3 == 'All':
        value3 = option3_list
    if not value4 or value4 == 'All':
        value4 = option4_list
    if not value5 or value5 == 'All':
        value5 = option5_list
    
    ddf = df.query('option1 == @value1 and '
                   'option2 == @value2 and '
                   'option3 == @value3 and '
                   'option4 == @value4 and '
                   'option5 == @value5',
                   engine='python')    

    return 

if __name__ == '__main__':
    app.run_server(debug=True, dev_tools_hot_reload = False)

Редактировать 2:

Есть ли способ включить исходные имена столбцов без преобразования в целочисленный суффикс?

Year = cycle(["2012", "2013", "2014", "2015"])
Season = cycle(["Win", "Spr", "Sum", "Fall"])
Month = cycle(
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
)
temp_group = cycle(["Hot", "Cold", "Mild"])
prec_group = cycle(["Dry", "Wet"])

df = pd.DataFrame(index=range(20))

df["Year"] = [next(Year) for count in range(df.shape[0])]
df["Season"] = [next(Season) for count in range(df.shape[0])]
df["Month"] = [next(Month) for count in range(df.shape[0])]
df["Temp"] = [next(temp_group) for count in range(df.shape[0])]
df["Prec"] = [next(prec_group) for count in range(df.shape[0])]

Year_list = sorted(df["Year"].unique().tolist())
Season_list = df["Season"].unique().tolist()
Month_list = df["Month"].unique().tolist()
Temp_list = sorted(df["Temp"].unique().tolist())
Prec_list = sorted(df["Prec"].unique().tolist())

df = df.rename(columns = {'Year':'option1',
                     'Season':'option2',
                     'Month':'option3',
                     'Temp':'option4',
                     'Prec':'option5'})

app = Dash(__name__)

app.layout = html.Div(
    [
        dbc.Card(
            dbc.CardBody(
                [
                    dbc.Row(
                        [
                            dbc.Col(
                                [
                                    html.P("Year"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                            id = "Year_dropdown",
                                            options=Year_list,
                                            value=[],
                                            placeholder = "All",
                                            multi=True,
                                            clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Season"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                            id = "Season_dropdown",
                                            options=Season_list,
                                            value=[],
                                            placeholder = "All",
                                            multi=True,
                                            clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Month"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                            id = "Month_dropdown",
                                            options=Month_list,
                                            value=[],
                                            placeholder = "All",
                                            multi=True,
                                            clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Temp"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                            id = "Temp_dropdown",
                                            options=Temp_list,
                                            value=[],
                                            placeholder = "All",
                                            multi=True,
                                            clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Prec"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                            id = "Prec_dropdown",
                                            options=Prec_list,
                                            value=[],
                                            placeholder = "All",
                                            multi=True,
                                            clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                        ],
                        align = "center",
                    ),
                ]
            ),
            color = "dark",
        ),
        dbc.Card(
            dbc.CardBody(
                [
                    dbc.Row(
                        [html.Div([html.Div(id = "dd-output-container")])], align = "center"
                    ),
                ]
            ),
            color = "dark",
        ),
        dbc.Card(
            dbc.CardBody(
                [
                    dbc.Row(
                        [
                            html.Div(
                                [
                                    dash_table.DataTable(
                                        id = "table_container", data=df.to_dict("records")
                                    )
                                ]
                            )
                        ],
                        align = "center",
                    ),
                ]
            ),
            color = "dark",
        ),
    ]
)


df = df.rename(columns = {'Year':'option1',
                     'Season':'option2',
                     'Month':'option3',
                     'Temp':'option4',
                     'Prec':'option5'})

def construct_query(filter_values):
    additive_clauses = list()
    subtractive_clauses = list()

    for i, filter_value in enumerate(filter_values):
        if filter_value and filter_value != "All":

            clause = f"option{i + 1} == @value{i + 1}"
        
            if i <= 3:
                additive_clauses.append(clause)
            else:
                subtractive_clauses.append(clause)

    if len(additive_clauses) > 0 or len(subtractive_clauses) > 0:
        additive_section = " or ".join(additive_clauses)
        subtractive_clauses = " and ".join(subtractive_clauses)

        if additive_section and subtractive_clauses:
            query = f"({additive_section}) and {subtractive_clauses}"
        else:
            query = additive_section or subtractive_clauses

        return query


@app.callback(
    [
        Output("Year_dropdown", "options"),
        Output("Season_dropdown", "options"),
        Output("Month_dropdown", "options"),
    ],
    [
        Input("Temp_dropdown", "value"),
        Input("Prec_dropdown", "value"),
    ],
 )
def update_additive_options(value4, value5):

    query = None

    option4_query = "option4 == @value4"
    option5_query = "option5 == @value5"

    if value4 and value4 != "All" and value5 and value5 != "All":
        query = f"{option4_query} and {option5_query}"
    elif value4 and value4 != "All":
        query = option4_query
    elif value5 and value5 != "All":
        query = option5_query

    if query:
        df_filtered = df.query(
            query,
            engine = "python",
        )
    else:
        df_filtered = df

    return (
        sorted(df_filtered["option1"].unique().tolist()),
        df_filtered["option2"].unique().tolist(),
        df_filtered["option3"].unique().tolist(),
    )


@app.callback(
    [Output("Temp_dropdown", "options"), Output("Prec_dropdown", "options")],
    [
        Input("Year_dropdown", "options"),
        Input("Season_dropdown", "options"),
        Input("Month_dropdown", "options"),
    ],
)
def update_subtractive_options(value1, value2, value3):

    query = None
    additive_clauses = []
    for i, filter_value in enumerate([value1, value2, value3]):
        if filter_value and filter_value != "All":
            clause = f"option{i + 1} == @value{i + 1}"
       
            additive_clauses.append(clause)

    if len(additive_clauses) > 0:
        query = " or ".join(additive_clauses)

    if query:
        df_filtered = df.query(
            query,
            engine = "python",
        )
    else:
        df_filtered = df

    return (
        sorted(df_filtered["option4"].unique().tolist()),
        sorted(df_filtered["option5"].unique().tolist()),
    )


@app.callback(
    Output("table_container", "data"),
    [
        Input("Year_dropdown", "value"),
        Input("Season_dropdown", "value"),
        Input("Month_dropdown", "value"),
        Input("Temp_dropdown", "value"),
        Input("Prec_dropdown", "value"),
    ],
)

def update_table(value1, value2, value3, value4, value5):

    query = construct_query(filter_values=[value1, value2, value3, value4, value5])

    if query:
        df_filtered = df.query(
            query,
            engine = "python",
        )
    else:
        df_filtered = df

    return df_filtered.to_dict("records")


# ====== Using this as a way to view the selections
@app.callback(
    Output("dd-output-container", "children"),
    [
        Input("Year_dropdown", "value"),
        Input("Season_dropdown", "value"),
        Input("Month_dropdown", "value"),
        Input("Temp_dropdown", "value"),
        Input("Prec_dropdown", "value"),
    ],
)
def selection(value1, value2, value3, value4, value5):
    #  If value lists are empty or equal to the default of 'All', use the initial df values
    if not value1 or value1 == "All":
        value1 = Year_list
    if not value2 or value2 == "All":
        value2 = Season_list
    if not value3 or value3 == "All":
        value3 = Month_list
    if not value4 or value4 == "All":
        value4 = Temp_list
    if not value5 or value5 == "All":
        value5 = Prec_list

    ddf = df.query(
        "option1 == @value1 and "
        "option2 == @value2 and "
        "option3 == @value3 and "
        "option4 == @value4 and "
        "option5 == @value5",
        engine = "python",
    )

    return

if __name__ == "__main__":
    app.run_server(debug=True, dev_tools_hot_reload=False)
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
157
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Этого можно добиться с помощью сюжетного тире. Хитрость заключается в том, чтобы использовать операторы or между первыми тремя фильтрами, чтобы сделать их аддитивными, и операторы and между двумя последними, чтобы сделать их вычитающими. Первые три варианта необходимо решить как один блок, прежде чем включать последние два варианта.

Пример структуры запроса: (option1 == @value1 or option2 == @value2 or option3 == @value3) and option4 == @value4 and option5 == @value5

Я решил построить запрос программно на основе того, какие фильтры имеют значения, чтобы логика or работала правильно. См. функцию construct_query() в примере ниже.

def construct_query(filter_values):
    additive_clauses = list()
    subtractive_clauses = list()

    for i, filter_value in enumerate(filter_values):
        if filter_value and filter_value != "All":
            clause = f"option{i + 1} == @value{i + 1}"
            if i <= 3:
                additive_clauses.append(clause)
            else:
                subtractive_clauses.append(clause)

    if len(additive_clauses) > 0 or len(subtractive_clauses) > 0:
        additive_section = " or ".join(additive_clauses)
        subtractive_clauses = " and ".join(subtractive_clauses)

        if additive_section and subtractive_clauses:
            query = f"({additive_section}) and {subtractive_clauses}"
        else:
            query = additive_section or subtractive_clauses

        return query

Другая проблема — избежать создания циклических обратных вызовов, которые имеют одинаковые входные и выходные компоненты. Один из способов добиться этого — разбить большие обратные вызовы на несколько отдельных обратных вызовов, чтобы входные и выходные данные не были циклическими. В приведенном ниже примере я разделил обновление первых трех раскрывающихся списков на update_additive_options(), а последних двух раскрывающихся списков на update_subtractive_options(). Plotly также описывает другой способ управления циклическими обратными вызовами в своих приложениях. Документация по расширенным обратным вызовам с контекстной функциональностью.

Пример я: Пример 2:

Вот полная версия моего кода:

import pandas as pd
from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
from itertools import cycle
import random

Year = cycle(["2012", "2013", "2014", "2015"])
Season = cycle(["Win", "Spr", "Sum", "Fall"])
Month = cycle(
    ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
)
temp_group = cycle(["Hot", "Cold", "Mild"])
prec_group = cycle(["Dry", "Wet"])

df = pd.DataFrame(index=range(20))

df["option1"] = [next(Year) for count in range(df.shape[0])]
df["option2"] = [next(Season) for count in range(df.shape[0])]
df["option3"] = [next(Month) for count in range(df.shape[0])]
df["option4"] = [next(temp_group) for count in range(df.shape[0])]
df["option5"] = [next(prec_group) for count in range(df.shape[0])]

option1_list = sorted(df["option1"].unique().tolist())
option2_list = df["option2"].unique().tolist()
option3_list = df["option3"].unique().tolist()
option4_list = sorted(df["option4"].unique().tolist())
option5_list = sorted(df["option5"].unique().tolist())

app = Dash(__name__)

app.layout = html.Div(
    [
        dbc.Card(
            dbc.CardBody(
                [
                    dbc.Row(
                        [
                            dbc.Col(
                                [
                                    html.P("Option 1"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                                id = "option1_dropdown",
                                                options=option1_list,
                                                value=[],
                                                placeholder = "All",
                                                multi=True,
                                                clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Option 2"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                                id = "option2_dropdown",
                                                options=option2_list,
                                                value=[],
                                                placeholder = "All",
                                                multi=True,
                                                clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Option 3"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                                id = "option3_dropdown",
                                                options=option3_list,
                                                value=[],
                                                placeholder = "All",
                                                multi=True,
                                                clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Option 4"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                                id = "option4_dropdown",
                                                options=option4_list,
                                                value=[],
                                                placeholder = "All",
                                                multi=True,
                                                clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                            dbc.Col(
                                [
                                    html.P("Option 5"),
                                    html.Div(
                                        [
                                            dcc.Dropdown(
                                                id = "option5_dropdown",
                                                options=option5_list,
                                                value=[],
                                                placeholder = "All",
                                                multi=True,
                                                clearable=True,
                                            ),
                                        ],
                                        style = {
                                            "width": "100%",
                                            "display": "inline-block",
                                        },
                                    ),
                                ]
                            ),
                        ],
                        align = "center",
                    ),
                ]
            ),
            color = "dark",
        ),
        dbc.Card(
            dbc.CardBody(
                [
                    dbc.Row(
                        [html.Div([html.Div(id = "dd-output-container")])], align = "center"
                    ),
                ]
            ),
            color = "dark",
        ),
        dbc.Card(
            dbc.CardBody(
                [
                    dbc.Row(
                        [
                            html.Div(
                                [
                                    dash_table.DataTable(
                                        id = "table_container", data=df.to_dict("records")
                                    )
                                ]
                            )
                        ],
                        align = "center",
                    ),
                ]
            ),
            color = "dark",
        ),
    ]
)


def construct_query(filter_values):
    additive_clauses = list()
    subtractive_clauses = list()

    for i, filter_value in enumerate(filter_values):
        if filter_value and filter_value != "All":
            clause = f"option{i + 1} == @value{i + 1}"
            if i <= 3:
                additive_clauses.append(clause)
            else:
                subtractive_clauses.append(clause)

    if len(additive_clauses) > 0 or len(subtractive_clauses) > 0:
        additive_section = " or ".join(additive_clauses)
        subtractive_clauses = " and ".join(subtractive_clauses)

        if additive_section and subtractive_clauses:
            query = f"({additive_section}) and {subtractive_clauses}"
        else:
            query = additive_section or subtractive_clauses

        return query


@app.callback(
    [
        Output("option1_dropdown", "options"),
        Output("option2_dropdown", "options"),
        Output("option3_dropdown", "options"),
    ],
    [
        Input("option4_dropdown", "value"),
        Input("option5_dropdown", "value"),
    ],
)
def update_additive_options(value4, value5):

    query = None

    option4_query = "option4 == @value4"
    option5_query = "option5 == @value5"

    if value4 and value4 != "All" and value5 and value5 != "All":
        query = f"{option4_query} and {option5_query}"
    elif value4 and value4 != "All":
        query = option4_query
    elif value5 and value5 != "All":
        query = option5_query

    if query:
        df_filtered = df.query(
            query,
            engine = "python",
        )
    else:
        df_filtered = df

    return (
        sorted(df_filtered["option1"].unique().tolist()),
        df_filtered["option2"].unique().tolist(),
        df_filtered["option3"].unique().tolist(),
    )


@app.callback(
    [Output("option4_dropdown", "options"), Output("option5_dropdown", "options")],
    [
        Input("option1_dropdown", "value"),
        Input("option2_dropdown", "value"),
        Input("option3_dropdown", "value"),
    ],
)
def update_subtractive_options(value1, value2, value3):

    query = None
    additive_clauses = []
    for i, filter_value in enumerate([value1, value2, value3]):
        if filter_value and filter_value != "All":
            clause = f"option{i + 1} == @value{i + 1}"
            additive_clauses.append(clause)

    if len(additive_clauses) > 0:
        query = " or ".join(additive_clauses)

    if query:
        df_filtered = df.query(
            query,
            engine = "python",
        )
    else:
        df_filtered = df

    return (
        sorted(df_filtered["option4"].unique().tolist()),
        sorted(df_filtered["option5"].unique().tolist()),
    )


@app.callback(
    Output("table_container", "data"),
    [
        Input("option1_dropdown", "value"),
        Input("option2_dropdown", "value"),
        Input("option3_dropdown", "value"),
        Input("option4_dropdown", "value"),
        Input("option5_dropdown", "value"),
    ],
)
def update_table(value1, value2, value3, value4, value5):

    query = construct_query(filter_values=[value1, value2, value3, value4, value5])

    if query:
        df_filtered = df.query(
            query,
            engine = "python",
        )
    else:
        df_filtered = df

    return df_filtered.to_dict("records")


# ====== Using this as a way to view the selections
@app.callback(
    Output("dd-output-container", "children"),
    [
        Input("option1_dropdown", "value"),
        Input("option2_dropdown", "value"),
        Input("option3_dropdown", "value"),
        Input("option4_dropdown", "value"),
        Input("option5_dropdown", "value"),
    ],
)
def selection(value1, value2, value3, value4, value5):
    #  If value lists are empty or equal to the default of 'All', use the initial df values
    if not value1 or value1 == "All":
        value1 = option1_list
    if not value2 or value2 == "All":
        value2 = option2_list
    if not value3 or value3 == "All":
        value3 = option3_list
    if not value4 or value4 == "All":
        value4 = option4_list
    if not value5 or value5 == "All":
        value5 = option5_list

    ddf = df.query(
        "option1 == @value1 and "
        "option2 == @value2 and "
        "option3 == @value3 and "
        "option4 == @value4 and "
        "option5 == @value5",
        engine = "python",
    )

    return


if __name__ == "__main__":
    app.run_server(debug=True, dev_tools_hot_reload=False)

Можно ли реализовать тот же подход без целого числа i? Например, если опция (x) будет заменена на Год, Сезон, Месяц, Темп. процент?

tonydanza123 23.07.2024 06:29

Да, это возможно. Я использовал переменную i для простого примера, поскольку имена столбцов были последовательными. Вместо этого вы можете перебирать имена столбцов в фрейме данных или определить список имен столбцов, которые вы хотите использовать в качестве фильтров.

nhorner 26.07.2024 18:44

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