I've recently started a Dash application that shows up pre-registered HTML files that I show via HTML.iFrame :
html.Iframe(id = 'my-output', src = "assets/ABCD.html",
style={"height": "495px", "width": "100%",})
and I've got a function/app callback, like the following:
#app.callback(
Output(component_id='my-output', component_property='children'),
Input(component_id='my-input', component_property='value'),
)
def update_output_div(input_value):
return XYZ
Now I need that output value in my src, like this
html.Iframe(id = 'my-output', src = "assets/XYZ.html",
style={"height": "495px", "width": "100%",})
But i don't know how to get back that output value and change my src parameters.
You can make the src property an Output in your callback.
Example that uses a Dropdown as Input:
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input
app = dash.Dash()
app.layout = html.Div(
[
html.Iframe(
id="my-output",
src="assets/ABCD.html",
style={"height": "495px", "width": "100%"},
),
dcc.Dropdown(
id="input",
options=[
{"label": "ABCD", "value": "ABCD.html"},
{"label": "XYZ", "value": "XYZ.html"},
],
value="ABCD.html",
),
]
)
#app.callback(
Output("my-output", "src"), Input("input", "value"), prevent_initial_call=True
)
def update_output_div(input_value):
return f"assets/{input_value}"
if __name__ == "__main__":
app.run_server()
Related
In Python I am working with Dash and Dash bootstrap components. I am having trouble with the bootstrap Modal component. My most basic implementation of the modal, using the first example here, works fine. However, If I try to replace their single callback with two separate callbacks for the buttons, it stops working. Can anybody explain to me why this is and help me get it working? The callbacks don't seem difficult at all.
Most basic implementation of their code (this works for me):
from dash import Dash, html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from dash_bootstrap_components.themes import LUMEN
app = Dash(external_stylesheets=[LUMEN])
app.title = "Test"
app.layout = html.Div(
[
dbc.Button("Open modal", id="open", n_clicks=0),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("Header")),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(
dbc.Button(
"Close", id="close", className="ms-auto", n_clicks=0
)
),
],
id="modal",
is_open=False,
),
]
)
#app.callback(
Output("modal", "is_open"),
[Input("open", "n_clicks"), Input("close", "n_clicks")],
[State("modal", "is_open")],
)
def toggle_modal(n1, n2, is_open):
print(is_open)
print(type(is_open))
if n1 or n2:
return not is_open
return is_open
app.run()
Code with their callbacks replaced by two separate callbacks for the buttons (not working):
from dash import Dash, html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from dash_bootstrap_components.themes import LUMEN
app = Dash(external_stylesheets=[LUMEN])
app.title = "Test"
app.layout = html.Div(
[
dbc.Button("Open modal", id="open", n_clicks=0),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("Header")),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(
dbc.Button(
"Close", id="close", className="ms-auto", n_clicks=0
)
),
],
id="modal",
is_open=False,
),
]
)
#app.callback(
Output("modal", "is_open"),
Input("open", "n_clicks")
)
def toggle_modal_open(n1):
if n1:
return True
#app.callback(
Output("modal", "is_open"),
Input("close", "n_clicks")
)
def toggle_modal_close(n1):
if n1:
return False
app.run()
I know this question might be asked, but I couldn't find a solution that fits my problem.
I'm trying to build a multi layout dash app.
I would like to to change the layout (which contains dcc.Graphs and dbc.Card) everytime I click on a different Tab ( I have 3 of those). The problem is that I have this exception when I run my code:
"dash.exceptions.InvalidCallbackReturnValue: The callback for <Output content.children>
returned a value having type Dash
which is not JSON serializable. "
Below is my code:
import dash_bootstrap_components as dbc
import base64
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from DashFriends import friends_layout
from DashUser import user_layout
from FriendsUserApp import userfriends_layout
app = dash.Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.MINTY],
meta_tags=[{'name': 'viewport',
'content': 'width=device-width, initial-scale=1.0'}]
)
colors = {
'background': '#ffffff',
'text': '#4d94ff',
'plot': '#D1D0CE',
'textfig': '#000000'
}
app_tabs = html.Div(
[
dbc.Tabs(
[
dbc.Tab(label="My friends", tab_id="tab-friends", labelClassName="text-success font-weight-bold",
activeLabelClassName="text-danger"),
dbc.Tab(label="Just me", tab_id="tab-user", labelClassName="text-success font-weight-bold",
activeLabelClassName="text-danger"),
dbc.Tab(label="My Friends and I", tab_id="tab-userfriends",
labelClassName="text-success font-weight-bold",
activeLabelClassName="text-danger")
],
id="tabs",
active_tab="tab-user",
),
], className="mt-3"
)
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
html.H1(
children='Twitter User Analysis',
style={
'textAlign': 'center',
'font-family': 'Garamond',
'font-weight': 'bold',
'color': colors['text']
}
),
html.Div(children='Get an analysis of a user', style={
'textAlign': 'center',
'font-family': 'Garamond',
'font-weight': 'bold',
'color': colors['text']
}),
html.Br(),
html.Hr(),
dbc.Row(dbc.Col(app_tabs, width=12), className="mb-3"),
html.Br(),
html.Div(id='content', children=[])
])
#app.callback(
Output(component_id="content", component_property="children"),
[Input(component_id="tabs", component_property="active_tab")]
)
def switch_tab(tab_chosen):
if tab_chosen == "tab-friends":
return friends_layout
elif tab_chosen == "tab-user":
return user_layout
elif tab_chosen == "tab-userfriends":
return userfriends_layout
return html.P("This shouldn't be displayed for now...")
if __name__ == '__main__':
app.run_server(debug=True)
The problem is in code you haven't shared, but based on the error
dash.exceptions.InvalidCallbackReturnValue: The callback for <Output content.children>
returned a value having type Dash
which is not JSON serializable.
one of the layouts you return in your switch_tab callback returns an instance of a Dash app.
You can't do this:
In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.
I am trying to build a webpage with dash plotly. I want it to be interactive so whenever I insert values and click on the button.
Therefore, I use request on the API to get the results.
However, for some reason in terminal I can only see :
"ERROR in app: Exception on /_dash-update-component [POST]"
before inserting the values then it starts giving me success code
"POST /_dash-update-component HTTP/1.1" 200
Can anyone tell me how to solve the initial error?
Here is my code:
import json
import base64
import datetime
import requests
import pathlib
import math
import pandas as pd
import flask
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import dash_bootstrap_components as dbc
import plotly.express as px
from dash.dependencies import Input, Output, State
from plotly import tools
def fig1(data):
colors = {
'background': '#000220',
'text': '#FFFFFF'
}
today=datetime.datetime.today().strftime("%Y -%m -%d")
df_nested=data
df = df_nested.loc[df_nested['timestamp']>=today].groupby(['contract_name','contract_ticker_symbol']).mean('close.quote').reset_index()
fig = px.pie(df, values='close.quote', names='contract_name',labels={ "contract_name":'Contract Name',
"close.quote": "USD Value"} , title='Asset Allocation', color_discrete_sequence=px.colors.sequential.Plasma)
fig.update_traces(textposition='inside')
# fig.update_layout(uniformtext_minsize=12, uniformtext_mode='hide')
fig.update_layout(plot_bgcolor=colors['background'], paper_bgcolor=colors['background'],font_color=colors['text']
)
return fig
def fig2(data):
colors = {
'background': '#000220',
'text': '#FFFFFF'
}
df_nested=data
fig2=px.line(df_nested, x="timestamp", y="close.quote", color="contract_name",line_group="contract_ticker_symbol",labels={
"contract_name":'Contract Name',
"timestamp": "Date",
"close.quote": "USD Value",
"contract_ticker_symbol": "Ticker"
}, title='Asset Value Over Time', hover_name="contract_ticker_symbol",)
fig2.update_layout(plot_bgcolor=colors['background'], paper_bgcolor=colors['background'],font_color=colors['text'])
return fig2
app = dash.Dash(
__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = ""
server = app.server
PATH = pathlib.Path(__file__).parent
# API Requests for news div
news_requests = requests.get(
"https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=API_KEY"
)
# API Call to update news
def update_news():
json_data = news_requests.json()["articles"]
df = pd.DataFrame(json_data)
df = pd.DataFrame(df[["title", "url"]])
max_rows = 10
return html.Div(
children=[
html.P(className="p-news", children="Headlines"),
html.P(
className="p-news float-right",
children="Last update : "
+ datetime.datetime.now().strftime("%H:%M:%S"),
),
html.Table(
className="table-news",
children=[
html.Tr(
children=[
html.Td(
children=[
html.A(
className="td-link",
children=df.iloc[i]["title"],
href=df.iloc[i]["url"],
target="_blank",
)
]
)
]
)
for i in range(min(len(df), max_rows))
],
),
]
)
# Dash App Layout
app.layout = html.Div(
className="row",
children=[
# Interval component for live clock
dcc.Interval(id="interval", interval=1 * 1000, n_intervals=0),
# Interval component for ask bid updates
dcc.Interval(id="i_bis", interval=1 * 2000, n_intervals=0),
# Interval component for graph updates
dcc.Interval(id="i_tris", interval=1 * 5000, n_intervals=0),
# Interval component for graph updates
dcc.Interval(id="i_news", interval=1 * 60000, n_intervals=0),
# Left Panel Div
html.Div(
className="three columns div-left-panel",
children=[
# Div for Left Panel App Info
html.Div(
className="div-info",
children=[
html.Img(
className="logo", src=app.get_asset_url("covalent.png")
),
html.H6(className="title-header", children="Covalent Analytics"),
html.P(
"""
Covalent Analytics provide portfolio tracking services across chains
"""
),
],
),
# Div for News Headlines
html.Div(
className="div-news",
children=[html.Div(id="news", children=update_news())],
),
],
),
# Right Panel Div
html.Div(
className="nine columns div-right-panel",
children=[
# Panel for orders
html.Div(
id="bottom_panel",
className="row div-bottom-panel",
children=[
html.Div(
className="display-inlineblock",
children=[
dcc.Input(id="address", placeholder="Enter wallet address...", type="text"),
dcc.Dropdown(id='chain_id',placeholder="Select Chain", options = [
{"label": "Ethereum", "value": "1"},
{"label": "Matic", "value": "137"},
{"label": "Binance Smart Chain", "value": "56"},
{"label": "Avalanche", "value": "43114"},
{"label": "Fantom", "value": "250"}
],
value=[],
),
],
),
html.Div(
className="display-inlineblock float-right",
children=[
html.Button('Add Wallet', id='btn-1', n_clicks=0)
],
), html.Div(id='container')
],
),
],
),
],
)
#JSON NORMALIZE
def normalize(data):
df=data['items']
df=pd.json_normalize(df,record_path=['holdings'],meta=['contract_ticker_symbol','contract_name',"contract_address"])
df=df[['contract_ticker_symbol','contract_name',"contract_address",'timestamp','close.quote']]
return df
#SET TIME FORMAT
def set_time(data):
return pd.to_datetime(data['timestamp'])
#app.callback(Output('container', 'children'),
Input("chain_id", "value"),
Input("address", "value"),)
def display(value,address):
ctx = dash.callback_context
api_key= "####"
if not ctx.triggered:
pass
else:
response = requests.get(f"https://api.covalenthq.com/v1/{value}/address/{address}/portfolio_v2/?format=format%3Dcsv&key={api_key}")
data=normalize(response.json())
data['timestamp']=set_time(data)
return [
dcc.Graph(
id='graph1',
figure=fig1(data)
),
dcc.Graph(
id='graph2',
figure=fig2(data)
)
]
# Dynamic Callbacks
# Function to open or close STYLE or STUDIES menu
def generate_open_close_menu_callback():
def open_close_menu(n, className):
if n == 0:
return "not_visible"
if className == "visible":
return "not_visible"
else:
return "visible"
return open_close_menu
# Function for hidden div that stores the last clicked menu tab
# Also updates style and studies menu headers
def generate_active_menu_tab_callback():
def update_current_tab_name(n_style, n_studies):
if n_style >= n_studies:
return "Style", "span-menu selected", "span-menu"
return "Studies", "span-menu", "span-menu selected"
return update_current_tab_name
# Function show or hide studies menu for chart
def generate_studies_content_tab_callback():
def studies_tab(current_tab):
if current_tab == "Studies":
return {"display": "block", "textAlign": "left", "marginTop": "30"}
return {"display": "none"}
return studies_tab
# Function show or hide style menu for chart
def generate_style_content_tab_callback():
def style_tab(current_tab):
if current_tab == "Style":
return {"display": "block", "textAlign": "left", "marginTop": "30"}
return {"display": "none"}
return style_tab
# Callback to update news
#app.callback(Output("news", "children"), [Input("i_news", "n_intervals")])
def update_news_div(n):
return update_news()
if __name__ == "__main__":
app.run_server(debug=False)
I am trying to add multiple navigations for the same URL path.
my code..
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
app = dash.Dash()
index_layout = html.Div([
# represents the URL bar, doesn't render anything
dcc.Location(id='url', refresh=False),
html.Br(),
dcc.Link(dbc.Button('Page1',
color="secondary",
className="mr-1",
outline=True,
style={"width":400,
"vertical-align": "middle",
}
), href='/page1'),
html.Br(),html.Br(),html.Br(),html.Br(),html.Br(),
dcc.Link(dbc.Button("Page2",
style={"width":400,
"vertical-align": "middle"},
color="secondary",
className="mr-1",
outline=True
), href='/page2'),
])
page1_layout = html.H1("Page1")
page2_layout = html.H1("Page2")
app.layout = html.Div([
dcc.Location(id='url-nav', refresh=True),
html.Span(dbc.Nav(
[
dbc.NavLink(dbc.NavLink("Page1", href="/page1")),
dbc.NavLink(dbc.NavLink("Page2", href="/page2")),
],
pills=True,),
className="ml-auto"
),
dcc.Location(id='url', refresh=True),
html.Center([
html.H3('DEMO AP',id='title'),
# content will be rendered in this element
html.Div(id='page-content'),
],),
])
### CALLBACKS
#app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname="/"):
ctx = dash.callback_context
triggered_by = ctx.triggered[0].get("prop_id")
if pathname == "/page1":
return page1_layout
elif pathname == "/page2":
return page2_layout
else:
return index_layout
if __name__ == "__main__":
app.run_server()
Button navigations are working fine, but html.Nav only works on the very first click, not consistent and not working on the following clicks.
Kindly help.
From testing this out the problem seems to be with this line in index_layout:
dcc.Location(id='url', refresh=False),
If you look in the console you will see that a lot of requests are sent constantly when you're on the main page (when index_layout is rendered).
When this line is removed your code works as expected.
Working solution:
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
app = dash.Dash()
index_layout = html.Div(
[
html.Br(),
dcc.Link(
dbc.Button(
"Page1",
color="secondary",
className="mr-1",
outline=True,
style={
"width": 400,
"vertical-align": "middle",
},
),
href="/page1",
),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
dcc.Link(
dbc.Button(
"Page2",
style={"width": 400, "vertical-align": "middle"},
color="secondary",
className="mr-1",
outline=True,
),
href="/page2",
),
]
)
page1_layout = html.H1("Page1")
page2_layout = html.H1("Page2")
app.layout = html.Div(
[
dcc.Location(id="url-nav", refresh=True),
html.Span(
dbc.Nav(
[
dbc.NavLink(dbc.NavLink("Page1", href="/page1")),
dbc.NavLink(dbc.NavLink("Page2", href="/page2")),
],
pills=True,
),
className="ml-auto",
),
dcc.Location(id="url", refresh=True),
html.Center(
[
html.H3("DEMO AP", id="title"),
# content will be rendered in this element
html.Div(id="page-content"),
],
),
]
)
### CALLBACKS
#app.callback(
dash.dependencies.Output("page-content", "children"),
[dash.dependencies.Input("url", "pathname")],
)
def display_page(pathname="/"):
ctx = dash.callback_context
triggered_by = ctx.triggered[0].get("prop_id")
if pathname == "/page1":
return page1_layout
elif pathname == "/page2":
return page2_layout
else:
return index_layout
if __name__ == "__main__":
app.run_server()
The problem here I think is that there are two Location components rendered at the same time with the same id (url). This apparently causes the callback to be called constantly and causes inconsistent link behavior.
I have a function that dynamically creates a set of buttons:
def generate_team_button(team_shortName):
return dbc.Button(
str(team_shortName),
className="btn btn-primary",
id=str(team_shortName),
style={
"margin-right": "10px",
"margin-bottom": '10px',
},
n_clicks=0,
)
These buttons are displayed by looping through a set of items
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input
from dash.dependencies import Output
from dash.dependencies import State
import pandas as pd
data = {'teams': ['team1', 'team2', 'team3', 'team4']}
df_teams = pd.DataFrame(data)
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(
[
dbc.Row([
dbc.Col(
children=[generate_team_button(i) for i in df_teams['teams']]
),
]),
dbc.Row([
dbc.Col(
id='section',
#WANT TO UPDATE THIS SECTION BASED ON WHICH BUTTON IS BEEING CLICKED
),
]),
]
),
What I want to do is to update id=section based on which button is being pressed. To do that I need a #app.callback like below. But what I get is a tuple with how many times each button has been pressed.
#app.callback(
[
Output('league-table', 'value'),
],
[
Input(str(i), 'n_clicks') for i in df_teams['teams']
]
)
def update_league_table(*args):
print(args)
return f'{args}'
How can I update a section based on which button has been clicked?
This information is available via the callback_context object. Here is a small example,
import dash
import dash_html_components as html
from dash.dependencies import Output, Input
from dash import callback_context
n_buttons = 5
# Create example app.
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Button {}".format(i), id=str(i)) for i in range(n_buttons)] + [html.Div(id="log")])
#app.callback(Output("log", "children"), [Input(str(i), "n_clicks") for i in range(n_buttons)])
def func(*args):
trigger = callback_context.triggered[0]
return "You clicked button {}".format(trigger["prop_id"].split(".")[0])
if __name__ == '__main__':
app.run_server()
For additional details, see the documentation on advanced callbacks.