Related
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.
I can't get this code to run and I am supposed to get a couple of things to work. First, a data table which I managed to get up and get to work. Then I created a few buttons so I can filter the data table. The buttons don't do anything to change the data table, I need to get them to work. Second, I am trying to get a pie chart to work and have it be interactive with the data table. The pie chart does not render. Lastly, I need a geolocation chart that interacts with the data table as well. The data table has a lateral location and a longitude location. geolocation doesn't render either*
from jupyter_plotly_dash import JupyterDash
import dash
import dash_leaflet as dl
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import dash_table as dt
from dash.dependencies import Input, Output, State
import os
import numpy as np
import pandas as pd
from pymongo import MongoClient
from bson.json_util import dumps
# change animal_shelter and AnimalShelter to match your CRUD Python module file name and class name
from AnimalShelter import AnimalShelter
import base64
###########################
# Data Manipulation / Model
###########################
# FIX ME change for your username and password and CRUD Python module name
username = "aacuser"
password = "42213"
shelter = AnimalShelter(username, password)
# class read method must support return of cursor object
df = pd.DataFrame.from_records(shelter.read())
#########################
# Dashboard Layout / View
#########################
app = JupyterDash('SimpleExample')
#FIX ME Add in Grazioso Salvareās logo
image_filename = 'Grazioso Salvare Logo.png' # replace with your own image
encoded_image = base64.b64encode(open(image_filename, 'rb').read())
#FIX ME Place the HTML image tag in the line below into the app.layout code according to your design
#FIX ME Also remember to include a unique identifier such as your name or date
#html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()))
app.layout = html.Div([
html.Div(id='hidden-div', style={'display':'none'}),
html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode())),
html.Center(html.B(html.H1('Willi Blanco CS-340 Dashboard'))),
html.Hr(),
html.Div(
#FIXME Add in code for the interactive filtering options. For example, Radio buttons, drop down, checkboxes, etc.
className='row',
style={'display': 'flex'},
children=[
html.Button(id='submit-button-one',n_clicks=0, children= 'Water Rescue'),
html.Button(id='submit-button-two',n_clicks=0, children= 'Mountain or Wilderness Rescue'),
html.Button(id='submit-button-three',n_clicks=0, children='Disaster Rescue or Individual Tracking'),
html.Button(id='submit-button-four', n_clicks=0, children='reset')
]
),
html.Hr(),
dt.DataTable(
id='datatable-id',
columns=[
{"name": i, "id": i, "deletable": False, "selectable": True} for i in df.columns
],
data=df.to_dict('records'),
#FIXME: Set up the features for your interactive data table to make it user-friendly for your client
#If you completed the Module Six Assignment, you can copy in the code you created here
page_size=100,
style_table={'height':'300px','overflowY':'auto','overflowX':'auto'},
style_header={
'backgroundColor':'rgb(230,230,230)',
'fontWeight':'bold'
},
style_data={
'whiteSpace':'normal',
'height':'auto'
},
#tooltips that we are going to use on the table so that we know what information we are looking at
tooltip ={i: {
'value': i,
'use_with': 'both' # both refers to header & data cell
} for i in df.columns},
tooltip_delay=0,
tooltip_duration = None,
#sorting features that we are going to use
sort_action='native',
sort_mode='multi',
filter_action='native',
editable=False,
column_selectable=False,
row_selectable='single',
row_deletable=False,
selected_rows=[],
),
html.Br(),
html.Hr(),
#This sets up the dashboard so that your chart and your geolocation chart are side-by-side
html.Div(className='row',
style={'display' : 'flex'},
children=[
html.Div(
id='graph-id',
className='col s12 m6',
),
html.Div(
id='map-id',
className='col s12 m6',
)
])
])
#############################################
# Interaction Between Components / Controller
#############################################
#app.callback([Output('datatable-id','data')],
[Input('submit-button-one', 'n_clicks'),Input('submit-button-two','n_clicks'),
Input('submit-button-three','n_clicks'),Input('submit-button-four','n_clicks')])
def update_dashboard(bt1,bt2,bt3,bt4):
### FIX ME Add code to filter interactive data table with MongoDB queries
if (int(bt1) >= 1):
df = pd.Dataframe.from_records(shelter.read({'$and': [
{'$or': [ {'breed':'Labrador Retriever Mix'}, {'breed':'Chesapeake Bay Retriever'},
{'breed':'Newfoundland'}]},
{'sex_upon_outcome':'Intact Female'}, {'age_upon_outcome_in_weeks':{'$lte':26, 'gte':156}}]}))
bt2, bt3, bt4 = 0
elif (int(bt2)>= 1):
df = pd.Dataframe.from_records(shelter.read({'$and': [
{'$or': [ {'breed':'German Shepherd'}, {'breed':'Alaskan Malamute'},
{'breed':'Old English Sheepdog'},{'breed':'Siberian Husky'},{'breed':'Rottweiler'}]},
{'sex_upon_outcome':'Intact Male'}, {'age_upon_outcome_in_weeks':{'$lte':26, 'gte':156}}]}))
bt1, bt3 ,bt4 = 0
elif (int(bt3)>=1):
df = pd.Dataframe.from_records(shelter.read({'$and': [
{'$or': [ {'breed':'Doberman Pinscher'}, {'breed':'German Sheperd'},
{'breed':'Golden Retriever'},{'breed':'Bloodhound'},{'breed':'Rottweiler'}]},
{'sex_upon_outcome':'Intact Male'}, {'age_upon_outcome_in_weeks':{'$lte':20, 'gte':300}}]}))
bt1, bt2, bt4 = 0
elif(int(bt4)>=1):
df = pd.Dataframe.from_records(shelter.read())
bt1, bt2, bt3 = 0
columns=[{"name": i, "id": i, "deletable": False, "selectable": True} for i in df.columns]
data=df.to_dict('records')
return data
#app.callback(
Output('datatable-id', 'style_data_conditional'),
[Input('datatable-id', 'selected_columns')]
)
def update_styles(selected_columns):
return [{
'if': { 'column_id': i },
'background_color': '#D2F3FF'
} for i in selected_columns]
#app.callback(
Output('graph-id', "children"),
[Input('datatable-id', "derived_viewport_data")])
def update_graphs(viewData):
###FIX ME ####
# add code for chart of your choice (e.g. pie chart)
df = pd.DataFrame.from_dict(viewData)
return [
dcc.Graph(
figure = px.pie(df, values=values, names=names, title='Percentage of breeds available')
)
]
#app.callback(
Output('map-id', "children"),
[Input('datatable-id', "derived_viewport_data"),
Input('datatable-id',"derived_viewport_selected_rows")])
def update_map(viewData):
#FIXME: Add in the code for your geolocation chart
#If you completed the Module Six Assignment, you can copy in the code you created here.
viewDF = pd.DataFrame.from_dict(viewData)
dff = viewDF.loc[rows]
return [ dl.Map(style={'width': '1000px', 'height': '500px'}, center=[dff.loc[0,'location_lat'],dff.loc[0,'location_long']], zoom=15, children=[
dl.TileLayer(id="base-layer-id"),
# Marker with tool tip and pop up
dl.Marker(position=[dff.loc[0,'location_lat'],dff.loc[0,'location_long']], children=[
dl.Tooltip(dff['breed']),
dl.Popup([
html.H1("Animal Name"),
html.P(dff.loc[0,'name'])
])
])
])]
app
In the #app.callback([Output('datatable-id','data')], add [Input('filter-type', 'value')]).
Also, in the callback before update_map, remove Input('datatable-id',"derived_viewport_selected_rows")]). Try: #app.callback(Output('map-id', "children"), [Input('datatable-id', "derived_viewport_data")])
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 succeed in adding dynamically container/bloc in my dash app when clicking on a button.
Each bloc contains one graph and two dropdown (one for X axis and the other for Y axis)
Each time I update a dropdown input (X or Y) the graph axis are updated and datas are correctly plotted
It works, but...
Before I choose dropdown value, some values are inially plotted on the graph zone. And I don't want this. I would like an empty graph
enter image description here
Here is my app code:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, MATCH, ALL
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(name="OUATT")
DATA = pd.read_csv('C:/Users/joris/Desktop/donnees.txt', sep=';')
print(DATA)
#graphe_test= px.scatter(DATA,x=DATA.x,y=DATA.y)
def create_figure(column_x, column_y):
return px.scatter(DATA,x=column_x,y=column_y)
app.layout = html.Div([
html.Button(" + Graphe", id="ajout-graphe", n_clicks=0),
html.Div(),
html.Div(id='bloc_graphe', children=[])
])
#app.callback( Output('bloc_graphe', 'children'),
[Input('ajout-graphe', 'n_clicks')],
[State('bloc_graphe', 'children')])
def ajouter_graphe(n_clicks, children):
nouvelle_zone_graphe = html.Div(
style={'width': '23%', 'display': 'inline-block', 'outline': 'thin lightgrey solid', 'padding': 10},
children=[
dcc.Graph(
id ={'type': 'Graphique',
'index': n_clicks}
),
dcc.Dropdown(
id={
'type':'Selection_variable_X',
'index': n_clicks
},
options=[{'label':i, 'value':i} for i in DATA.columns],
value = None
),
dcc.Dropdown(
id={
'type':'Selection_variable_Y',
'index': n_clicks
},
options=[{'label':i, 'value':i} for i in DATA.columns],
value = None
),
])
children.append(nouvelle_zone_graphe)
return children
#app.callback( Output({'type':'Graphique', 'index':MATCH},'figure'),
[Input({'type':'Selection_variable_X', 'index':MATCH}, 'value'),
Input({'type':'Selection_variable_Y', 'index':MATCH}, 'value')]
)
def display_output(column_x,column_y):
return create_figure(column_x, column_y)
if __name__ == '__main__':
app.run_server(debug=True)
My datas are basic and located in a text file:
enter image description here
I use Pattern-Matching callbacks. I'm sure I miss something in this part of my code:
#app.callback( Output({'type':'Graphique', 'index':MATCH},'figure'),
[Input({'type':'Selection_variable_X', 'index':MATCH}, 'value'),
Input({'type':'Selection_variable_Y', 'index':MATCH}, 'value')]
)
def display_output(column_x,column_y):
return create_figure(column_x, column_y)
If someone can tell me why I have not empty graph when adding a new bloc ?
Thanks a lot in advance for your support
Joe
I always suggest explicitly setting the prop you plan to update, figure in this case, to some default you want, such as {}.
It's possible the callback is running when you add the dropdowns. You can stop that by doing something like this:
#app.callback( Output({'type':'Graphique', 'index':MATCH},'figure'),
[Input({'type':'Selection_variable_X', 'index':MATCH}, 'value'),
Input({'type':'Selection_variable_Y', 'index':MATCH}, 'value')]
)
def display_output(column_x,column_y):
if column_x is None and column_y is None:
raise dash.exceptions.PreventUpdate
return create_figure(column_x, column_y)
Hopefully that keeps your figure empty until the user selects from the dropdowns.
I'm quite new to Plotly-Dash, and I'm currently struggling with the multi-page-dropdown.py example I found on the Dash Recipes Github because it is not working as I would expect.
I would like to have a multi-page app, with a dropdown menu on all pages that works as a filter on what is displayed on such pages; the dropdown selection should be persistent on all pages. The behaviour I'm looking for is displayed in the following GIF.
https://github.com/plotly/dash-recipes/blob/master/multi-page-dropdown-example.gif
When I run the recipe, however, I see an empty plot, when I open a new page.
My understanding of the callbacks that regulate the functioning of the code is that update_graph updates the plot based on the dropdown selection or when the URL changes (i.e., when a new page opens).
What I notice when I run the code provided in the recipe is that the update_graph callback updates correctly the graph when the dropdown selection is changed, but it fails to update the graph on a new page, when I open it.
Please find below the code I'm running, for reference.
Is there anything I'm doing wrong and should be done differently?
Thanks in advance for your support!
import dash
from dash.dependencies import Input, State, Output
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
df = pd.DataFrame({
'x': [1, 2, 3, 1, 2, 3, 1, 2, 3],
'y': [3, 2, 4, 1, 4, 5, 4, 3, 1],
'group-1': ['/', '/exhibit-b', '/exhibit-c', '/', '/exhibit-b', '/exhibit-c', '/', '/exhibit-b', '/exhibit-c'],
'group-2': ['LA', 'LA', 'LA', 'London', 'London', 'London', 'Montreal', 'Montreal', 'Montreal'],
})
app = dash.Dash()
app.scripts.config.serve_locally=True
# app.config.supress_callback_exceptions = True
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
# This "header" will persist across pages
html.H2('Multi Page Dash App'),
# Each "page" will modify this element
html.Div(id='content-container-part-1'),
dcc.Dropdown(
id='graph-control',
options=[{'label': i, 'value': i} for i in df['group-2'].unique()],
value='LA'
),
# Each "page" will modify this element
html.Div(id='content-container-part-2'),
# This Location component represents the URL bar
dcc.Location(id='url', refresh=False)
], className="container")
link_mapping = {
'/': 'Exhibit A',
'/exhibit-b': 'Exhibit B',
'/exhibit-c': 'Exhibit C',
}
styles = {
'link': {'padding': '20'}
}
#app.callback(
Output('content-container-part-1', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
return html.Div([
html.Div([
html.Span(
dcc.Link(link_mapping['/'], href="/") if pathname != '/' else 'Exhibit A',
style=styles['link']
),
html.Span(
dcc.Link(link_mapping['/exhibit-b'], href="/exhibit-b") if pathname != '/exhibit-b' else 'Exhibit B',
style=styles['link']
),
html.Span(
dcc.Link(link_mapping['/exhibit-c'], href="/exhibit-c") if pathname != '/exhibit-c' else 'Exhibit C',
style=styles['link']
)
]),
dcc.Markdown('### {}'.format(link_mapping[pathname])),
])
#app.callback(
Output('content-container-part-2', 'children'),
[Input('url', 'pathname')])
def display_page(*args):
return html.Div([
dcc.Graph(
id='graph',
)
])
#app.callback(
Output('graph', 'figure'),
[Input('graph-control', 'value'),
Input('url', 'pathname')])
def update_graph(value, pathname):
dff = df[(df['group-1'] == pathname) & (df['group-2'] == value)]
return {
'data': [{
'x': dff.x,
'y': dff.y,
'type': 'bar'
}],
'layout': {
'title': '{} in {}'.format(value, link_mapping[pathname])
}
}
app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})
if __name__ == '__main__':
app.run_server(debug=True)
The issue seems to be resolved by simply swapping the order of display_page and update_graph callbacks: the correct requires update_graph to come first in the code, and display_page to follow.
Now, my question is if it is possible to control the execution order of callbacks, to make sure everything is executed correctly?
Obviously, if anyone has more brilliant explanations or solutions, please come forward!
For reference, the piece should look like this.
#app.callback(
Output('graph', 'figure'),
[Input('graph-control', 'value'),
Input('url', 'pathname')])
def update_graph(value, pathname):
dff = df[(df['group-1'] == pathname) & (df['group-2'] == value)]
return {
'data': [{
'x': dff.x,
'y': dff.y,
'type': 'bar'
}],
'layout': {
'title': '{} in {}'.format(value, link_mapping[pathname])
}
}
#app.callback(
Output('content-container-part-2', 'children'),
[Input('url', 'pathname')])
def display_page(*args):
return html.Div([
dcc.Graph(
id='graph',
)
])