Related
How can I process when I have 2 callbacks functions with the same output (in that case : a graph) knowing that the first callback function returns a graph and a slider, whereas the input of 2nd callback function is the value of the new slider (created thanks to the first slider ) and returns also a graph (by adding new traces on the old traces)
The code is like that :
# Create Div to place a conditionally visible element inside
myslider = html.Div(
id='slider-container',
children=[
# Create a slider to hide/show
dcc.Slider(0,5,
step=1,
value=0,
id="newslider"
)
],
hidden=True,
)
mygraph = html.Div(dcc.Graph(id="graph", figure=go.Figure(go.Scattergeo())))
mydropdown = html.Div(dcc.Dropdown(['NYC', 'MTL', 'SF'], id="dropdown",
multi=True,
clearable=False))
layout = dbc.Container([mydropdown, mygraph, myslider,html.Div(id='slider-output-container',hidden=True)])
#app.callback(Output(component_id='graph', component_property='figure'),
Output(component_id='newslider', component_property='max'),
Output("newslider", "marks"),
Output(component_id='slider-container', component_property='hidden'),
Input(component_id='dropdown', component_property='value'),
Input(component_id='timeslider', component_property='value'),
State(component_id='newslider', component_property='max'),
State("newslider", "marks"),
prevent_initial_call=True
)
def create_graph_and_slider(dropdown,value,maxi,marks):
#created the initial traces of the graph associated to the newslider thanks to the value of dropdown
return fig, maxi, marks, False
#app.callback(Output(component_id='slider-output-container', component_property='children'),
Output(component_id='slider-output-container', component_property='hidden'),
Output(component_id='graph', component_property='figure'),
Input(component_id='newslider', component_property='value'),
prevent_initiall_call=True
)
def update_graph_from_extrapolation_slider(value):
#add new traces in the graph thanks to the value of new slider
return 'You have selected "{}"'.format(value), False, fig
I've already searched everywhere but can't find a way to build a callback to update my graphs in real time properly, can someone give me advices?
The aim is to receive the data through sensors with arduino, but for testing i'm creating random values to plot.
Here is the rep: https://github.com/Gugarauj07/RacingTelemetry_Visualization
This is how i initialy plot the graphs:
graph_temperature = go.Figure(layout={"template": "plotly_dark"})
graph_temperature.add_trace(
go.Scatter(x=df["tempo"], y=df["temp_obj"], name="temp_obj", mode="lines", line=dict(color="#F6511D")))
graph_temperature.add_trace(
go.Scatter(x=df["tempo"], y=df["temp_amb"], name="temp_amb", mode="lines", line=dict(color="#FFB400")))
graph_temperature.update_layout(yaxis_title="Temperatura CVT", margin=dict(l=5, r=5, t=5, b=5), autosize=True,
height=150)
How should i program my callback to update this types of graphs, and not losing the layout?
#app.callback(
[
Output('graph_temperature', 'figure'),
# Output('graph_velocidade', 'figure'),
# Output('graph_RPM', 'figure'),
# Output('graph_ACC', 'figure'),
# Output('graph_laps', 'figure'),
],
Input('interval-component', 'n_intervals')
)
def update_graphs(num):
if num == 0:
raise PreventUpdate
else:
graph_temperature = {
}
so today, I'm trying to create a simple dahsboard with data from multiple dataframes. I use the dropdown to select the dataframe to show in the plot. However, when I run this code, I got callback error in the web page says
Callback error updating loglog.figure
Traceback (most recent call last):
File "C:\Users\nahar\AppData\Local\Temp/ipykernel_1556/982666652.py", line 63, in build_graph
TypeError: string indices must be integers
I don't understand why this occurs, here is the code
logs = ['CALI','RDEP','GR','RHOB','NPHI','SP','DTC']
colors = ['black','firebrick','green','mediumaquamarine','royalblue','goldenrod','lightcoral']
log_cols = np.arange(1,8)
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.SANDSTONE], meta_tags=[
{"name": "viewport", "content": "width=device-width, initial-scale=1"}
])
server = app.server
app.config.suppress_callback_exceptions = True
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.H1('FORCE 2020 Well Log Challange Dashboard',
className='text-center mb-4'),
width=12)
]),
dbc.Row([
dbc.Col([
dcc.Dropdown(id='droplog',
options=[
{'label':'15/9-13','value':'well1'},
{'label':'15/9-15','value':'well2'},
{'label':'15/9-17','value':'well3'},
{'label':'16/1-2','value':'well4'},
{'label':'16/1-6 A','value':'well5'},
{'label':'16/10-1','value':'well6'},
{'label':'16/10-2','value':'well7'},
{'label':'16/10-3','value':'well8'},
{'label':'16/10-5','value':'well9'},
{'label':'16/11-1 ST3','value':'well10'},
{'label':'16/2-11 A','value':'well11'},
{'label':'16/2-16','value':'well12'}
], multi=False, value='well1'),
dcc.Graph(id='loglog',figure={})
])
]),
dbc.Row([
])
])
#app.callback(
Output(component_id='loglog',component_property='figure'),
[Input(component_id='droplog',component_property='value')]
)
def build_graph(plot_chosen):
logplot = make_subplots(rows=1, cols=len(logs), shared_yaxes=True)
for i in range (len(logs)):
if i == 1:
logplot.add_trace(go.Scatter(x=plot_chosen[logs[i]], y=plot_chosen['DEPTH_MD'],
name=logs[i], line_color=colors[i]),row=1, col=log_cols[i])
logplot.update_xaxes(type='log',row=1, col=log_cols[i], title_text=logs[i],
tickfont_size=12, linecolor='#585858')
else:
logplot.add_trace(go.Scatter(x=plot_chosen[logs[i]], y=plot_chosen['DEPTH_MD'],
name=logs[i], line_color=colors[i]),row=1, col=log_cols[i])
logplot.update_xaxes(col=log_cols[i], title_text=logs[i], linecolor='#585858')
logplot.update_xaxes(showline=True, linewidth=2, linecolor='black', mirror=True, ticks='inside', tickangle= 0)
logplot.update_yaxes(tickmode='linear', tick0=0,dtick=250, showline=True, linewidth=2, linecolor='black',
mirror=True, ticks='outside')
logplot.update_yaxes(row=1, col=1, autorange='reversed')
logplot.update_layout(height=750, width=1200, showlegend=False)
logplot.update_layout(plot_bgcolor = "rgba(0,0,0,0)", paper_bgcolor = "rgba(0,0,0,0)")
return logplot
if __name__=='__main__':
app.run_server(debug=True,use_reloader=False)
and the input data used is in the form of many dataframes, one of which is like this
for well 1
I tried to run defined function only, which build_graph, and it worked like a charm. The result of figure is shown here
I think I know what the problem is: the variable plot_chosen which is the argument in the function build_graph is a string. As a result you can not type y=plot_chosen['DEPTH_MD']. Although after choosing 15/9-13 on the Dropdown menu it has a value of well1, it does not represent the dataframe but a simple string. Try creating for example a dictionary with the dataframes
dataframes = {'well1': well1, 'well2': well2, ...}
and then choose the appropriate DataFrame from the dictionary.
So for example when the user chooses 15/9-13 on the dropdown you will get plot_chosen='well1' and you can simply get the dataframe well1 by using dataframes[plot_chosen].
I want to design the Dash app layout in such a way, that two trend/line charts are arranged in the same container/figure and I want to switch it with a button to display one chart at a time, the x-axis is the same for both charts.
I have tried with the below code but it doesn't update the label of the y-axis and hover text according to charts.
import pandas as pd
import plotly.express as px
dfx = pd.DataFrame({'months':['apr','may','jun','jul','aug','sep','oct','nov','dec','jan','feb','mar']
,'imported_qty':[25,35,45,30,35,45,50,25,30,35,45,40]
,'unit_price':[1.80,1.75,2.10,2.08,2.25,2.20,2.35,2.38,2.28,2.32,2.38,2.51]})
fig = px.line(dfx, x='months', y=dfx['imported_qty'])
fig.update_traces(mode="lines")
fig.update_layout(yaxis={'showgrid': False}
,xaxis={'showgrid': False}
,template='plotly_dark'
,hovermode="x"
,legend=dict(y=1, x=1, font=dict(size=8))
,height=350
,font=dict(size=10, color='gray')
,title={'text': "Import Qty. Trend"
,'y':0.95
,'x':0.5
,'xanchor': 'center'
,'yanchor': 'top'
,'font_size':15
,'font_color':'white'}
,updatemenus=[
dict(
type="buttons",
direction="right",
x=0.7,
y=1,
showactive=True,
buttons=list(
[
dict(
label="Qty",
method="update",
args=[{"y": [dfx['imported_qty']]}
,{'title':'Import Qty. Trend'}
,{'y':'Import qty.'}],
),
dict(
label="Price",
method="update",
args=[{"y": [dfx['unit_price']]}
,{'title':'Unit Price Trend'}
,{'y':'Unit Price'}],
),
]
),
)
]
)
Thank You.
Why not put you fig as dash Graph as a children of a html Div, create two buttons in the layout, and then create a callback that listens on these two buttons and that updates the children of the html Div depending on which button has been clicked ?
I have a plot that I've created with plotly that's interactive with clicks and widgets within Jupyter. I'm happy with how my plot works and I want to export it to use outside of Jupyter using dash. When I take my figure and try to output it with dash all the interactive functions I've created through plotly in Jupyter don't work. When I run the code the figure and layout are present, but the interactive part is gone. If I comment out running this on the app.run_server everything works great. All my functions in plotly use #out.capture() then xx.on_click(function) and I use widgets.Button or widgets.FloatText. Are there changes that I need to make to my capture functions to work in dash? Any suggestions are appreciated!
import pandas as pd
import numpy as np
import io
import os
import plotly.graph_objects as go
import json
import ipywidgets as widgets
from dash import Dash, dcc, html
app=Dash(__name__)
x=np.random.uniform(-10,10,size=50)
y=np.sin(x)
# Initialize the figure using plotly
fig=go.FigureWidget([go.Scatter(x=x,
y=y,
mode='markers',
opacity=1,
marker=dict(
color=['#a3a7e4']*100,
size=[10]*100)
),
go.Scatter(x=[],
y=[],
mode='lines',
marker=dict(
color='DarkSlateGrey')
)])
fig.update_layout(
template='simple_white',
showlegend=False,
title='Title',
xaxis=dict(title="X Axis",
mirror=True,
),
yaxis=dict(title='Y Axis',
mirror=True,
)
)
scatter=fig.data[0]
line = fig.data[1]
# Create the box on the bottom to append the data in the output
out = widgets.Output(layout={'border': '1px solid black'})
out.append_stdout('\n')
reset = widgets.Button(description="Reset")
export = widgets.Button(description="Export")
enter_text=widgets.FloatText(description='Text:')
# Create our callback function
#out.capture()
def update_point(trace, points, selector):
x = list(line.x) + points.xs
y = list(line.y) + points.ys
line.update(x=x, y=y)
c = list(scatter.marker.color)
s = list(scatter.marker.size)
for i in points.point_inds:
c[i] = '#bae2be'
s[i] = 20
with fig.batch_update():
scatter.marker.color = c
scatter.marker.size = s
# Function to clear the output when 'Reset' button is clicked
#out.capture()
def on_reset_clicked(b):
line.update(x=[], y=[])
scatter.marker.color=['#a3a7e4']*100
scatter.marker.size=[10]*100
out.clear_output()
# Function for exporting the points clicked
#out.capture()
def on_export_clicked(b):
line.update(x=[],y=[])
scatter.marker.color=['#a3a7e4']*100
scatter.marker.size=[10]*100
out.clear_output
reset.on_click(on_reset_clicked)
export.on_click(on_export_clicked)
scatter.on_click(update_point)
widgets.VBox([widgets.HBox([reset, export,enter_text]), widgets.VBox([fig, out])])
app.layout=html.Div([
dcc.Graph(
id='Title',
figure=fig
)
])
if __name__=='__main__':
app.run_server(debug=False)