Related
Want to create a dash board, with two or more inputs, a submit button at the end of inputs that outputs a table. I am having trouble creating properly spaced inputs, placing the button and formatting the output table.
import pandas as pd
import dash
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output, State
df1 = pd.DataFrame({{'col1': [1, 2], 'col2': [3, 4]}})
df1 = df1 + 100
df3 = df1 -100
df4 = df1/2
app = dash.Dash()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Markdown(children= ''' Drop Down''')
]),
dcc.Dropdown(id = 'dd',
options = [{'label' : 'NY', 'value' : 'NY'},
{'label' : 'SF', 'value' : 'SF'}],
value = 'NY'
)
],
style = {'width':'48%', 'display':'inline-block'}
),
html.Div([
html.Div([
dcc.Markdown(children= ''' Input''')
]),
dcc.Input(id = 'x',
placeholder='Enter a value...',
value = '',
type = 'number',
max = 1.0,
min = 0.0
),
],
style = {'width':'48%', 'display':'inline-block'}
),
html.Button(id = 'submit',
# n_clicks = 0,
children = 'Submit here',
style = {'fontsize':24}
),
html.Div(id = 'table')
])
#app.callback(Output(component_id = 'table',
component_property = 'children'),
[Input(component_id ='dd',
component_property = 'value'),
Input(component_id ='x',
component_property = 'value')
],
[State('submit', 'value')]
)
def risk(dd, d):
if ((dd == 'NY') and (d <0.5)):
table = df1
elif ((dd == 'NY') and (d >= 0.5)):
table = df2
elif ((dd == 'SF') and (d <0.5)):
table = df3
else :
table = df4
return dbc.Table.from_dataframe(table,
striped=True,
bordered=True,
hover=True)
if __name__ == '__main__':
app.run_server()
I ran the above after commenting out the html.Button and the State part. It runs.
How can I properly include the button such that the table is produced only when I input all inputs and click submit?
How can I better format the table with borders?
Here is how my html looks like, when I run after removing Button and State.
This is ugly. Help me format better.
PS - I want the puts(Drop Down and Input take equal space, and are on the same line. Submit button should ideally be in the middle, right below the inputs.
I am new to dash and I am also requiring the guidance in the same matter, I have a code with the cascaded radio buttons, I want to add the Start button and after clicking the Start button the dash should start displaying the data, but currently its just opening and displaying the data.
I also need help , as I have auto-update in my dash, will there be any contradiction if I need to add Start button and then dash should display the data and auto update the values.
I am new to Python and have limited coding experience, so any input and advice is deeply appreciated.
I have created a dynamic choropleth map which includes a scatter_geo plot that overlays the relevant areas.
I am trying create a hover callback so that when I hover over one of these points, a dataframe appears that is indexed according to the point id (the first column in the defined dataframe). Essentially, it is a choropleth map equivalent of this example: https://plotly.com/python/v3/cars-exploration/ but without using FigureWidget.
I keep getting stuck on the hover callback function; no dataframe displays when I hover. Below is the code I have so far.
license_df1 = pd.read_excel(lic, "Primary Holdings by License", dtype = "str").fillna('')
license_df2 = pd.read_excel(lic, "Secondary Holdings by License", dtype = "str").fillna('')
### CREATE PLOTTING FEATURES ###
app = dash.Dash(__name__, suppress_callback_exceptions = True)
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True
app.layout = html.Div([
html.P("Spectrum Band:"), # Create Toggle Items between spectrum bands
dcc.RadioItems(id = "Band", options=[{'value': x, 'label':x} for x in df1_band], value = df1_band[0]),
dcc.Graph(id = "choropleth"),
dash_table.DataTable(id = "table")])
#app.callback(
Output("choropleth", "figure"),
[Input("Band", "value")])
def build_graph(value):
if value == '600 MHz':
df1_600 = df1[(df1["Band"] == "600 MHz")]
fig1 = px.choropleth(df1_600, geojson = PEAs, featureidkey = "properties.PEA_Num",
locations = 'PEA # ', hover_data = {'PEA # ': False}, scope = "usa")
# Overlay Geographic Scatter Plot for interactive functionality
fig1b = px.scatter_geo(df1_600, geojson = PEAs, featureidkey = "properties.PEA_Num",
locations = 'PEA # ', hover_name = 'Market', scope = "usa")
fig1.add_trace(fig1b.data[0])
fig1.update_traces(showlegend = False)
fig1.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
return fig1
elif value == '3.7 GHz':
df1_3700 = df1[(df1["Band"] == "3.7 GHz")]
fig2 = px.choropleth(df1_3700, geojson = PEAs, featureidkey = "properties.PEA_Num",
locations = 'PEA # ', hover_data = {'PEA # ': False}, scope = "usa")
# Overlay Geographic Scatter Plot for interactive functionality
fig2b = px.scatter_geo(df1_3700, geojson = PEAs, featureidkey = "properties.PEA_Num",
locations = 'PEA # ', hover_name = 'Market', scope = "usa")
fig2.add_trace(fig2b.data[0])
fig2.update_traces(showlegend = False)
fig2.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
return fig2
#app.callback(
Output("table", "data"),
[Input("fig1", "hover_data")]) # WHERE I AM HAVING TROUBLE
def disp_license1(hover_data):
table_vals = license_df1.iloc[points.point_inds[0]].to_frame().to_html()
return table_vals
app.run_server(debug = True)
I made a Dash app that graphs Stock Market data from my SQL database. The app uses one input that can have multiple values. For my case, this input strictly only refers to stocks. Hence, users can chain multiple stocks in an input to create a plot with their prices, on top of each other. Using the Flask #callback methods, I am able to do that.
The graph is not working, the input bar works great and users can select multiple stocks. For sure it has to do with the data that is being passed but I can't locate where and the more I seem to fix it the more it breaks...
Check out my code below:
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import dash_html_components as html
from dash.exceptions import PreventUpdate
#PostgreSQL Connection
from connect import *
# CSS
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
# Pre-load:
stock_ids = execute_query(conn, "SELECT DISTINCT id FROM security_price;")
stock_ids = [i[0] for i in stock_ids]
options = [{'label': i, 'value': i} for i in stock_ids]
# Create Dash app
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Create app layout
app.layout = html.Div(
[ html.Div(className='row', # Define the row element
children=[
# left element
html.Div(className='eight columns div-user-controls',
children = [
html.H2('SP500 Equity Analyzer'),
html.P(''' Compare stocks on your watchlist.'''),
dcc.Dropdown(id="my-multi-dynamic-dropdown", options=options, multi=True, placeholder="Select a Symbol"),
dcc.Graph(id='timeseries', config={'displayModeBar': False}),
]
),
# right element
html.Div(className='four columns div-for-charts bg-grey'),
]),
])
# User callbacks
#user input
#app.callback(
dash.dependencies.Output("my-multi-dynamic-dropdown", "options"),
[dash.dependencies.Input("my-multi-dynamic-dropdown", "search_value")],
[dash.dependencies.State("my-multi-dynamic-dropdown", "value")],
)
def update_multi_options(search_value, value):
if not search_value:
raise PreventUpdate
else:
return [
o for o in options if search_value in o["label"] or o["value"] in (value or [])
]
# timeseries graph
#app.callback(Output('timeseries', 'figure'),
[Input("my-multi-dynamic-dropdown", 'search_value')],
[State("my-multi-dynamic-dropdown", "value")],
)
def update_timeseries(input_data, state):
if input_data == None:
raise PreventUpdate
if state == None:
raise PreventUpdate
# Draw and append traces for each stock
trace = []
for stock in input_data:
stock_info = execute_query(conn, f"SELECT date, close FROM security_price WHERE security_price.id = '{stock}' ;")
for row in stock_info:
date = []
adj_close = []
date.append(row[0])
adj_close.append(row[1])
# STEP 2
trace.append(go.Scatter(x=date,
y=adj_close,
mode='lines',
opacity=0.7,
name=stock,
textposition='bottom center'))
# STEP 3
traces = [trace]
data = [val for sublist in traces for val in sublist]
# Define Figure
# STEP 4
figure = {'data': traces,
'layout': go.Layout(
colorway=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'],
template='plotly_dark',
paper_bgcolor='rgba(0, 0, 0, 0)',
plot_bgcolor='rgba(0, 0, 0, 0)',
margin={'b': 15},
hovermode='x',
autosize=True,
title={'text': 'Stock Prices', 'font': {'color': 'white'}, 'x': 0.5},
),
}
return figure
if __name__ == '__main__':
app.run_server(debug=True)
This is the error I get:
Invalid argument `figure.data[0]` passed into Graph with ID "timeseries".
Expected `object`.
Was supplied type `array`.
Alongside this Javascript error from Dash:
Error: Invalid argument `figure.data[0]` passed into Graph with ID "timeseries".
Expected `object`.
Was supplied type `array`.
at propTypeErrorHandler (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/dash_renderer.v1_8_0m1599348644.dev.js:90547:9)
at CheckedComponent (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/dash_renderer.v1_8_0m1599348644.dev.js:84930:77)
at renderWithHooks (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:14960:20)
at updateFunctionComponent (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:17193:22)
at beginWork (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:18778:18)
at HTMLUnknownElement.callCallback (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:182:16)
at Object.invokeGuardedCallbackDev (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:231:18)
at invokeGuardedCallback (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:286:33)
at beginWork$1 (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:23369:9)
at performUnitOfWork (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom#16.v1_8_0m1599348644.13.0.js:22323:14)
Would greatly appreciate where my program went wrong.
This is where your problem is coming from:
# Draw and append traces for each stock
trace = []
for stock in input_data:
stock_info = execute_query(conn, f"SELECT date, close FROM security_price WHERE security_price.id = '{stock}' ;")
for row in stock_info:
date = []
adj_close = []
date.append(row[0])
adj_close.append(row[1])
# STEP 2
trace.append(go.Scatter(x=date,
y=adj_close,
mode='lines',
opacity=0.7,
name=stock,
textposition='bottom center'))
# STEP 3
traces = [trace]
You've made trace a list, and then put that into traces, another list. You should put all of the go.Scatter objects into traces, so that the list contains Scatter objects, not sub-lists.
I am trying to add interactivity to a plotly 3d scatter plot which I am hosting using dash. My question contains two related parts:
(i) I would like to manually select points in my 3d scatter and change the selected points' colour to red. Selection should include click event and selection event.
(ii) I would like to be able to delete these points from the plot on pressing of a key e.g. 'delete' key.
Part (i) is similar to an example in the plotly guide https://plot.ly/python/click-events/, however, on_click is not available as a method for 3d scatter charts.
I have been attempting to use FigureWidget as that apparently provides methods to capture clicks and selections, but after 2 days I am struggling to make headway.
Example data (copy below to clipboard and run df = pd.read_clipboard(sep=','))
id,x_val,z_val,y_val
a,11.313449728149418,0.13039110880256777,0.5386387766748618
b,11.321463427315383,0.2360697833061771,1.32441455152796
c,10.127132005050942,0.23085014016641864,1.0961116175427044
d,11.639819269465233,0.0958798324712593,0.6506370305953094
e,8.892696370438149,0.08223988244819926,0.6440321391968353
f,6.711586646011124,0.3657515974938044,
g,7.095030650760687,,0.5723062047617504
h,6.4523124528415,,1.293852184258803
i,7.165105300812886,0.4151365420301895,-0.5920674079031845
j,7.480703395137295,0.14284429977557123,1.0600936940126982
k,5.570775744372319,,
l,4.358946555449826,,
I have example code below which I hope is almost there (but not quite). The idea is that 'handle_click' should capture click events. I should also handle 'selection' events, although I am not sure how to do this as 3d scatter plot does not provide a selection box or lassoo tool. With the callback, I'm not even sure how to initiate, as there is no clickData/selectionData event with 3d scatterplot that I can utilize (so [Input('subindustry-dropdown', 'value')]) is incorrect and note that subindustry-dropdown is not something that I have provided in the example, but I select my ids from a dropdown which returns a subindustry value in my development version. )
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.css.append_css({
"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})
app.layout = html.Div([html.Div(id = '3d-scatter'),
])
# Calculate and store data
#app.callback(Output('3d-scatter', 'children'),
[Input('subindustry-dropdown', 'value')])
def chart_3d():
f = go.FigureWidget(px.scatter_3d(df, x = 'x_val', y = 'y_val', z = 'z_val', hover_name = 'company_nm'))
f.layout.clickmode = 'event+select'
f.data[0].on_click(handle_click) # if click, then update point/df.
return dcc.Graph(id = '3d_scat', figure=f)
def handle_click(trace, points, selector):
c = list(f.data[0].marker.color)
s = list(f.data[0].marker.size)
for i in points.point_inds:
c[i] = '#bae2be'
s[i] = 20
with f.batch_update():
f.data[0].marker.color = c
f.data[0].marker.size = s
return f.data[0]
Here is a solution which allows:
selecting points by clicking individually
delete selected points by pressing html button
clear selection by pressing html button
according to this issue selecting multiple points in a 3d plot is currently not supported
(The use of FigureWidget does not seem to make a difference, so I removed it)
import dash
import plotly.express as px
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import pandas as pd
import json
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.css.append_css({
"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})
import pandas as pd
df = pd.DataFrame(columns=['x_val','z_val','y_val'])
df.loc['a'] = [11.313449728149418,0.13039110880256777,0.5386387766748618]
df.loc['b'] = [11.321463427315383,0.2360697833061771,1.32441455152796]
df.loc['c'] = [10.127132005050942,0.23085014016641864,1.0961116175427044]
df.loc['d'] = [11.639819269465233,0.0958798324712593,0.6506370305953094]
df.loc['e'] = [8.892696370438149,0.08223988244819926,0.6440321391968353]
df.loc['f'] = [6.711586646011124,0.3657515974938044,0]
df.loc['g'] = [7.095030650760687,0,0.5723062047617504]
df.loc['h'] = [6.4523124528415,0,1.293852184258803]
df.loc['i'] = [7.165105300812886,0.4151365420301895,-0.5920674079031845]
df.loc['j'] = [7.480703395137295,0.14284429977557123,1.0600936940126982]
df.loc['k'] = [5.570775744372319,0,0]
df.loc['l'] = [4.358946555449826,0,0]
def create_figure(skip_points=[]):
dfs = df.drop(skip_points)
return px.scatter_3d(dfs, x = 'x_val', y = 'y_val', z = 'z_val')
f= create_figure()
app.layout = html.Div([html.Button('Delete', id='delete'),
html.Button('Clear Selection', id='clear'),
dcc.Graph(id = '3d_scat', figure=f),
html.Div('selected:'),
html.Div(id='selected_points'), #, style={'display': 'none'})),
html.Div('deleted:'),
html.Div(id='deleted_points') #, style={'display': 'none'}))
])
#app.callback(Output('deleted_points', 'children'),
[Input('delete', 'n_clicks')],
[State('selected_points', 'children'),
State('deleted_points', 'children')])
def delete_points(n_clicks, selected_points, delete_points):
print('n_clicks:',n_clicks)
if selected_points:
selected_points = json.loads(selected_points)
else:
selected_points = []
if delete_points:
deleted_points = json.loads(delete_points)
else:
deleted_points = []
ns = [p['pointNumber'] for p in selected_points]
new_indices = [df.index[n] for n in ns if df.index[n] not in deleted_points]
print('new',new_indices)
deleted_points.extend(new_indices)
return json.dumps(deleted_points)
#app.callback(Output('selected_points', 'children'),
[Input('3d_scat', 'clickData'),
Input('deleted_points', 'children'),
Input('clear', 'n_clicks')],
[State('selected_points', 'children')])
def select_point(clickData, deleted_points, clear_clicked, selected_points):
ctx = dash.callback_context
ids = [c['prop_id'] for c in ctx.triggered]
if selected_points:
results = json.loads(selected_points)
else:
results = []
if '3d_scat.clickData' in ids:
if clickData:
for p in clickData['points']:
if p not in results:
results.append(p)
if 'deleted_points.children' in ids or 'clear.n_clicks' in ids:
results = []
results = json.dumps(results)
return results
#app.callback(Output('3d_scat', 'figure'),
[Input('selected_points', 'children'),
Input('deleted_points', 'children')],
[State('deleted_points', 'children')])
def chart_3d( selected_points, deleted_points_input, deleted_points_state):
global f
deleted_points = json.loads(deleted_points_state) if deleted_points_state else []
f = create_figure(deleted_points)
selected_points = json.loads(selected_points) if selected_points else []
if selected_points:
f.add_trace(
go.Scatter3d(
mode='markers',
x=[p['x'] for p in selected_points],
y=[p['y'] for p in selected_points],
z=[p['z'] for p in selected_points],
marker=dict(
color='red',
size=5,
line=dict(
color='red',
width=2
)
),
showlegend=False
)
)
return f
if __name__ == '__main__':
app.run_server(debug=True)
I have a function that takes a matplotlib plot and turns it into a plotly plot using tls.matplotlib_to_pyplot. In the end I named it plotly_fig. Now I'm trying to add sliders to a dash webapp. But when I compile it, I get an error saying plotly_fig is not defined.
The following is some sample code that recreates the error.
import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
from numpy.linalg import matrix_power
import matplotlib.pyplot as plt
import plotly.tools as tls
from mpl_toolkits.mplot3d import Axes3D
from dash.dependencies import Input, Output
app = dash.Dash()
#begin with the knobs
app.layout = html.Div([
dcc.Graph(
id = 'graph',
figure = plotly_fig),
html.Label('Config L'), ## this is the knob for the length
dcc.Slider(
id = 'l',
min = 5,
max = 10,
marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(5,10)},
value = L,
),
html.Label('Config n'), ##knob for the n-gon
dcc.Slider(
id = 'n',
min = 0,
max = 10,
marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,10)},
value = n,
),
html.Label('Config N'), ##knob for the number of n-gons outside initial
dcc.Slider(
id = 'N',
min = 0,
max = 10,
marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,10)},
value = N,
),
html.Label('Config r'), ##knob for r only works on integers for now
dcc.Slider(
id = 'r',
min = 0,
max = 2,
marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,2)},
value = r,
),
html.Label('Config d'), ##knoc for the depth of the dip
dcc.Slider(
id = 'd',
min = 0,
max = 2,
marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,2)},
value = d,
)
],
style = {'columnCount': 1})
#app.callback(
dash.dependencies.Output('graph', 'figure'),
[dash.dependencies.Input('l', 'value'),
dash.dependencies.Input('n', 'value'),
dash.dependencies.Input('N', 'value'),
dash.dependencies.Input('r', 'value'),
dash.dependencies.Input('d', 'value')])
def output(L,n,N,r,d):
x = np.linspace(np.pi, L*n*N*r*d*np.pi, 1000)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, sinx)
plotly_fig = tls.mpl_to_plotly(mpl_fig)
return{plotly_fig}
if __name__=='__main__':
app.run_server(debug = True)
What am I doing wrong?
The problem is that the variable plotly_fig is not even declared when you are trying to use it in the Graph's figure field. It is just declared locally in the callback.
It is not required to set the figure property of the Graph explicitly, It will be automatically mapped during the callback, so you can directly do it like this,
#your code here
app = dash.Dash()
#begin with the knobs
app.layout = html.Div([
dcc.Graph(
id = 'graph'), # ==> here you can remove the figure as it will be automatically set during the callback.
#your code here
],
style = {'columnCount': 1})
#app.callback(
dash.dependencies.Output('graph', 'figure'), #here figure represents the field
[dash.dependencies.Input('l', 'value'),
dash.dependencies.Input('n', 'value'),
dash.dependencies.Input('N', 'value'),
dash.dependencies.Input('r', 'value'),
dash.dependencies.Input('d', 'value')])
def output(L,n,N,r,d):
#your code here
plotly_fig = tls.mpl_to_plotly(mpl_fig)
return{plotly_fig}
if __name__=='__main__':
app.run_server(debug = True)
In the above snippet case, the value property of the Slider is the input of the app and the output of the app is the figure property of the Graph. Whenever the value of the Slider changes, Dash calls the callback function output with the new input values. The function filters the dataframe with this new value, constructs a figure object, and returns it to the Dash application.
Meanwhile, if you want a default value to be set even before the callback function is called you can declare plotly_fig as a global variable like this,
#your code here
plotly_fig = None # declare the default figure here
app = dash.Dash()
#begin with the knobs
app.layout = html.Div([
dcc.Graph(
id = 'graph', figure = plotly_fig),
#your code here
],
style = {'columnCount': 1})
#app.callback(
dash.dependencies.Output('graph', 'figure'),
[dash.dependencies.Input('l', 'value'),
dash.dependencies.Input('n', 'value'),
dash.dependencies.Input('N', 'value'),
dash.dependencies.Input('r', 'value'),
dash.dependencies.Input('d', 'value')])
def output(L,n,N,r,d):
#your code here
plotly_fig = tls.mpl_to_plotly(mpl_fig)
return{plotly_fig}
if __name__=='__main__':
app.run_server(debug = True)
For more information refer the official documentation page which has a similar example,
https://dash.plot.ly/getting-started-part-2