У меня есть гистограмма, подключенная к обратному вызову для фильтрации. Ниже приведена фильтрация по столбцу «Тип».
Проблема: реальные данные, которые я фильтрую, содержат тысячи элементов. Сначала я хочу показать все данные, но не хочу визуализировать все отдельные элементы в раскрывающемся списке (потому что их слишком много). Поэтому я планирую включить функцию «Выбрать все».
Я не думаю, что нынешним подходом можно манипулировать, но я открыт для новых идей.
Вопрос: Если в раскрывающемся меню выбран вариант «Выбрать все», это должен быть единственный видимый значок. Вы не можете иметь все предметы и что-то еще. Если изначально выбран отдельный тип(ы), то если впоследствии будет выбран вариант «Выбрать все», отдельный элемент должен быть удален из раскрывающейся панели.
Пример ниже. Начните с B, затем выбирается Select All, поэтому B следует удалить из раскрывающегося списка.
Кроме того, я вообще сомневаюсь, что это функция, но если Select All стоит, то отдельные типы не могут быть добавлены в раскрывающийся список.
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objs as go
import pandas as pd
df = pd.DataFrame({
'Type': ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],
})
N = 300
df = pd.concat([df] * N, ignore_index=True)
df['TIMESTAMP'] = pd.date_range(start='2024/01/01 07:36', end='2024/01/30 08:38', periods=len(df))
df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['TIMESTAMP']])
df['DATE'] = pd.to_datetime(df['DATE'], format='%Y-%m-%d')
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
filter_box = html.Div(children=[
html.Div(children=[
dcc.Dropdown(
id = 'Type',
options = [
{'label': x, 'value': x} for x in df['Type'].unique()
] + [
{'label': 'Select All', 'value': 'all'}
],
value = 'all',
multi = True,
clearable = True,
style = {'display': 'inline-block','margin':'0.1rem'}
),
], className = "vstack gap-1 h-100",
)
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
dbc.Row([
dbc.Col(html.Div(filter_box),
),
]),
]),
dbc.Col([
dbc.Row([
dcc.Graph(id = 'date-bar-chart'),
]),
])
])
], fluid = True)
@app.callback(
Output('date-bar-chart', 'figure'),
[Input('Type', 'value'),
])
def chart(value_type):
if 'all' in value_type:
value_type = ['all']
else:
value_type = value_type
if value_type == 'all':
dff = df
elif value_type == ['all']:
dff = df
else:
dff = df[df['Type'].isin(value_type)]
df_count = dff.groupby(['DATE','Type'])['DATE'].count().reset_index(name = 'counts')
if df_count.empty == True:
type_fig = go.Figure()
else:
df_count = df_count
type_fig = px.bar(x = df_count['DATE'],
y = df_count['counts'],
color = df_count['Type']
)
return type_fig
if __name__ == '__main__':
app.run_server(debug = True, port = 8052)






Я не очень разбираюсь в Dash, но вы можете попробовать внести пару изменений в объявление dcc.Dropdown, чтобы убедиться, что вы видите «Выбрать все». Во-первых, словарь «Выбрать все» добавлен в конец списка параметра options, а не в начало. Возможно, вы захотите переместить его в начало, чтобы оно появилось. Согласно документации:
Параметры, представленные в виде одного словаря, отображаются в браузере в произвольном порядке. Предоставление списка, содержащего словарь для каждого параметра, гарантирует отображение параметров в указанном порядке.
Во-вторых, у вас есть параметр dcc.Dropdownvalue, настроенный как value = 'Select All', но пример в документации указывает, что для него должно быть установлено значение соответствующего словаря, а не ключа:
dcc.Dropdown(
options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': 'Montreal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'},
],
value='MTL'
)
Следовательно, вы также можете попробовать изменить это на value = 'all'. В итоге:
dcc.Dropdown(
id = 'Type',
options = [
{'label': 'Select All', 'value': 'all'}
] + [
{'label': x, 'value': x} for x in df['Type'].unique()
],
value = 'all',
multi = True,
clearable = True,
style = {'display': 'inline-block','margin':'0.1rem'}
),
Хорошо, это проясняет ситуацию. Если у меня будет время позже, я напишу пример кода; Между тем, эта документация может помочь, если вы хотите попробовать ее.
Обработка выбора в порядке, но вам не хватает обновления компонента Dropdown.
Кроме того, в случае добавления чего-то еще к опции «Выбрать все» вы, вероятно, захотите очистить только выделение, но сохранить график без изменений. Можно отметить, что существуют противоположные случаи, которые заканчиваются одинаковым значением выбора, например. ['A', 'all']. Чтобы отличить их, вам необходимо отслеживать предыдущее состояние, что можно реализовать с помощью компонента dcc.Store.
Они суммируются следующими изменениями:
from dash import no_update
from dash.dependencies import State
SELECT_ALL = 'all' # to avoid string literals in the code
def make_figure(*, select_all=True, selected_values=None):
if select_all:
dff = df # use source data frame
elif selected_values is None:
return go.Figure() # result is empty without filter values
else:
dff = df[df['Type'].isin(selected_values)] # filtered
df_count = dff.groupby(['DATE', 'Type'])['DATE'].count().reset_index(
name='counts')
if df_count.empty:
return go.Figure()
return px.bar(x=df_count['DATE'],
y=df_count['counts'],
color=df_count['Type'])
filter_box = html.Div(children=[
dcc.Store(id='session_select_all_types', data=True, storage_type='session'),
html.Div(children=[
dcc.Dropdown(
...
app.layout = dbc.Container([
...
# Initialize with all types selected
dcc.Graph(id='date-bar-chart',
figure=make_figure(select_all=True)),
@app.callback(
Output('date-bar-chart', 'figure'),
Output('Type', 'value'),
Output('session_select_all_types', 'data'),
Input('Type', 'value'),
State('session_select_all_types', 'data'))
def chart(value_type, select_all_types_previous):
select_all_types = SELECT_ALL in value_type
if select_all_types:
if select_all_types_previous is True:
return (no_update, # you don't want to recreate a valid figure
[SELECT_ALL], # force it to have an only Select all value
no_update) # already True
value_type = [SELECT_ALL]
figure = make_figure(select_all=select_all_types,
selected_values=value_type)
return (figure,
value_type, # update the selection
select_all_types) # update the flag in the session storage
Спасибо. Работает хорошо. Однако есть несколько вопросов. Select All не отображает никаких данных при первом открытии или при обновлении *ЕСЛИ Select All было последним значением, выбранным перед обновлением. all возвращается, но данные на диаграмме не отображаются. Отдельно, насколько сложно было бы отбросить Select All, если бы было выбрано индивидуальное значение? Вместо того, чтобы очищать Select All перед выбором отдельного значения.
О, вы правы, я пропустил значение по умолчанию «Выбрать все». Обновил ответ: переключите значение хранилища по умолчанию на True, сделайте вспомогательный метод для генерации фигур, сразу инициализируйте макет полной фигурой вместо первого обратного вызова.
Что касается второй части, то это лучше другой вопрос. Но это не сложно. Вам необходимо реализовать эту логику: если было выбрано все, а стало выбрано все+, затем нажмите «Выбрать все», если не было «Выбрать все», а стало «Выбрать все+», тогда сделайте так, чтобы оно только выбрало все, в противном случае работайте с выбранными значениями.
Да, спасибо. Я мог бы обратиться к вам за помощью со второй частью. Мне нужно несколько цифр в моем реальном приложении, поэтому я попробую найти путь вперед с помощью вашего метода.
Спасибо, я внес некоторые поправки. Главный вопрос все еще остается в силе, но он стал немного чище.