Dash: how to write callback for html.Form component - python

I am developing a dash app. I am creating a form using html.Form component.
html.Form(
id="form_upload",
name="form_upload",
method="POST",
action="/upload",
encType="multipart/form-data",
# accept="application/octet-stream",
children=[
dbc.Input(id="ip_name", name="ip_name", type="text"),
dbc.Input(id="ip_upload", name="ip_upload", type="file"),
dbc.Input(id="ip_submit", name="ip_submit", type="submit"),
],
),
But I have no clue how to write a callback for above form, so that I can access and process the form inputs(request payload) i.e. name and file contents.
I read offical document and searched alot but didnot find any demo or example.
Please help.

do you want the callback to trigger whenever an input is typed (for every letter)? If so you can trigger the callback using the 'value' parameter from the Input field. See dbc examples below:
import dash_bootstrap_components as dbc
from dash import Input, Output, html
text_input = html.Div(
[
dbc.Input(id="input", placeholder="Type something...", type="text"),
html.Br(),
html.P(id="output"),
]
)
#app.callback(Output("output", "children"), [Input("input", "value")])
def output_text(value):
return value
If you dont want it to trigger with every input, you should add a submit button to the form. In which case you can use the Buttons n_click parameter for the trigger:
import dash_bootstrap_components as dbc
from dash import Input, Output, html
button = html.Div(
[
dbc.Button(
"Click me", id="example-button", className="me-2", n_clicks=0
),
html.Span(id="example-output", style={"verticalAlign": "middle"}),
]
)
#app.callback(
Output("example-output", "children"), [Input("example-button", "n_clicks")]
)
def on_button_click(n):
if n is None:
return "Not clicked."
else:
return f"Clicked {n} times."
Good luck =)

Related

Retrieve Hex or RGB values from Bootswatch theme via python/dash

I am currently creating a dashboard using dash with figures using plotly. I am using the bootswatch themes (https://bootswatch.com/) with bootstrap components to style the dashboard and I was wondering if there was a way to retrieve the primary, secondary, success etc. colours into either RGB or HEX so that I don't have to hard code it in and can then parse these into plotly functions to style the graphs in the same theme.
As of writing this there isn't a way to do it with Python only.
A dash bootstrap components theme is just a uri pointing to a stylesheet.
>>> dbc.themes.BOOTSTRAP
https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css
For the stylesheets in external_stylesheets link elements are generated and added to the document.
So there isn't a property on a theme or on the app that holds the value of the css variables.
A workaround solution is to use clientside callbacks:
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input
import dash_bootstrap_components as dbc
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div([dcc.Store(id="intermediate-store"), dcc.Store(id="color-store")])
app.clientside_callback(
"""
function(val) {
const bodyStyles = window.getComputedStyle(document.body);
return {
primary: bodyStyles.getPropertyValue("--primary"),
secondary: bodyStyles.getPropertyValue("--secondary"),
success: bodyStyles.getPropertyValue("--success"),
};
}
""",
Output("intermediate-store", "data"),
Input("intermediate-store", "data"),
)
#app.callback(
Output("color-store", "data"),
Input("intermediate-store", "data"),
)
def update_output_div(data):
# data equals: {'primary': '#007bff', 'secondary': '#6c757d', 'success': '#28a745'}
return data
if __name__ == "__main__":
app.run_server(debug=True)
So the idea in the code above is to use Javascript in clientside callbacks to retrieve the css variables and store them in an intermediate Store. When it's stored we can use another callback to retrieve the value as a dictionary and do something with it.
You could use it by setting a variable when the second callback is triggered or you could use State("color-store", "data") in other callbacks.

How to use multiple States in Dash callback?

I want to use multiple states in one callback. I didnt get it to work so I checked the below example from the documentation in which multiple states are used in a callback. Yet, when I run this code I get the error:
The input argument submit-button-state.n_clicks must be a list or tuple of
dash.dependencies.Inputs
Two questions:
Did something change and is the documentation outdated? (which seems unlikely as they have excellent documentation)
How do I get this to work?
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id='input-1-state', type='text', value='Montréal'),
dcc.Input(id='input-2-state', type='text', value='Canada'),
html.Button(id='submit-button-state', n_clicks=0, children='Submit'),
html.Div(id='output-state')
])
#app.callback(Output('output-state', 'children'),
Input('submit-button-state', 'n_clicks'),
State('input-1-state', 'value'),
State('input-2-state', 'value'))
def update_output(n_clicks, input1, input2):
return u'''
The Button has been pressed {} times,
Input 1 is "{}",
and Input 2 is "{}"
'''.format(n_clicks, input1, input2)
if __name__ == '__main__':
app.run_server(debug=True)
The code in the question works – in recent versions of Dash, the current version being 1.20.0.
The requirement to have all Output, Input and State arguments of #app.callback in three seperate lists (as suggested in the answer by Ger) was removed in August 2020 in version 1.15.0 (see release notes). As seen by the examples in the documentation, doing so is not recommended anymore. If at all possible, update your Dash version instead of switching to the old style.
It is as straight forward as the error suggests. I already tried it some ties, but probably I made a typo somewhere.
The solution is to put the inputs, outputs and states all in a seperate list.
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id='input-1-state', type='text', value='Montréal'),
dcc.Input(id='input-2-state', type='text', value='Canada'),
html.Button(id='submit-button-state', n_clicks=0, children='Submit'),
html.Div(id='output-state')
])
#app.callback([Output('output-state', 'children')],
[Input('submit-button-state', 'n_clicks')],
[State('input-1-state', 'value'),
State('input-2-state', 'value')])
def update_output(n_clicks, input1, input2):
return u'''
The Button has been pressed {} times,
Input 1 is "{}",
and Input 2 is "{}"
'''.format(n_clicks, input1, input2)
if __name__ == '__main__':
app.run_server(debug=True)

Changing the pattern-matching call depending on value of radio button in Dash

I am creating a Dash app that allows the user to either enter URLS to be screenshot and then analyzed or the user can upload their own images. I am trying to get the main app.py file right so the inputs can be sent to one of three different functions (one that only takes screenshots of the websites they listed, one that uses robots to search for similar websites and then takes screenshots of those to be analyzed, or just having the user upload their own images to be analyzed). Note that once they hit the "Submit" button, that the relevant inputs (the email, company name, and URL/images) will be passed off to an rq job. I understand how to do this part, so for the example, we can just print out the relevant inputs in the web app just to confirm that we have the right inputs.
The idea for the UI is that it would first have a section to put your email (and other info), and then start with radio buttons for each screenshot option. Then depending on the user's preference of the inputs they want to provide, they would either be shown a place for them to enter the different URLs or a place to upload their images (See image here).
It seems that pattern-matching would be useful for them to add more URLs, but I can't quite figure out how to allow different types of inputs using it. Here's what I have so far:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, MATCH, ALL
app = dash.Dash(__name__, external_stylesheets = ['https://codepen.io/chriddyp/pen/dZVMbK.css'])
server = app.server
app.layout = html.Div([
html.Div([
html.H6("""E-mail address:"""),
dcc.Input(
id='rec-email',
placeholder="youremail#domain.com",
size=30
),
html.H6("""Company Name:"""),
dcc.Input(
id='company-name',
size=30
),
]),
html.Div([
dcc.RadioItems(
id='radio-option',
options=[
{'label': "Only analyze these websites", 'value': 'exact_sites'},
{'label': "Allow robot to analyze additional related websites", 'value': 'robot_sites'},
{'label': "I want to upload my own images", 'value': 'upload_images'}
],
value='exact_sites'
),
]),
html.Div(id='website-methods-output')
])
#app.callback(
Output('website-method', 'children'),
[Input('radio-option', 'value')],
[State('rec-email', 'value'),
State('company-name', 'value')]
)
def display_inputs(radio_option, email, company):
if radio_option=="upload_images":
return html.Div([
id='inputs-start',
dcc.Upload(
id='input-upload',
children=html.Div([
'Drag and Drop or ',
html.A('Select Image to be Analyzed.')
]),
style={
'width': '30%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
# Allow multiple files to be uploaded
multiple=False # Maybe change to True?
),
children=[],
html.Button("Add Image", id="add-image", n_clicks=0)
])
else:
return html.Div([
id='inputs-start'
dcc.Input(
placeholder='www.website.com'
),
children=[],
html.Button("Add URL", id="add-url", n_clicks=0)
])
if __name__ == '__main__':
app.run_server(debug=True)
What if you have an input for each of the possible radio button options, but only show the one that's selected? You can set up pattern-matching callbacks for all the inputs, and use just one at a time. Perhaps a change to the radio button selection would not only change which options are shown/hidden, but clear all of them as well, so you can be sure to accept only entries in the correct one.
Edit:
This really goes beyond the scope of a single question, so I'm leaving out a lot of details here to keep from writing an entire Dash app. I hope this helps. These are some possible function definitions for each of the different types of callbacks I mentioned in the comments.
Show/hide sections
#app.callback(
Output('inputs-container', 'children'),
[Input('radio-option', 'value')])
def callback_func_show_hide(radio_selection):
# Add the function logic
pass
Add a new input for a section
#app.callback(
Output('inputs-type-1-container', 'children'),
[Input('add-input-1', 'n_clicks')]
[State('inputs-type-1-container', 'children')])
def callback_func_add_input_1(add_input_click, previous_children):
# Add the function logic. You'll need the previous_children in
# order to append new inputs
pass
Use inputs from a section
#app.callback(
Output('some-output', 'children'),
[Input({'type': 'upload-1', 'index': dash.dependencies.ALL}, 'value')])
def callback_func_process_upload_1(uploaded_data_list):
# Add the function logic. Use uploaded_data_list to process everything.
# Output can be whatever you want to let the user know the task is done
pass

Python plotly dash - button to link to webpage

I am using python dash and I'd like to have a button below my table that when clicked, will take the user to a specific webpage. I am very - VERY - new to using dash so I'm not even sure if this functionality exists. I did search this topic specifically to python dash and came up empty handed. Any and all help is appreciated, thank you!
You can use dash_bootstrap_components or dbc to do that. Check this page for more detailed information about dbc: https://dash-bootstrap-components.opensource.faculty.ai/docs/components/button/
To summarize, what you need to do:
If you haven't done yet, pip install dbc:
pip install dash-bootstrap-components
Import it to your code:
import dash_bootstrap_components as dbc
Configure your app with one of the dbc themes. When you creat the app, just include an external_stylesheet:
app = Dash(external_stylesheets=[dbc.themes.CYBORG])
Include the dbc.Button componen in your app (see examples in documentation or below).
Here is an example:
from dash import Dash, html
import dash_bootstrap_components as dbc
app = Dash(external_stylesheets=[dbc.themes.CYBORG])
app.layout = html.Div([
html.Div("Default format"),
dbc.Button(
children='Open Page',
id='button_plain',
href = "https://stackoverflow.com/"),
html.Br(),
html.Br(),
html.Br(),
html.Div("Modify format"),
dbc.Button(
children='Open Page',
id='button_format',
color = "primary",
outline = True, #more lightweight format
size = "lg", #sm, lg
href = "https://stackoverflow.com/"),
])
if __name__ == '__main__':
app.run_server(debug=True)
More about dbc Themes: https://bootswatch.com/
use this for button example and to learn more please use this
link:https://dash.plotly.com/dash-core-components.
import dash
import dash_html_components as html
import dash_core_components as dcc
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Div(dcc.Input(id='input-box', type='text')),
html.Button('Submit', id='button'),
html.Div(id='output-container-button',
children='Enter a value and press submit')
])
#app.callback(
dash.dependencies.Output('output-container-button', 'children'),
[dash.dependencies.Input('button', 'n_clicks')],
[dash.dependencies.State('input-box', 'value')])
def update_output(n_clicks, value):
return 'The input value was "{}" and the button has been clicked {} times'.format(
value,
n_clicks
)
if __name__ == '__main__':
app.run_server(debug=True)

Python Plotly Dash - How do I access updated component value without using callback?

When you enter something other than "test" in the input box, and press enter, the label should change to reflect that input.
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
markerNameInp = dbc.Input(id='markerNameInp',placeholder='Enter name..',
style={'min-width':'150px','width':'15%',
'margin-right':'20px','display':'inline-block',
'margin-bottom':'10px'}, value = 'test')
app = dash.Dash()
app.layout = html.Div(style={'font':'Frutiger Linotype, sans-serif',
'margin-left':'50px','margin-right':'50px'},
children=[
html.Div([markerNameInp]),
dbc.Button('Enter',id='enter',
color = 'primary',
className='mr-1',
style={'height':'40px'}),
html.Div(id="output")
])
#app.callback(
Output(component_id='output', component_property='children'),
[Input(component_id='enter', component_property='n_clicks')]
)
def func(enter_clicks):
return dbc.Label(markerNameInp.value)
if __name__ == "__main__":
app.run_server(debug=True)
Thanks in advance.
It is not possible to access an updated component value by accessing the Python object defined in the layout (markerNameInp.value). This is because each user accessing the Dash app will interact with it differently, and the state is stored on the client-side (the user's browser) rather than server-side (where the app is running, and where the Python object markerNameInp is located).
In your use case, it is possible to access the value property of markerNameInp by using dash.dependencies.State, which does not trigger the callback when the component is updated, but the value can still be captured.
Here's the updated code:
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
markerNameInp = dbc.Input(
id="markerNameInp",
placeholder="Enter name..",
style={
"min-width": "150px",
"width": "15%",
"margin-right": "20px",
"display": "inline-block",
"margin-bottom": "10px",
},
value="test",
)
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(
children=[
html.Div([markerNameInp]),
dbc.Button("Enter", id="enter", color="primary", className="mr-1"),
html.Div(id="output"),
],
)
#app.callback(
Output("output", "children"),
[Input("enter", "n_clicks")],
[State("markerNameInp", "value")]
)
def func(n_clicks, marker_value):
return dbc.Label(marker_value)
if __name__ == "__main__":
app.run_server(debug=True)
(the bootstrap code was changed in order to reflect best practice, and some styling was removed for simplicity).

Categories