Could you explain, what this app is supposed to do? Right now you are changing the Status from Offline to Online in n_intervals if I understand correctly.
EDIT: I don’t think you can make this work even with pattern matching callbacks. The problem is, that you are constantly recreating the table content instead of hiding the information based on your drop down.
Here is a quick & dirty
prototype you might consider as starting point. I changed a lot of your initial code, so I’m not even sure, if it meets your needs. Basically instead of recreating the table each time, I hide rows depending on the drop down selection. Pattern matching callbacks are not necessary in this case, but I included them to show how the syntax would look like.
import dash
from dash import html, dcc, Input, Output, ALL, ctx
import dash_bootstrap_components as dbc
import pandas as pd
import uuid
data = {
"Location": ["Europe", "Europe", "Asia", "Europe", "America", "Asia", "Europe"],
"Name": [f"Test-PC-{number}" for number in range(7)],
"Status": ["Online", "Offline", "Online", "Offline", "Online", "Offline", "Online"],
}
machines = pd.DataFrame(data)
locations = machines.Location.unique()
machine_names = machines.Name.unique()
initial_state = {name: state for name, state in zip(machine_names, machines.Status)}
dropdown = dbc.DropdownMenu(
id="location_selector",
label="Location",
children=[dbc.DropdownMenuItem(location, id=location) for location in locations]
)
table_header = [
html.Thead(html.Tr(
[html.Th("Name"), html.Th("Status")]))
]
def extract_indices(m_names):
return [int(num[-1]) for num in m_names]
def all_machines():
table_body = create_rows(machine_names)
return table_header + table_body
def filtered_by(location):
return machines.Name.loc[(machines['Location'] == location)]
def create_rows(m_list):
# extract index from name
indices = extract_indices(m_list)
# set variable
rows = []
for idx, name in zip(indices, m_list):
row = html.Tr(
id={'type': 'row', 'index': idx},
children=[
html.Td(name, id={'type': 'Test-PC-', 'index': idx}),
html.Td(name, id={'type': 'status_Test-PC-', 'index': idx})
]
)
rows.append(row)
table_body = [html.Tbody(rows)]
return table_body
# create table
table_content = all_machines()
table = dbc.Table(table_content, id="summary_table", bordered=True, hover=True, striped=True)
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(
[
dcc.Interval(id='update', n_intervals=0, interval=1000 * 5),
dropdown,
html.Br(),
table,
]
)
# def swap_status(name):
# idx = machines.index[machines["Name"] == name]
# old = machines.iloc[idx]["Status"]
#
# if old.values[0] == 'Online':
# machines.loc[idx, 'Status'] = "Offline"
# return "Offline"
# else:
# machines.loc[idx, 'Status'] = "Online"
# return "Online"
@app.callback(
Output('location_selector', 'label'),
[Input(location, 'n_clicks') for location in locations]
)
def update_dropdown(*args):
trigger = ctx.triggered_id
if args is None or not trigger:
return "Location"
return trigger
@app.callback(
Output({'type': 'status_Test-PC-', 'index': ALL}, 'children'),
Output({'type': 'row', 'index': ALL}, 'hidden'),
Input('update', 'n_intervals'),
Input("location_selector", 'label'),
)
def update_status(timer, selected_location):
# get the machine names corresponding to the location
names = filtered_by(selected_location)
# index is the last char of the machine name
indices = extract_indices(names)
# set the current status to initial values
current_status = [initial_state[name] for name in machine_names]
# prepare list for row visibility
hide_rows = [True for _ in machine_names]
for idx, item in enumerate(current_status):
if idx in indices:
current_status[idx] = str(uuid.uuid4())
# ^^ assign new value
hide_rows[idx] = False
# this is actually just for startup: show all rows
if selected_location == 'Location':
hide_rows = [False for _ in hide_rows]
return current_status, hide_rows
if __name__ == '__main__':
app.run_server(debug=True)