I have a sidebar and a date-picker in my dashboard built with Dash. However, I am unable to load the graph correctly based on the date range selected. The data source can be found in the link below, however, I changed the column "Year" values to dates in this format "YYYY-MM-DD".
Data Source
Help is much appreciated.
Output errors:
FileNotFoundError: [Errno 2] No such file or directory: 'iranian_students.csv'
ID not found in layout
Attempting to connect a callback Input item to component:
"date-range"
but no components with that id exist in the layout.
If you are assigning callbacks to components that are
generated by other callbacks (and therefore not in the
initial layout), you can suppress this exception by setting
`suppress_callback_exceptions=True`.
This ID was used in the callback(s) for Output(s):
students.figure
students.figure
ID not found in layout
Attempting to connect a callback Output item to component:
"students"
but no components with that id exist in the layout.
If you are assigning callbacks to components that are
generated by other callbacks (and therefore not in the
initial layout), you can suppress this exception by setting
`suppress_callback_exceptions=True`.
This ID was used in the callback(s) for Output(s):
students.figure
My code:
# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from flask import Flask
import pandas as pd
from pandas import DataFrame
from pandas import json_normalize
import pymongo
from pymongo import MongoClient
import plotly.graph_objs as go
import plotly.offline as pyo
import plotly.express as px
import numpy as np
import pytz, time
from datetime import datetime, tzinfo, timezone, timedelta, date
import dash_bootstrap_components as dbc
import random
from sqlalchemy import create_engine
from plotly.subplots import make_subplots
# %%
# constants
df = pd.read_csv('Bootstrap\Side-Bar\iranian_students.csv')
localTimezone = pytz.timezone('Africa/Cairo')
datetimeNow = datetime.now(localTimezone)
# %%
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.FLATLY],
meta_tags=[{'name': 'viewport',
'content': 'width=device-width, initial-scale=1.0'}]
)
# %%
def serve_layoutOnReload():
# styling the sidebar
SIDEBAR_STYLE = {
"position": "fixed",
"top": 0,
"left": 0,
"bottom": 0,
"width": "16rem",
"padding": "2rem 1rem",
"background-color": "#f8f9fa",
}
# padding for the page content
CONTENT_STYLE = {
"margin-left": "18rem",
"margin-right": "2rem",
"padding": "2rem 1rem",
}
sidebar = html.Div(
[
html.H2("Sidebar", className="display-4"),
html.Hr(),
html.P(
"Number of students per education level", className="lead"
),
dbc.Nav(
[
dbc.NavLink("Home", href="/", active="exact"),
dbc.NavLink("Page 1", href="/page-1", active="exact"),
dbc.NavLink("Page 2", href="/page-2", active="exact"),
],
vertical=True,
pills=True,
),
],
style=SIDEBAR_STYLE,
)
content = html.Div(id="page-content", children=[], style=CONTENT_STYLE)
web_layout = html.Div([
dcc.Location(id="url"),
sidebar,
content
])
return web_layout
app.layout = serve_layoutOnReload
# app.layout = html.Div([
# dcc.Location(id="url"),
# sidebar,
# content
# ])
# %%
#app.callback(
Output("page-content", "children"),
[Input("url", "pathname")]
)
def render_page_content(pathname):
if pathname == "/":
return [
html.H1('Kindergarten',
style={'textAlign':'center'}),
dbc.Container([
dbc.Row([
dbc.Col([
html.P("Date picker:", className='text-right font-weight-bold mb-4'),
],xs=12, sm=12, md=12, lg=5, xl=5),
dbc.Col([
dcc.DatePickerRange(id='date-range',
min_date_allowed=date(2020, 6, 1),
max_date_allowed=datetimeNow.date(),
start_date=datetimeNow.date() - timedelta(days=7),
end_date=datetimeNow.date(), ),
],xs=12, sm=12, md=12, lg=5, xl=5),], no_gutters=True, justify='center'),
dbc.Row(
dbc.Col(html.H2(" ", className='text-center text-primary mb-4'), width=12)
),
dbc.Row([
dbc.Col([
dcc.Graph(id="students", figure={}),
], xs=12, sm=12, md=12, lg=5, xl=5),], justify='center')
], fluid=True)
]
elif pathname == "/page-1":
return [
html.H1('Grad School',
style={'textAlign':'center'}),
dcc.Graph(id='bargraph',
figure=px.bar(df, barmode='group', x='Date',
y=['Girls Grade School', 'Boys Grade School']))
]
elif pathname == "/page-2":
return [
html.H1('High School',
style={'textAlign':'center'}),
dcc.Graph(id='bargraph',
figure=px.bar(df, barmode='group', x='Date',
y=['Girls High School', 'Boys High School']))
]
# If the user tries to reach a different page, return a 404 message
return dbc.Jumbotron(
[
html.H1("404: Not found", className="text-danger"),
html.Hr(),
html.P(f"The pathname {pathname} was not recognised..."),
]
)
# %%
#app.callback([Output("students", "figure")],
[Input("date-range", "start_date"),
Input("date-range", "end_date")])
def update_charts(start_date, end_date):
# read data upon refresh browser
df = pd.read_csv('iranian_students.csv')
# masks
mask1 = (
(df.Date >= pd.to_datetime(start_date))
& (df.Date <= pd.to_datetime(end_date))
)# daily sgym signups
# filtered dataframes
filtered_data1 = df.loc[mask1, :].reset_index(drop=True)
# plots
# daily sgym signups
trace = []
trace.append(go.Bar(
x = filtered_data1['Date'],
y = filtered_data1['Girls Kindergarten'],
name = 'Count of students'
))
# add moving average
filtered_data1['Moving Avg'] = filtered_data1['Girls Kindergarten'].rolling(window=7, min_periods=1).mean()
trace.append(go.Scatter(x=filtered_data1['Date'], y=filtered_data1['Moving Avg'], name = 'Rolling Mean=7'))
students_fig = {'data': trace,
'layout': go.Layout(
{"title": {"text": "Student Count\n"
'('+str(start_date)+' to '+str(end_date)+')',
"x": 0.05, "xanchor": "left"},
"xaxis": {"fixedrange": False, 'title':'Date',
'tickmode':'linear', 'automargin':True},
"yaxis": {"fixedrange": False, 'title':'Count of Signups'},
'xaxis_tickformat':'%d %b',
'title_font_size': 14,
'hovermode':'closest',
'legend_title_text':'Gym',
'hovermode':'closest',
},) }
return students_fig
# %%
if __name__=='__main__':
app.run_server(debug=True, port=3000)
The first error is telling you exactly where the problems start. The problem is in the file path that you define when updating the graph.
instead of this:
def update_charts(start_date, end_date):
# read data upon refresh browser
df = pd.read_csv('iranian_students.csv')
You need to do this:
def update_charts(start_date, end_date):
# read data upon refresh browser
df = pd.read_csv('Bootstrap\Side-Bar\iranian_students.csv')
the second problem is that you
call function serve_layoutOnReload without the brackets?
app.layout = serve_layoutOnReload
instead of
app.layout = serve_layoutOnReload()
The third problem is in how you define your layout. See this discussion for reference.This discussion from January is using the same code/database that you have and they are facing the same issues.
I would try defining the layout directly like this:
app.layout = html.Div([])
Related
I'm creating a dashboard with Dash on which I want a variable number of graphs with associated dropdowns underneath each other. The dropdowns control an aspect of the graph (how it's sorted, but this is unimportant). Here is the code:
from dash import html, dcc
from dash.dependencies import Output, Input, State, MATCH
import dash_bootstrap_components as dbc
from app.plots import get_product_breakdown_bar_chart
from .selectors import get_product_selection_checklist, get_impact_parameter_selection_checklist, get_product_to_sort_on_dropdown, DEFAULT_PRODUCT_CHECKLIST_ID, DEFAULT_IMPACT_PARAMETER_CHECKLIST_ID, DEFAULT_PRODUCTS, DEFAULT_IMPACT_PARAMETERS
def get_selectors_pane():
selectors_row = dbc.Row([
dbc.Col(
[get_product_selection_checklist()],
width = 6
),
dbc.Col(
[get_impact_parameter_selection_checklist()],
width = 6
)
])
labels_row = dbc.Row([
dbc.Col(
[dbc.Label("Products:", html_for = DEFAULT_PRODUCT_CHECKLIST_ID)],
width = 6
),
dbc.Col(
[dbc.Label("Impact parameters: ", html_for = DEFAULT_IMPACT_PARAMETER_CHECKLIST_ID)],
width = 6
)
])
return html.Div([
labels_row,
selectors_row
])
saved_sorted_on_states = {}
selected_products = DEFAULT_PRODUCTS
def render_graph_rows(selected_products, selected_impact_parameters):
def sov(impact_parameter):
if impact_parameter in saved_sorted_on_states:
if saved_sorted_on_states[impact_parameter] in selected_products:
return saved_sorted_on_states[impact_parameter]
else:
saved_sorted_on_states.pop(impact_parameter)
return selected_products[0]
else:
return selected_products[0]
rows = []
for s_ip in selected_impact_parameters:
sort_on_dropdown_id = {"type": "sort-on-dropdown", "index": s_ip}
ip_graph_id = {"type": "impact-parameter-graph", "index": s_ip}
rows.append(
html.Div([
dbc.Row([
dbc.Col([dbc.Label("Sort on:", html_for = sort_on_dropdown_id)], width = 2),
dbc.Col([get_product_to_sort_on_dropdown(sort_on_dropdown_id, sov(s_ip))], width = 10)
]),
dbc.Row([
dbc.Col([
dcc.Graph(
id = ip_graph_id,
figure = get_product_breakdown_bar_chart(s_ip, selected_products, sov(s_ip))
)
], width = 12)
])
])
)
return rows
content_layout = html.Div(
id = "content",
children = [
get_selectors_pane(),
html.Div(
id = "graph-grid",
children = render_graph_rows(DEFAULT_PRODUCTS, DEFAULT_IMPACT_PARAMETERS)
)
],
style = {
"margin-left": "14rem",
"margin-right": "2rem",
"padding": "2rem 1rem",
}
)
def register_callback(app):
def sort_graph_callback(value, index):
global saved_sorted_on_states
saved_sorted_on_states[index] = value
return (get_product_breakdown_bar_chart(index, selected_products, value), )
app.callback(
[Output({"type": "impact-parameter-graph", "index": MATCH}, "figure")],
[Input({"type": "sort-on-dropdown", "index": MATCH}, "value")],
[State({"type": "sort-on-dropdown", "index": MATCH}, "id")]
)(sort_graph_callback)
def new_master_selection_callback(s_ps, s_ips):
global selected_products
selected_products = s_ps
return (render_graph_rows(s_ps, s_ips), )
app.callback(
[Output("graph-grid", "children")],
[Input(DEFAULT_PRODUCT_CHECKLIST_ID, "value"), Input(DEFAULT_IMPACT_PARAMETER_CHECKLIST_ID, "value")]
)(new_master_selection_callback)
The problem is that the sort_graph_callback defined on line 86 never gets called. This callback is supposed to connect dynamically added graphs with dynamically added dropdowns associated to them. But when I select a different option in such a dropdown nothing happens to the associated graph and the callback doesn't get called at all. I know this from setting breakpoints in them. I have verified that the correct id's are assigned to the rendered graph and dropdown components.
(Please note that I'm registering the callbacks in a peculiar way due to code organization reasons. I have verified that this is not the cause of the issue)
I have no clue anymore how to debug this issue. In my development environment pattern matching callback examples from the official documentation work just fine. Is there anything I'm missing?
Thank you so much in advance,
Joshua
The first segment of code below (code # 1) generates a graph for which 1) when you hover over each point, the data associated with each point is displayed and 2) when you click on each point, the data associated with each point is saved to a list. For this code, I would also like to display the image associated with each point. Assume the dataframe df has a column 'image' which contains the image pixel/array data of each point. I found code online (code #2) that implements this image hover feature but without the click feature. I'm having a hard time combining the image hover feature with the click feature. So, basically, I'm trying to combine the click feature (click on point, it's data is saved to a list) of code # 2 into code # 1.
CODE # 1 (with click feature):
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
from dash import dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data
df = px.data.gapminder().query("continent=='Oceania'")
# plotly figure
fig = px.line(df, x="year", y="lifeExp", color="country", title="No label selected")
fig.update_traces(mode="markers+lines")
app.layout = html.Div([
dcc.Graph(
id='figure1',
figure=fig,
),
html.Div(className
='row', children=[
html.Div([
dcc.Markdown(d("""Hoverdata using figure references""")),
html.Pre(id='hoverdata2', style=styles['pre']),
], className='three columns'),
html.Div([
dcc.Markdown(d("""
Full hoverdata
""")),
html.Pre(id='hoverdata1', style=styles['pre']),
], className='three columns')
]),
])
# container for clicked points in callbacks
store = []
#app.callback(
Output('figure1', 'figure'),
Output('hoverdata1', 'children'),
Output('hoverdata2', 'children'),
[Input('figure1', 'clickData')])
def display_hover_data(hoverData):
if hoverData is not None:
traceref = hoverData['points'][0]['curveNumber']
pointref = hoverData['points'][0]['pointNumber']
store.append([fig.data[traceref]['name'],
fig.data[traceref]['x'][pointref],
fig.data[traceref]['y'][pointref]])
fig.update_layout(title = 'Last label was ' + fig.data[traceref]['name'])
return fig, json.dumps(hoverData, indent=2), str(store)
else:
return fig, 'None selected', 'None selected'
app.run_server(mode='external', port = 7077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
CODE # 2 (includes image hover feature):
from jupyter_dash import JupyterDash
from dash import Dash, dcc, html, Input, Output, no_update
import plotly.graph_objects as go
import pandas as pd
## create sample random data
df = pd.DataFrame({
'x': [1,2,3],
'y': [2,3,4],
'z': [3,4,5],
'color': ['red','green','blue'],
'img_url': [
"https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2880px-Stack_Overflow_logo.svg.png",
"https://upload.wikimedia.org/wikipedia/commons/3/37/Plotly-logo-01-square.png",
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Pandas_logo.svg/2880px-Pandas_logo.svg.png"
]
})
fig = go.Figure(data=[
go.Scatter3d(
x=df['x'],
y=df['y'],
z=df['z'],
mode='markers',
marker=dict(color=df['color'])
)
])
# turn off native plotly.js hover effects - make sure to use
# hoverinfo="none" rather than "skip" which also halts events.
fig.update_traces(hoverinfo="none", hovertemplate=None)
fig.update_layout(
scene = dict(
xaxis = dict(range=[-1,8],),
yaxis = dict(range=[-1,8],),
zaxis = dict(range=[-1,8],),
),
)
app = JupyterDash(__name__)
server = app.server
app.layout = html.Div([
dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True),
dcc.Tooltip(id="graph-tooltip"),
])
#app.callback(
Output("graph-tooltip", "show"),
Output("graph-tooltip", "bbox"),
Output("graph-tooltip", "children"),
Input("graph-basic-2", "hoverData"),
)
def display_hover(hoverData):
if hoverData is None:
return False, no_update, no_update
# demo only shows the first point, but other points may also be available
pt = hoverData["points"][0]
bbox = pt["bbox"]
num = pt["pointNumber"]
df_row = df.iloc[num]
img_src = df_row['img_url']
children = [
html.Div([
html.Img(src=img_src, style={"width": "100%"}),
], style={'width': '100px', 'white-space': 'normal'})
]
return True, bbox, children
app.run_server(mode="inline")
you want a callback that does hover and click
on hover display image associated with point and full hover info
on click update list of clicked points and figure title
Assume the dataframe df has a column 'image' have created one that is a b64 encoded image
have inserted this into the figure by using customdata (hover_data parameter in px)
have added an additional div image
have changed callback to behave as it did before and also contents on new div. This uses b64 encoded image, extending with necessary "data:image/png;base64,"
need to take note of this https://dash.plotly.com/vtk/click-hover and https://dash.plotly.com/advanced-callbacks
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
import base64, io, requests
from PIL import Image
from pathlib import Path
warnings.simplefilter(action="ignore", category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {"pre": {"border": "thin lightgrey solid", "overflowX": "scroll"}}
# data for whare images can be found
df_flag = pd.read_csv(
io.StringIO(
"""country,Alpha-2 code,Alpha-3 code,URL
Australia,AU,AUS,https://www.worldometers.info//img/flags/small/tn_as-flag.gif
New Zealand,NZ,NZL,https://www.worldometers.info//img/flags/small/tn_nz-flag.gif"""
)
)
# ensure that images exist on your file system...
f = Path.cwd().joinpath("flags")
if not f.exists():
f.mkdir()
# download some images and use easy to use filenames...
for r in df_flag.iterrows():
flag_file = f.joinpath(f'{r[1]["Alpha-3 code"]}.gif')
if not flag_file.exists():
r = requests.get(r[1]["URL"], stream=True, headers={"User-Agent": "XY"})
with open(flag_file, "wb") as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
# encode
def b64image(country):
b = io.BytesIO()
im = Image.open(Path.cwd().joinpath("flags").joinpath(f"{country}.gif"))
im.save(b, format="PNG")
b64 = base64.b64encode(b.getvalue())
return b64.decode("utf-8")
df_flag["image"] = df_flag["Alpha-3 code"].apply(b64image)
# data
df = px.data.gapminder().query("continent=='Oceania'")
df = df.merge(df_flag, on="country") # include URL and b64 encoded image
# plotly figure. Include URL and image columns in customdata by using hover_data
fig = px.line(
df,
x="year",
y="lifeExp",
color="country",
title="No label selected",
hover_data={"URL": True, "image": False},
)
fig.update_traces(mode="markers+lines")
app.layout = dash.html.Div(
[
dash.dcc.Graph(
id="figure1",
figure=fig,
),
dash.html.Div(
className="row",
children=[
dash.html.Div(id="image"),
dash.html.Div(
[
dash.dcc.Markdown(d("""Hoverdata using figure references""")),
dash.html.Pre(id="hoverdata2", style=styles["pre"]),
],
className="three columns",
),
dash.html.Div(
[
dash.dcc.Markdown(
d(
"""
Full hoverdata
"""
)
),
dash.html.Pre(id="hoverdata1", style=styles["pre"]),
],
className="three columns",
),
],
),
]
)
# container for clicked points in callbacks
store = []
#app.callback(
Output("figure1", "figure"),
Output("hoverdata1", "children"),
Output("hoverdata2", "children"),
Output("image", "children"),
[Input("figure1", "clickData"), Input("figure1", "hoverData")],
)
def display_hover_data(clickData, hoverData):
# is it a click or hover event?
ctx = dash.callback_context
if ctx.triggered[0]["prop_id"] == "figure1.clickData":
traceref = clickData["points"][0]["curveNumber"]
pointref = clickData["points"][0]["pointNumber"]
store.append(
[
fig.data[traceref]["name"],
fig.data[traceref]["x"][pointref],
fig.data[traceref]["y"][pointref],
]
)
fig.update_layout(title="Last label was " + fig.data[traceref]["name"])
return fig, dash.no_update, str(store), dash.no_update
elif ctx.triggered[0]["prop_id"] == "figure1.hoverData":
# simpler case of just use a URL...
# dimg = dash.html.Img(src=hoverData["points"][0]["customdata"][0], style={"width": "30%"})
# question wanted image encoded in dataframe....
dimg = dash.html.Img(
src="data:image/png;base64," + hoverData["points"][0]["customdata"][1],
style={"width": "30%"},
)
return fig, json.dumps(hoverData, indent=2), dash.no_update, dimg
else:
return fig, "None selected", "None selected", "no image"
# app.run_server(mode='external', port = 7077, dev_tools_ui=True,
# dev_tools_hot_reload =True, threaded=True)
app.run_server(mode="inline")
I'm new to Dash and Python. I have an app with a dropdown and a search input however I cannot get the callback to get both inputs to work. Currently either only the dropdown will work or just the input. I would like to first select the dropdown and then be able to search for text within the Datatable.
Below is my code.
import pandas as pd
import dash
import dash_table
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import pathlib
from dash.dependencies import Input, Output
df = pd.read_csv('data.csv',encoding='cp1252')
env_list = df["Environment"].unique()
PAGE_SIZE = 20
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]
)
def description_card():
"""
:return: A Div containing logo.
"""
return html.Div(
id="description-card",
children=[
html.Img(id="logo", src=app.get_asset_url("logo.png"), height=80)
],style={'textAlign': 'center'}
)
def generate_control_card():
"""
:return: Descriptions
"""
return html.Div(
id="env-card",
children=[
html.H3("Welcome to the Package Catalog"),
]
)
app.layout = html.Div(
id="app-container",
children=[
# Banner
html.Div(
id="banner",
className="banner",
children=[description_card(),generate_control_card()
],
),
html.Div([
html.P([
html.Label("Select Environment", style={"background": "#F5F5F5"}),
dcc.Dropdown(
id='env-select',
options=[{'label': i, 'value': i} for i in env_list],
value=env_list[0],
)]),
html.Div([
html.P([
html.Label("Search for a package and description in the search box.", style={'display':'inline-block', 'background': '#F5F5F5'}),
dcc.Input(value='', id='filter-input', placeholder='Filter', debounce=True)
]),
dash_table.DataTable(css=[{'selector': '.row', 'rule': 'margin: 0'}],
id='datatable-paging',
columns=[
{"name": i, "id": i} for i in df.columns # sorted(df.columns)
],
style_header={
'backgroundColor': 'F5F5F5',
'fontWeight': 'bold'
},
page_current=0,
page_size=PAGE_SIZE,
page_action='custom',
sort_action='custom',
sort_mode='single',
sort_by=[]
)
]),
]),
])
#app.callback(
Output('datatable-paging', 'data'),
[
Input('datatable-paging', 'page_current'),
Input('datatable-paging', 'page_size'),
Input('datatable-paging', 'sort_by'),
Input('env-select', 'value'),
Input('filter-input', 'value')
])
def update_table(page_current, page_size, sort_by, environment_input, filter_string,
):
# Filter
dff = df[df.Environment==environment_input]
dff = df[df.apply(lambda row: row.str.contains(filter_string, regex=False).any(), axis=1)]
# Sort
if len(sort_by):
dff = dff.sort_values(
sort_by[0]['column_id'],
ascending=sort_by[0]['direction'] == 'asc',
inplace=False
)
return dff.iloc[
page_current * page_size:(page_current + 1) * page_size
].to_dict('records')
Change this line
dff = df[df.apply(lambda row: row.str.contains(filter_string, regex=False).any(), axis=1)]
to this
dff = dff[df.apply(lambda row: row.str.contains(filter_string, regex=False).any(), axis=1)]
In the line before the one shown above you apply your dropdown filter and store the filtered result as dff. So by using df instead of dff you're essentially discarding the dropdown filter result.
I would like to add a range slider along with my dropdown, and make the range slider the 'Wallclock' datetime along with an interaction that allows the range slider to chose the datetime for that capsules based on the dropdown value. I managed to find several ways that other people have done this but none seems to work for my situation especially the callback and the update of the graph. Thank you!
Data looks like this.
Dash looks like this.
Code looks like this.
import pandas as pd
import plotly.express as px # (version 4.7.0)
import plotly.graph_objects as go
import numpy as np
import openpyxl
import dash # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
app = dash.Dash(__name__)
server = app.server
df = pd.read_excel("tcd vs rh 2.xlsx")
print(df)
capsuleID = df['Capsule_ID'].unique()
print(capsuleID)
capsuleID_names = sorted(list(capsuleID))
print(capsuleID_names)
capsuleID_names_1 = [{'label': k, 'value': k} for k in sorted(capsuleID)]
capsuleID_names_2 = [{'label': '(Select All)', 'value': 'All'}]
capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2
app.layout = html.Div([
html.H1("Relative Humidity vs TCD", style={'text-align': 'center'}),
dcc.Dropdown(id="capsule_select",
options=capsuleID_names_all,
optionHeight=25,
multi=True,
searchable=True,
placeholder='Please select...',
clearable=True,
value=['All'],
style={'width': "100%"}
),
dcc.RangeSlider(id='slider',
min=df['Wallclock'].min(),
max=df['Wallclock'].max(),
value=[df.iloc[-101]['Wallclock'].timestamp(), df.iloc[-1]['Wallclock'].timestamp()]
),
html.Div([
dcc.Graph(id="the_graph"),
]),
])
# -----------------------------------------------------------
#app.callback(
Output('the_graph', 'figure'),
Output('capsule_select', 'value'),
Input('capsule_select', 'value'),
Input('slider', 'value'),
)
def update_graph(capsule_chosen):
lBound = pd.to_datetime(value[0], unit='s')
uBound = pd.to_datetime(value[1], unit='s')
filteredData = df.loc[(df['date'] >= lBound) & (df['date'] <= uBound)]
dropdown_values = capsule_chosen
if "All" in capsule_chosen:
dropdown_values = capsuleID_names
dff = df
else:
dff = df[df['Capsule_ID'].isin(capsule_chosen)] # filter all rows where capsule ID is the capsule ID selected
scatterplot = px.scatter(
data_frame=dff,
x="tcd",
y="humidity",
hover_name="Wallclock",
)
scatterplot.update_traces(textposition='top center')
return scatterplot, dropdown_values
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app.run_server(debug=True)
obviously I don't have access to your Excel spreadsheet so generated a data frame with same shape
taken approach of using a second figure with a rangeslider for slider capability
updated callback to use this figure as input for date range
used jupyter dash inline, this can be changed back to your setup (commented lines)
generate some sample data
import pandas as pd
import numpy as np
df = pd.DataFrame(
{
"Wallclock": pd.date_range(
"22-dec-2020 00:01:36", freq="5min", periods=2000
),
"tcd": np.linspace(3434, 3505, 2000) *np.random.uniform(.9,1.1, 2000),
"humidity": np.linspace(63, 96, 2000),
}
).pipe(lambda d: d.assign(Capsule_ID=(d.index // (len(d)//16))+2100015))
slider is a figure with a rangeslider
import pandas as pd
import plotly.express as px # (version 4.7.0)
import plotly.graph_objects as go
import numpy as np
import openpyxl
import dash # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
from jupyter_dash import JupyterDash
# app = dash.Dash(__name__)
# server = app.server
app = JupyterDash(__name__)
# df = pd.read_excel("tcd vs rh 2.xlsx")
# print(df)
capsuleID = df["Capsule_ID"].unique()
# print(capsuleID)
capsuleID_names = sorted(list(capsuleID))
# print(capsuleID_names)
capsuleID_names_1 = [{"label": k, "value": k} for k in sorted(capsuleID)]
capsuleID_names_2 = [{"label": "(Select All)", "value": "All"}]
capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2
def slider_fig(df):
return px.scatter(
df.groupby("Wallclock", as_index=False).size(), x="Wallclock", y="size"
).update_layout(
xaxis={"rangeslider": {"visible": True}, "title":None},
height=125,
yaxis={"tickmode": "array", "tickvals": [], "title": None},
margin={"l": 0, "r": 0, "t": 0, "b": 0},
)
app.layout = html.Div(
[
html.H1("Relative Humidity vs TCD", style={"text-align": "center"}),
dcc.Dropdown(
id="capsule_select",
options=capsuleID_names_all,
optionHeight=25,
multi=True,
searchable=True,
placeholder="Please select...",
clearable=True,
value=["All"],
style={"width": "100%"},
),
dcc.Graph(
id="slider",
figure=slider_fig(df),
),
html.Div(
[
dcc.Graph(id="the_graph"),
]
),
]
)
# -----------------------------------------------------------
#app.callback(
Output("the_graph", "figure"),
Output("capsule_select", "value"),
Output("slider", "figure"),
Input("capsule_select", "value"),
Input('slider', 'relayoutData'),
State("slider", "figure")
)
def update_graph(capsule_chosen, slider, sfig):
dropdown_values = capsule_chosen
if "All" in capsule_chosen:
dropdown_values = capsuleID_names
dff = df
else:
dff = df[
df["Capsule_ID"].isin(capsule_chosen)
] # filter all rows where capsule ID is the capsule ID selected
if slider and "xaxis.range" in slider.keys():
dff = dff.loc[dff["Wallclock"].between(*slider["xaxis.range"])]
else:
# update slider based on selected capsules
sfig = slider_fig(dff)
scatterplot = px.scatter(
data_frame=dff,
x="tcd",
y="humidity",
hover_name="Wallclock",
)
scatterplot.update_traces(textposition="top center")
return scatterplot, dropdown_values, sfig
# ------------------------------------------------------------------------------
if __name__ == "__main__":
# app.run_server(debug=True)
app.run_server(mode="inline")
I'm new using Dash and I wonder if it is possible to have a Dash table with 1 column of numeric values like this one:
Values
-------
1
2
3
4
And have the option to choose/click to one of the values and make a bar plot appear with the value clicked.
Hope you can help me. Thanks in advance.
You could use the active_cell property of dash_table.DataTable to get the clicked value in a callback. Then you can use this value to plot the graph:
import pandas as pd
from dash import Dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from dash_table import DataTable
import plotly.graph_objects as go
df = pd.DataFrame(
{"values": [1, 2, 3, 4], "labels": ["value 1", "value 2", "value 3", "value 4"]}
)
app = Dash(__name__)
app.layout = html.Div(
[
dcc.Graph(id="graph"),
DataTable(
id="table",
columns=[{"name": "values", "id": "values"}],
data=df.to_dict("records"),
),
]
)
#app.callback(
Output("graph", "figure"), Input("table", "active_cell"), prevent_initial_call=True
)
def update_output_div(active_cell):
selected_value = df.iloc[active_cell["row"], active_cell["column"]]
num_values = len(df["values"])
fig = go.Figure(go.Bar(x=[selected_value], y=[selected_value]))
fig.update_layout(yaxis_range=[0, num_values])
fig.update_layout(
yaxis=dict(
tickmode="array",
tickvals=df["values"],
ticktext=df["labels"],
),
)
fig.update_layout(
xaxis=dict(
tickmode="array",
tickvals=[selected_value],
ticktext=[selected_value],
)
)
return fig
if __name__ == "__main__":
app.run_server()