I would like to use the code below in order to allow user to filter columns. The problem i sthat I cannot filter the columns with numerical values. How can I solve this issue? I was thinking to find column type, but it was not in the code
from dash import Dash, dcc, html, Input, Output, dash_table
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
df['id'] = df['country']
df.set_index('id', inplace=True, drop=False)
app = Dash(__name__)
app.layout = html.Div([
dcc.RadioItems(
[{'label': 'Read filter_query', 'value': 'read'}, {'label': 'Write to filter_query', 'value': 'write'}],
'read',
id='filter-query-read-write',
),
html.Br(),
dcc.Input(id='filter-query-input', placeholder='Enter filter query'),
html.Div(id='filter-query-output'),
html.Hr(),
dash_table.DataTable(
id='datatable-advanced-filtering',
columns=[
{'name': i, 'id': i, 'deletable': True} for i in df.columns
# omit the id column
if i != 'id'
],
data=df.to_dict('records'),
editable=True,
page_action='native',
page_size=10,
filter_action="native"
),
html.Hr(),
html.Div(id='datatable-query-structure', style={'whitespace': 'pre'})
])
#app.callback(
Output('filter-query-input', 'style'),
Output('filter-query-output', 'style'),
Input('filter-query-read-write', 'value')
)
def query_input_output(val):
input_style = {'width': '100%'}
output_style = {}
if val == 'read':
input_style.update(display='none')
output_style.update(display='inline-block')
else:
input_style.update(display='inline-block')
output_style.update(display='none')
return input_style, output_style
#app.callback(
Output('datatable-advanced-filtering', 'filter_query'),
Input('filter-query-input', 'value')
)
def write_query(query):
if query is None:
return ''
return query
#app.callback(
Output('filter-query-output', 'children'),
Input('datatable-advanced-filtering', 'filter_query')
)
def read_query(query):
if query is None:
return "No filter query"
return dcc.Markdown('`filter_query = "{}"`'.format(query))
#app.callback(
Output('datatable-query-structure', 'children'),
Input('datatable-advanced-filtering', 'derived_filter_query_structure')
)
def display_query(query):
if query is None:
return ''
return html.Details([
html.Summary('Derived filter query structure'),
html.Div(dcc.Markdown('''```json
{}
```'''.format(json.dumps(query, indent=4))))
])
if __name__ == '__main__':
app.run_server(debug=True)
Is there any way to handle this issue? Alternatively, where is the column type included in this script? I took it from Dash website.
If you want to write your own filter, you should enclose the column name with {}. For example, in order to get the value 708573 from pop column, you should write it as:
{pop} = 708573
But if you write your filter under a specific column, in this case, you only need to write = 708573
Please look in the documentation to familiarize yourself more to the filtering syntax.
Related
I'm trying to make a dashtable and its columns will be change dynamically based on dropdowns value.
Below is my sample code:
import pandas as pd
import numpy as np
import plotly.express as px
import dash
from dash import html
from dash import dcc
from dash.dependencies import Input, Output,State
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
from dash import dash_table
df1 = pd.DataFrame({
'Contract No': ['VN122001','VN122002','VN122003','VN122004','VN122005'],
'Amount': [22071,20775,20841,21891,22395]})
df1 = df1.set_index('Contract No')
df2 = pd.DataFrame({
'Contract No': ['VN122001','VN122002','VN122003','VN122004','VN122005'],
'Cusname': ['A','B','C','D','E'],
'Branch': ['HN','HCM','HP','BN','DN']})
df2 = df2.set_index('Contract No')
app = dash.Dash(__name__,external_stylesheets=[dbc.themes.LUX])
app.layout = html.Div([
dbc.Row([
dbc.Col([
dcc.Dropdown(id='columns_name',placeholder="Columns name", # Dropdown for heatmap color
options=list_column,
value='Cusname',
multi=False,
disabled=False,
clearable=True,
searchable=True)
],width={'size':4,'offset':0,'order':1},style={'padding-top' : 15}),
]),
dbc.Row([
html.Div(
id = 'tableDiv',
className = 'tableDiv'
)
])
])
#app.callback(Output('tableDiv', 'children'),
[Input('columns_name', 'value')])
def update_columns_name(columns):
col_name = df2[[columns]]
df3 = pd.merge(df1, col_name, left_index=True, right_index=True)
df3 = df3.reset_index()
mycolumns = [{'name': i, 'id': i} for i in df3.columns]
return html.Div([
dash_table.DataTable(
id='table',
columns=mycolumns,
data=df3.to_dict("rows")
)
])
if __name__ == "__main__":
app.run_server(debug=False,port=1222)
Actually it is working well but when I try to create Tabs and then return it to Tab, nothing show. Below is my code to create Tab.
app.layout = html.Div([dbc.Tabs(
[dbc.Tab(label="Dashboard", tab_id="dashboard"),
dbc.Tab(label="Table", tab_id="table"),
],
id="tabs",
active_tab="dashboard"),
html.Div(id="tab-content", className="p-4"),
])
#app.callback(
Output("tab-content", "children"),
[Input("tabs", "active_tab")])
def render_tab_content(active_tab):
if active_tab == "dashboard":
return html.Div([dbc.Row([html.H5('Graphs')])])
elif active_tab == "table":
return html.Div([
dbc.Row([
html.Div(id = 'tableDiv',
className = 'tableDiv')
])
])
#app.callback(Output('tableDiv', 'children'),
[Input('columns_name', 'value')])
def update_columns_name(columns):
col_name = df2[[columns]]
df3 = pd.merge(df1, col_name, left_index=True, right_index=True)
df3 = df3.reset_index()
mycolumns = [{'name': i, 'id': i} for i in df3.columns]
return html.Div([
dash_table.DataTable(
id='table',
columns=mycolumns,
data=df3.to_dict("rows"))
])
if __name__ == "__main__":
app.run_server(debug=False,port=1222)
What should I do to fix this issue. Thank you.
This is the error javascript throws back in the browser console:
Object { message: "ID not found in layout", html: "Attempting to connect a callback Output item to component:\n \"tableDiv\"\nbut no components with that id exist in the layout.\n\nIf you are assigning callbacks to components that are\ngenerated by other callbacks (and therefore not in the\ninitial layout), you can suppress this exception by setting\n```suppress_callback_exceptions=True```.\nThis ID was used in the callback(s) for Output(s):\n tableDiv.children" } dash_renderer.v2_1_0m1644023699.min.js:2:84904
Object { message: "ID not found in layout", html: "Attempting to connect a callback Input item to component:\n \"columns_name\"\nbut no components with that id exist in the layout.\n\nIf you are assigning callbacks to components that are\ngenerated by other callbacks (and therefore not in the\ninitial layout), you can suppress this exception by setting\n```suppress_callback_exceptions=True```.\nThis ID was used in the callback(s) for Output(s):\n tableDiv.children" }
As it suggests, you are referring to id components that are generated by another callback (namely, callback render_tab_content generates the tableDiv div and is being referred to by update_column_name). This is a problem, as your tableDiv won't be present when you select the dashboard table but the callback may still be invoked (at least initially which is why you are having an issue to begin with).
It's best to perhaps have the contents of update_column_name combined with render_table_content and generate the column stuff you need through the one callback. You don't really gain anything from splitting into 2 callbacks in this instance, and if you really want, you can abstract the contents of the other callback into a normal function and just call it in render_tab_content. Here is a suggested adaptation:
def update_columns_name(columns):
col_name = df2[[columns]]
df3 = pd.merge(df1, col_name, left_index=True, right_index=True)
df3 = df3.reset_index()
mycolumns = [{'name': i, 'id': i} for i in df3.columns]
return (
html.Div([
dbc.Row([
html.Div([
html.Div([
dash_table.DataTable(
id='table',
columns=mycolumns,
data=df3.to_dict("rows")
)
])
],
id='tableDiv',
className='tableDiv')
])
])
)
#app.callback(
Output("tab-content", "children"),
[Input("tabs", "active_tab")],
[State('columns_name', 'value')]
)
def render_tab_content(active_tab, columns):
print(active_tab, columns)
if active_tab == "dashboard":
return html.Div([dbc.Row([html.H5('Graphs')])])
elif active_tab == "table":
return update_columns_name(columns)
I am creating a search application with Dash by Plotly. I have a main search function for that creates a dataframe for the whole application that is defined as:
def search(term):
with index.searcher() as searcher:
parser = QueryParser("content", index.schema)
myquery = parser.parse(term)
results = searcher.search(myquery, limit=None)
print("Documents Containing ", term, ": ", len(results), "\n")
df = pd.DataFrame([i['date'], i['site'], i['system'], i['ticket'], i.score, i['level'], i['first'], i['last'], i['department'], \
i['detect'], i['code'],i['content'], i['description'], i['owner'], i['ownerGroup'], i['docId']] for i in results)
df.columns=['Reported Date', 'Site', 'System','Ticket ID', 'Score', 'Level', 'First', 'Last', 'Department', \
'Detection', 'Code', 'Content', 'Description', 'Owner', 'Owner Group', 'Document ID']
return df
I want users to be able to filter down search results with filters built into dcc.Dropdown. A couple of them can be hard-coded like so:
dcc.Dropdown(
id='siteFilter',
options=[
{'label': 'ABC', 'value': 'ABC'},
{'label': 'DEF', 'value': 'DEF'},
{'label': 'HIJ', 'value': 'HIJ'},
{'label': 'LMO', 'value': 'LMO'}
],
value=['ABC', 'DEF', 'HIJ', 'LMO'],
multi=True
However, some of the fields I want to filter on contain many options for a search and cannot be hard-coded. I can get the options to work. However, my application will not apply the filter changing when a user changes values. So, I have in my app.layout:
html.Div(dbc.Row([dbc.Col([
html.Label(["System Filter",
dcc.Dropdown(
id='systemFilter',
options='options',
value='All',
multi=True,
)
])
], width = 5)
]))
In my callback, I have tried several different options/combos of Outputs and States to achieve this with no luck. Callback:
#app.callback(
[Output(component_id='outTable', component_property='data'),
Output(component_id='outTable', component_property='columns'),
Output(component_id='commonWords', component_property='children'),
Output(component_id='systemFilter', component_property='options'),
#Output(component_id='systemFilter', component_property='value')
],
[Input(component_id='button', component_property='n_clicks')],
[State('searchId', 'value'),
State('siteFilter', 'value'),
State('detectFilter', 'value'),
State('levelFilter', 'value'),
State('codeFilter', 'value'),
#State(component_id='systemFilter', component_property='value')
])
def tableCreate(n_clicks, searchId, siteFilter, detectFilter, levelFilter, codeFilter):
if n_clicks > 0:
searchFrame = search(searchId)
###################### System Filter #######################################
#print('HERE DLKFSJSLDFKJSLDKJFJLKFDSJLDSKF')
#print(searchFrame['System'].unique())
#global optionsArray
optionsArray = searchFrame['System'].unique()
optionsArray = optionsArray.tolist()
print('Test')
print(optionsArray)
print('Test')
system_filter_options = [{'label': i, 'value': i} for i in optionsArray]
systemFilter = optionsArray
searchFrame = searchFrame[searchFrame['System'].isin(systemFilter)]
# Bunch of other code
searchFrame = searchFrame.drop(columns=['ContentNoStop'])
columns = [{'name': col, 'id': col} for col in searchFrame.columns]
data = searchFrame.to_dict(orient='records')
return data, columns, wordComponent, system_filter_options #, systemFilter
else:
return dash.no_update, dash.no_update, dash.no_update, dash.no_update
Essentially, one of 2 things happens. 1) The values return blank because they are not defined or 2) the options continually override the updated value parameter which I know is caused by the line systemFilter = optionsArray but I cannot seem to figure out a work around for this.
Here is an example image. I would like the results to populate all, but when a user filters by system and only selects a few, all my graphs and tables should update. But everytime, it does not seem to catch that. What am I missing here? How can the dcc.Dropdown selections be applied as a filter dynamically? I cannot and do not want to hard-code all the options
Easier reproduceable example:
I would like the dropdowns options to filter the table. If dog is selected, the table only shows dog.
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
import pandas as pd
from dash.dependencies import Input, Output, State
external_stylesheets = [dbc.themes.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
def createTable():
df = pd.DataFrame({'num_legs': [2, 4, 8, 0],
'num_wings': [2, 0, 0, 0],
'system': ['falcon', 'dog', 'spider', 'fish']},
index=[1, 2, 3, 4])
return df
app.layout = html.Div([
html.Button('Submit and Refresh', id='button', n_clicks=0, className='btn btn-primary'),
dbc.Row([dbc.Col([
html.Label(["System Filter",
dcc.Dropdown(
id='systemFilter',
options='options',
value='All',
multi=True,
)
])
], width = 5)
]),
html.Div([dash_table.DataTable(style_cell={
'whiteSpace': 'normal',
'height': 'auto',
'textAlign': 'left'
},
fill_width=False,
id='outTable',
sort_action="native",
sort_mode="multi",
column_selectable="single",
row_deletable=True,
)
],
) ])
#app.callback(
[Output(component_id='outTable', component_property='data'),
Output(component_id='outTable', component_property='columns'),
Output(component_id='systemFilter', component_property='options'),
#Output(component_id='systemFilter', component_property='value')
],
[Input(component_id='button', component_property='n_clicks')],
[
State(component_id='systemFilter', component_property='value')
])
def tableCreate(n_clicks, systemFilter):
if n_clicks > 0:
searchFrame = createTable()
optionsArray = searchFrame['system'].unique()
optionsArray = optionsArray.tolist()
print('Test')
print(optionsArray)
print('Test')
system_filter_options = [{'label': i, 'value': i} for i in optionsArray]
systemFilter = optionsArray
searchFrame = searchFrame[searchFrame['system'].isin(systemFilter)]
columns = [{'name': col, 'id': col} for col in searchFrame.columns]
data = searchFrame.to_dict(orient='records')
return data, columns, system_filter_options#, systemFilter
if __name__ == '__main__':
app.run_server(debug=False)
I am trying to build a dashboard with Dash. One of the feature of this dashboard is that after dynamically updating dropdowns a user will be able to select multiple options and group them together.
I am able to group options together but when I go to group other options it rewrites my previous changes.
Such as when I group t1 and t2 in Group1 it is done but when I remove these selection from dropdown and select t3 and t4 in Group2 it rewrites my previous group.
Following is my code:
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
import pandas as pd
data = [['tom', 'nick','t1',''], ['tom', 'nick','t2',''], ['tom', 'john','t3',''], ['tom','john','t4','']]
df = pd.DataFrame(data, columns = ['Captain', 'VCaptain', 'Teams','Groups'])
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
colors = {
"graphBackground": "#F5F5F5",
"background": "#ffffff",
"text": "#000000"
}
app.layout = dbc.Container(
[
dbc.Row(
[
dbc.Col(dbc.Card([
dbc.FormGroup([
dbc.Label(html.B("Select Captains from list below:")),
dcc.Dropdown(id="captains",
options=[{'label': i, 'value': i} for i in df['Captain'].unique()],
value=[i for i in df['Captain'].unique()],)
]),
dbc.FormGroup([
dbc.Label(html.B("Select Vice Captains from below:")),
dcc.Dropdown(id="vcaptains")
]
),
dbc.FormGroup([
dbc.Label(html.B("Select Teams which needs to be grouped together:")),
dcc.Dropdown(id="teams",multi = True),
]
),
dbc.FormGroup([
dbc.Label(html.B("Input new group name:")),
dbc.Input(id="group", placeholder="Type group name...", type="text"),
]
),
html.I("Write a Name for the Group of the selected teams.",
style={"color":"#737373", "font-size":"0.8rem"}),
html.Br(),
dbc.Button("Add Group", id="assign", block=False,
outline=True, color="primary", #className = "mr-2",
style = {"margin-right": "10.5rem"}),
html.Br(),
], body = True,
style={"top": "20px",
"left":10,
"height":"900px",
"width": "20rem",
"padding": "2rem 1rem",
"background-color": "#f8f9fa",}
), width=2),
dbc.Col(width = 1),
dbc.Col(id='table',width=6, style={"top":-120})
],
align="center",
),
],fluid=True)
# # Dropdown to filter Captains
# #app.callback(
# Output('captains', 'options'),
# [Input('captains', 'value')])
# def captain_options(value):
# opts=[]
# if value is not None:
# opts = df['Captain'].unique()
# return [{'label': i, 'value': i} for i in opts]
# Dropdown to filter Vice Captains
#app.callback(
Output('vcaptains', 'options'),
[Input('captains', 'value')])
def vice_captain_options(value):
opts=[]
if value is not None:
opts = df[df['Captain'].isin([value])]['VCaptain'].unique()
return [{'label': i, 'value': i} for i in opts]
# Dropdown to filter Vice Captains
#app.callback(
Output('teams','options'),
[Input('captains', 'value'),
Input('vcaptains', 'value')])
def teams_options(captains, vcaptains):
opts=[]
if captains is not None:
opts = df[df['Captain'].isin([captains])]['Teams'].unique()
if vcaptains is not None:
opts = df[df['Captain'].isin([captains]) &
df['VCaptain'].isin([vcaptains])]['Teams'].unique()
return [{'label': i, 'value': i} for i in opts]
#app.callback(
Output('table', 'data'),
[Input('captains', 'value'),
Input('vcaptains', 'value')])
def table(captains, vcaptains):
df1 = df
if captains is not None:
df1 = df[(df['Captain'].isin([captains]))]
if vcaptains is not None:
df1 = df[(df['VCaptain'].isin([vcaptains]))]
if df1 is not None:
return df1.to_dict('records')
#app.callback(
Output('table', 'children'),
[Input('table', 'data'),
Input('assign', 'n_clicks')],
[State('teams', 'value'),
State('group', 'value')])
def table(data,n,teams,group):
df1 = pd.DataFrame.from_dict(data)
changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]
if 'assign' in changed_id:
if teams is not None:
if type(teams)==str:
df1.loc[df1['Teams'].isin([teams]), 'Groups'] = group
else:
df1.loc[df1['Teams'].isin(teams), 'Groups'] = group
if df is not None:
return dash_table.DataTable(data = df1.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df1.columns])
if __name__ == '__main__':
app.run_server(debug=False)
If I've understood your problem correctly, then I think what you're missing is an intermediate step to hold data you've already selected. You could use the store component to do that. The flow would work like this:
Add selections to group 1
Group 1 selections update the Store
Add selections to group 2
Read in the existing Store value, and combine it with group 2 selections, then update the Store with the new combined values
Repeat until all desired selections are made
Something (perhaps a button) triggers the table to update using the data in the Store
I have Dashboard which uses data from Pandas df. It is one table on which I want to provide 2 filters. One for COUNTRY, second for STATE. Below is a code (only problematic part shown) which I am using:
app.layout = html.Div(children=[
html.H4(children='STATISTICS FOR COUNTRY AND STATE'),
dcc.Dropdown(id='dropdown_country', options=[
{'label': i, 'value': i} for i in stats_df.COUNTRY.unique()
], multi=True, placeholder='Filter by COUNTRY...'),
dcc.Dropdown(id='dropdown_state', options=[
{'label': i, 'value': i} for i in stats_df.STATE.unique()
], multi=True, placeholder='Filter by STATE...'),
html.Div(id='table-container')
])
#app.callback(
dash.dependencies.Output('table-container', 'children'),
[dash.dependencies.Input('dropdown_country', 'value'), dash.dependencies.Input('dropdown_state', 'value')])
def display_table(dropdown_country, dropdown_state):
if dropdown_country is None and dropdown_state is None:
return generate_table(stats_df)
stats_dff = stats_df.loc[(stats_df.COUNTRY.str.contains('|'.join(dropdown_country))) | (stats_df.STATE.str.contains('|'.join(dropdown_state)))]
return generate_table(stats_dff)
With below code my Dashboard displays correctly but when I chose value for first filter i.e. COUNTRY it crashes with error:
Callback error updating table-container.children TypeError: can only
join an iterable
Can anyone help to point where is an error? Wit just one filter (COUNTRY or STATE) all works OK.
I figured it out. Function display_table needs to be changed to this:
def display_table(dropdown_country, dropdown_state):
if dropdown_country is None and dropdown_state is None:
return generate_table(stats_df)
if dropdown_country is not None and dropdown_state is not None:
stats_dff = stats_df.loc[(stats_df.COUNTRY.str.contains('|'.join(dropdown_country))) & (stats_df.STATE.str.contains('|'.join(dropdown_state)))]
return generate_table(stats_dff)
if dropdown_country is not None:
stats_dff = stats_df.loc[stats_df.COUNTRY.str.contains('|'.join(dropdown_country))]
return generate_table(stats_dff)
if dropdown_state is not None:
stats_dff = stats_df.loc[stats_df.STATE.str.contains('|'.join(dropdown_state))]
return generate_table(stats_dff)
I cant figure out why my graph isnt updating with the data from the value I have selected. Can somebody please try help.
I've tried to rewrite this many times but I can't seem to get my head around the function which I must write after the app callback and what I should return in this function.
app = dash.Dash()
app.layout = html.Div(children = [
html.H1('Sports PA Dashboard'),
dcc.Dropdown(
id='sport_dropdown',
options=[{'label': i, 'value': i} for i in df.Sport.unique()],
value = df.Sport.unique()),
dcc.Graph(id='age_vs_rank')
])
#app.callback(
dash.dependencies.Output('age_vs_rank', 'figure'),
[dash.dependencies.Input('sport_dropdown', 'value')])
def update_output(selected_sport):
print(selected_sport)
sport = df[df.Sport == selected_sport]
rank = sport['Rank']
age = sport['Age']
dcc.Graph(id='age_vs_rank',
figure={
'data' : [{'x':rank, 'y':age, 'type' : 'bar', 'name' : 'age_vs_rank'}],
'layout' : {
'title' : 'Age vs Rank'
}
})
if __name__ == '__main__':
app.run_server(debug=True)
You can try create div and then fill him with what you want.
Code:
from flask import Flask
import dash
import dash_core_components as dcc
import dash_html_components as html
# if you import in a such way - you can call Input, Output directly
from dash.dependencies import Input, Output
# Create app
app = dash.Dash()
# Specify layout
app.layout = html.Div(children=[
html.H1('Sports PA Dashboard'),
dcc.Dropdown(
id='sport_dropdown',
options=[{'label': i, 'value': i} for i in df.Sport.unique()],
value=df.Sport.unique()),
# Create empty Div container, which you can fill with everything!
html.Div(id='your-plot-here')
])
#app.callback(
# If you stuck to what those values belongs to,
# you can specify them more in details:
# Output(component_id='your_plot_here', component_property='children'),
# instead of:
Output('your_plot_here', 'children'),
[Input('sport_dropdown', 'value')])
def update_output(selected_sport):
"""This function create age_vs_rank graph."""
# selected_sport == value property from sport_dropdown id
print(selected_sport)
sport = df[df.Sport == selected_sport]
rank = sport['Rank']
age = sport['Age']
# return what you want in empty Div container with id 'your_plot_here'
return dcc.Graph(id='age_vs_rank',
figure={'data': [
{'x': rank, 'y': age,
'type': 'bar', 'name': 'age_vs_rank'}
],
'layout': {
'title': 'Age vs Rank'
}
}
)
if __name__ == '__main__':
app.run_server(debug=True)
Try changing the return statement to your update_output function.
So it should look like,
#app.callback(
# If you stuck to what those values belongs to,
# you can specify them more in details:
# Output(component_id='your_plot_here', component_property='children'),
# instead of:
Output('your_plot_here', 'children'),
[Input('sport_dropdown', 'value')])
def update_output(selected_sport):
sport = df[df.Sport == selected_sport]
rank = sport['Rank']
age = sport['Age']
return figure = {'data': #stuff
'layout':#stuff
}
Only add the figure dict because thats the only value thats getting updated.
Sorry if the formatting looks weird, this is my first StackOverflow Answer :)