I need to write a call back function which will have a dynamic input component and a static input component. But putting them together is throwing error.
This is what I have done so far -
#app.callback(
[Output("new_list", "children")],
[
#Static Input Component
Input("clear", "n_clicks"),
#Dynamic Input Component
Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)
],
)
###########################################################
## Updated sample working code
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash import callback_context
from dash.dependencies import Input, Output, State
import numpy as np
import pandas as pd
import dash_table as dt
item1 = ['A','A','B','B']
item2 = ["W","X","Y","Z"]
item3 = ["L",np.nan,'M','L']
item_list = pd.DataFrame(list(zip(item1,item2,item3)),columns=["item1","item2","item3"])
cat_list = item_list.item1.unique()
global itemlist
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
def Add_item(data,data2):
print("BILLING: Add_item()")
item_list = dbc.Card(children = [
generate_item(data,data2),
dbc.Row([
dbc.Col([
dbc.Button(
html.H5("Cancel"), id="cancel", className="ml-auto", color = "danger"
)
]),
dbc.Col([
dbc.Button(
html.H5("Clear"), id="clear", className="ml-auto", color = "info"
)
]),
],style = {"width": "71rem"})
],
id="modal-body-newitem"
)
return item_list
def generate_item(item_list,itemlist):
buttons = html.Div(children =[
dbc.Row([
dbc.Button(
html.H5(str('+ ' + a)),
id= str(a),
className="mb-3",
color="primary",
block=True
),
dbc.Collapse([
dbc.Card([
dbc.Row([
dbc.Col([dbc.Button(html.H5(str('+ ' + b)),className="mb-3",color="info",block=True, disabled = True)],width = 10),
dbc.Col([dbc.Input(type="number", min=0, max=20, step=1,value = itemlist.loc[itemlist.item == b,'qty'],id = b )],width = 2)
]) for b in item_list.loc[item_list.item1== a, ('item3','item2','item1')].stack().groupby(level=0).agg(' '.join).sort_values()
#,dbc.Card(dbc.CardBody(str("This content is for " + a)))
],body = True, style = {"width": "71rem", "justify": "centre", "align": "centre"})
],id= str("collapse" + a))
]) for a in item_list.item1.unique()
])
return buttons
app = dash.Dash(__name__,external_stylesheets=[dbc.themes.CYBORG])
app.config.suppress_callback_exceptions = True
server = app.server
app.title="Test"
app.layout = html.Div([
dbc.Card(
dbc.CardBody(
[
html.H5("New Item", className="card-title"),
Add_item(item_list,itemlist),
html.Div(id = 'new_list')
]
)
)
])
#Item Ctegory List
#app.callback(
[Output(str("collapse" + i), "is_open") for i in cat_list],
[Input(str(i), "n_clicks") for i in cat_list]+
[Input("cancel", "n_clicks")])
def toggle_collapse_category_box(*args):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:toggle_collapse_category_box: Call - "+str(callback_context.triggered))
if not callback_context.triggered or trigger["prop_id"].split(".")[0] == 'cancel':
print('MYBIZZAPP:toggle_collapse_category_box: Not Triggered/Cancel')
global isopn
isopn = [False] * len(cat_list)
else:
print('MYBIZZAPP:toggle_collapse_category_box: Triggered')
for i in range(len(cat_list)):
if cat_list[i] == trigger["prop_id"].split(".")[0]:
isopn[i] = not isopn[i]
return isopn
### Clear item list
#app.callback(
[Output(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)],
[Input("cancel", "n_clicks"),
Input("clear", "n_clicks")])
def clear_item_box(n2,n3):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:clear_item_box: Call - "+str(callback_context.triggered))
if trigger["prop_id"].split(".")[0] == 'cancel':
print("MYBIZZAPP:clear_item_box: cancel order")
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
elif trigger["prop_id"].split(".")[0] == 'clear':
print("MYBIZZAPP:clear_item_box: clear order")
return [0] * len(item_list)
#Menu item list
#app.callback(
[Output("new_list", "children")],
[Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)]+
[Input("clear", "n_clicks"),
Input("cancel", "n_clicks")])
def menu_item_list(*args):
trigger = callback_context.triggered[0]
print("MYBIZZAPP:menu_item_list: Call - "+str(callback_context.triggered))
print(trigger["prop_id"].split(".")[0])
if not callback_context.triggered :
print('MYBIZZAPP:menu_item_list: Not Triggered')
global itemlist
itemlist = pd.DataFrame( columns = ['item','qty'])
for item in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join):
itemlist.loc[len(itemlist)] = (item,0)
else:
print('MYBIZZAPP:menu_item_list: Triggered')
itemlist.loc[itemlist.item == trigger["prop_id"].split(".")[0],'qty'] = trigger["value"]
if trigger["prop_id"].split(".")[0] == 'clear' or trigger["prop_id"].split(".")[0] == 'clear':
print('MYBIZZAPP:menu_item_list: Clear|Cancel')
itemlist['qty'] = 0
print('MYBIZZAPP:menu_item_list: Item List')
print(itemlist)
return ['Total items selected - ' + str(sum(itemlist.qty))]
if __name__ == '__main__':
app.run_server(debug=True)
If I do not mention the static input component, code works fine. But I need to have the static component as well.
Overall problem that I am trying to work on is - I have dynamic input text boxes, if and when a value is entered in any of these boxes, that value needs to be accounted for and returned as a table. Also, there is a 'clear' button. If clicked, all values should be re-set to default pre-defined value.
Thanks for your help in advance.
Thank you for updating with the error. This issue is coming from your list comprehension. When you add the first input, it creates invalid syntax for the comprehension. This should work, though:
#app.callback(
[Output("new_list", "children")],
[
#Static Input Component
Input("clear", "n_clicks"),
] + [
#Dynamic Input Component
Input(str(i), "value") for i in item_list[['item3','item2','item1']].stack().groupby(level=0).agg(' '.join)
],
)
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
For my dash app, in order to update some graphs dynamically, I have to use a function that I named update_graphs inside a for loop. Some of the graphs contain several traces while some others only have one. The update_graphs function is called inside a callback and returns a dict and an int to update the extendData property of the graph object. However, since I am using a return statement inside a for loop, I only get the first trace.
I am not familiar with the generators and the yield keyword, maybe this is an option. But I haven't been able to make it work.
I have also tried to store the results of the update_graphs inside a list but it is not working.
Any help is appreciated!
Here is the code for the app:
import dash
from dash.dependencies import Output, Input, State, MATCH, ALL
from dash import dcc, html, ctx
import plotly
import plotly.express as px
import random
import plotly.graph_objs as go
import pandas as pd
# Initializing the data with the correct format
init_store = {}
n=3
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int'), 'c':pd.Series(dtype='int'), 'd':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store['0'] = init_df
for i in range(n):
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store[f'{i+1}'] = init_df
# Function to update the dataframes with the new observations
def get_data(json_data):
df = pd.read_json(json_data)
compteur = df['a'][len(df['a'])-1]
if len(df.columns) > 2:
new_row = {'a':compteur + 1, 'b':random.randint(13,26), 'c':random.randint(13,26), 'd':random.randint(13,26)}
else:
new_row = {'a':compteur + 1, 'b':random.randint(13,26)}
df = df.shift(periods=-1)
df.iloc[len(df)-1] = new_row
return(df.to_json())
# Function to update the graphs based on the dataframes
def update_graphs(json_data, column, index=0):
df = pd.read_json(json_data)
nb_obs = df.shape[0]
x_new = df['a'][len(df)-1]
y_new = df[column][nb_obs-1]
return dict(x=[[x_new]], y=[[y_new]]), index
colors = px.colors.qualitative.G10
def generate_graph_containers(index, json_data):
dataframe = pd.read_json(json_data)
X = dataframe['a']
Y = dataframe.loc[:, dataframe.columns != 'a']
graph_id = {'type': 'graph-', 'index': index}
return(
html.Div(
html.Div(
dcc.Graph(
id=graph_id,
style={"height": "8rem"},
config={
"staticPlot": False,
"editable": False,
"displayModeBar": False,
},
figure=go.Figure(
{
"data": [
{
"x": list(X),
"y": list(Y[Y.columns[i]]),
"mode": "lines",
"name": Y.columns[i],
"line": {"color": colors[i+2]},
}
for i in range(len(Y.columns))
],
"layout": {
"uirevision": True,
"margin": dict(l=0, r=0, t=4, b=4, pad=0),
"xaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"yaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"paper_bgcolor": "rgba(0,0,0,0)",
"plot_bgcolor": "rgba(0,0,0,0)",
}
}
)
)
)
)
)
app = dash.Dash(__name__)
store = [dcc.Store(id={'type':'store-', 'index':i}, data=init_store[str(i)].to_json()) for i in range(n)]
def make_layout():
return(
html.Div(
[
html.Div(
store
),
dcc.Interval(
id = 'interval',
interval = 1000,
n_intervals = 0
),
html.Div(
[
generate_graph_containers(str(i), store[i].data) for i in range(n)
]
)
]
)
)
app.layout = make_layout
#app.callback(
Output(component_id={'type':'store-', 'index':MATCH}, component_property='data'),
[
Input('interval', 'n_intervals'),
State(component_id={'type':'store-', 'index':MATCH}, component_property='data')
]
)
def update_data(time, data):
return(get_data(data))
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
triggered_id = ctx.triggered_id
print(triggered_id['index'])
columns = ['b', 'c', 'd']
if triggered_id['index'] == 0:
for i in range(len(columns)):
return(update_graphs(data, columns[i], i))
else:
return(update_graphs(data, 'b'))
if __name__ == '__main__':
app.run_server(debug=True)
I figured it out. The trick is in the format expected to update the extendData property of a figure. When trying to update several traces, the format should be a dictionary with a key for the x values and one for the y values. The values associated should be an array for each key, containing an array per trace. Don't forget to add the trace indices after the dictionary. So for example, in the case of 3 distinct traces, the function should return something like:
dict(x=[[x_0], [x_1], [x_2]], y=[[y_0], [y_1], [y_2]]), [0, 1, 2]
Therefore the update_graphs function should be:
def update_graphs(json_data):
df = pd.read_json(json_data)
nb_obs = df.shape[0]
x_new = []
y_new = []
trace_index = []
for i in range(len(df.columns)-1):
x_new.append([df['a'][len(df)-1]])
y_new.append([df[df.columns[i+1]][nb_obs-1]])
trace_index.append(i)
return(dict(x=x_new, y=y_new), trace_index)
And the callback to update the graphs should be changed to:
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
return(update_graphs(data))
Does someone know how I would dynamically render tabs based on a given input?
For example, if I put a number(like 4) in a text box and pressed submit, I'd want to have 4 tabs show up underneath with content(let's the tab number underneath). If put 2 I'd want 2 tabs. I think I use a for loop somewhere but not sure how to implement.
I've only been able to get to show a static number of tabs once submit is clicked to start off.
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
app = dash.Dash()
input_group_Row = dbc.Row([ dbc.Col([
dbc.CardBody(
[
dbc.InputGroup(
[
dbc.InputGroupAddon("Enter number", addon_type="prepend"),
dbc.Input(id='integer',placeholder="Enter int"),
],className="mb-3",),
]),
]),
dbc.Col([
dbc.Button('Enter', color='primary',id='load', block=True,n_clicks=0),
])
])
app.layout = html.Div([input_group_Row, html.Div(id='output-content')], style = CONTENT_STYLE)
#app.callback(Output('output-content', 'children'),
[Input('load', 'n_clicks')],
[State('integer','value')],
)
def render_tabs(click1, integ):
output =""
ctx = dash.callback_context
action = ctx.triggered[0]['prop_id'].split('.')[0]
if action == 'load':
print(type(int(integ)))
output = integ
return dcc.Tabs(id='tab', value='tab1',children=[
dcc.Tab(label='Tab 1', value='tab1', children=[html.Div(output,style={'color': 'blue', 'fontSize': 140})]),
dcc.Tab(label='Tab 2', value='tab2', children=[html.Div(int(output)+3,style={'color': 'blue', 'fontSize': 140})])
])
You could use a list comprehension.
List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.
https://docs.python.org/3/tutorial/datastructures.html
Based on your example you could do something like this:
#app.callback(
Output("output-content", "children"),
[Input("load", "n_clicks")],
[State("integer", "value")],
)
def render_tabs(click1, integ):
output = ""
ctx = dash.callback_context
action = ctx.triggered[0]["prop_id"].split(".")[0]
if action == "load":
output = int(integ)
return dcc.Tabs(
id="tab",
value="tab1",
children=[
dcc.Tab(
label=f"Tab {num + 1}",
value=f"tab{num + 1}",
children=[html.Div(num)],
)
for num in range(output)
],
)
The same solution with a for loop could look like this:
#app.callback(
Output("output-content", "children"),
[Input("load", "n_clicks")],
[State("integer", "value")],
)
def render_tabs(click1, integ):
output = ""
ctx = dash.callback_context
action = ctx.triggered[0]["prop_id"].split(".")[0]
if action == "load":
output = int(integ)
tabs = []
for num in range(output):
tabs.append(
dcc.Tab(
label=f"Tab {num + 1}",
value=f"tab{num + 1}",
children=[html.Div(num)],
)
)
return dcc.Tabs(
id="tab",
value="tab1",
children=tabs,
)
I am trying to make a live updating dash app but the live update only shows when I manually press the refresh button on the web page until then the graph doesn't update , I am trying to generate a progressively updating heat map from some data derived from sensor reading to show how it would look like if the data is read in real time.
Data Source is available at : Data source used in code below 1MB in size only
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly
import pandas as pd
import random
import plotly.graph_objs as go
# The csv file for this dataset used here can be downloaded from:
# https://easyupload.io/0ni29p (Hyperlinked in post as well)
cols = [ 'shot' , 'chan' , 'peak_amplitude', 'onset_time_(ms)', 'bubble_period_(ms)']
cols_bubble_period = [ 'shot' , 'chan' , 'bubble_period_(ms)']
source_df = pd.read_csv('seq-4bubbleQC.txt').drop(['sequence', 'file'], axis=1)
source_df.columns = cols
source_df.loc[source_df['shot'] % 2 == 0, 'chan'] += 18
all_results = pd.DataFrame(columns = cols)
i=0
def df_to_plotly(df):
return {'z': df.values.tolist(),
'x': df.columns.tolist(),
'y': df.index.tolist()}
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Graph(id = 'live-graph', animate = True),
html.Button('START_PLOT', id='plot_start',n_clicks=0),
html.H2(id='hidden-div', style= {'display': 'none'} ),
dcc.Interval(
id = 'graph-update',
interval = 5*1000,
n_intervals = 0
),
]
)
#app.callback(
Output('hidden-div', 'children'),
[ Input('graph-update', 'n_intervals') ],
[Input('plot_start', 'n_clicks')]
)
def update_frame(n_clicks, n_interval):
global source_df
global i
global all_results
if n_clicks == 0:
raise dash.exceptions.PreventUpdate()
all_results = all_results.append((source_df[i: i+36]))
i+=36
#print(i)
#app.callback(
Output('live-graph', 'figure'),
[ Input('graph-update', 'n_intervals') ],
[Input('plot_start', 'n_clicks')]
)
def update_graph_heat(n_clicks, n_interval):
global all_results
all_results_1 = all_results.apply(pd.to_numeric)
#all_results_1 = all_results_1.drop_duplicates()
#all_results_1.to_csv('all_results.csv')
df_s1 = all_results_1.loc[all_results_1['chan'] <=18]
df_s1_bp = df_s1[cols_bubble_period]
#print(df_s1_bp)
#df_s1_bp.to_csv('test_data.csv')
df_s1_pivoted = df_s1_bp.pivot( 'chan', 'shot', 'bubble_period_(ms)')
data = go.Heatmap(df_to_plotly(df_s1_pivoted) , colorscale='rainbow', zmin=30.0, zmax=210.0)
return {'data': [data],
'layout' : go.Layout(xaxis_nticks=20, yaxis_nticks=20)}
if __name__ == '__main__':
app.run_server()
The graph only updates when a manual page refresh is done , how can I make the updated graph appear automatically?
Your callbacks are constructed incorrectly. All inputs should be within the same list. Here is what your first one should look like:
#app.callback(
Output('hidden-div', 'children'),
[Input('graph-update', 'n_intervals'),
Input('plot_start', 'n_clicks')]
)
def update_frame(n_clicks, n_interval):
global source_df...
# etc.
I am trying to add an item after a button is clicked. After clicking several buttons (A, B, C), the dataframe should have those information passed after the selected buttons are clicked. I want the passed dataframe to include df = pd.DataFrame( combination of A, B, C). However, at this stage, when I press the button, and write the corresponding information into a dataframe, the callback deletes all the information, and keeps only the last pressed button. I bypassed this limitation by writing corresponding information into csv but I wonder if there is a more elegant approach.
#app.callback(Output('intermediate_value', 'children'),
[Input('like_val_0', 'n_clicks_timestamp'),
Input('like_val_1','n_clicks_timestamp'),
Input('like_val_2', 'n_clicks_timestamp')
])
def construct_preferences(like_val_0, like_val_1, like_val_2):
listedTimestamps = [like_val_0, like_val_1, like_val_2]
listedTimestamps = [0 if v is None else v for v in listedTimestamps]
sortedTimestamps = sorted(listedTimestamps)
if like_val_0 == sortedTimestamps[-1]:
pickedButton = "like_val_0"
print (pickedButton)
sample_that_matches_address_0 = data[data['addresses'].str.contains(item_in_df[0].partition('.jpg')[0])]
sample_that_matches_address_0.to_csv('prefs.csv', columns=list(data), mode='a', header=False)
if like_val_1 == sortedTimestamps[-1]:
pickedButton = "like_val_1"
print (pickedButton)
sample_that_matches_address_1 = data[data['addresses'].str.contains(item_in_df[1].partition('.jpg')[0])]
sample_that_matches_address_1.to_csv('prefs.csv', columns=list(data), mode='a', header=False)
if like_val_2 == sortedTimestamps[-1]:
pickedButton = "like_val_2"
print (pickedButton)
sample_that_matches_address_2 = data[data['addresses'].str.contains(item_in_df[2].partition('.jpg')[0])]
sample_that_matches_address_2.to_csv('prefs.csv', columns=list(data), mode='a', header=False)
As you can see I write that item to csv and I wonder if there is any way to prevent callback from updating until I press another button; in my case predict.
#app.callback(Output('container', 'children'),
[Input('intermediate_value', 'children'),
Input('predict_val', 'n_clicks')])
def update_output_images (intermediate_value, n_clicks):
if (n_clicks!=0):
preferences = pd.read_csv('prefs.csv')
preferences.drop_duplicates(keep='first', inplace=True)
EDIT:
As the comment suggests, I update the example with a reproducible one
import json
import os
import pandas as pd
import random
import glob
from os import listdir
import flask
import pickle
import base64
from PIL import Image as PImage
import urllib.request
import numpy as np
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
server = app.server
data = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
preferences = pd.DataFrame(columns=list(data))
row_1 = html.Div([(dbc.Row([
dbc.Col([
html.P('Random_val_0 is {}'.format(data['A'].loc[0])),
dbc.Button('Like This One', id='like_val_0', style={'vertical-align': "bottom"}, n_clicks=0),
]),
dbc.Col([
html.P('Random_val_1 is {}'.format(data['A'].loc[1])),
dbc.Button('Like This One', id='like_val_1', style={'vertical-align': "bottom"}, n_clicks=0),
]),
dbc.Col([
html.P('Random_val_2 is {}'.format(data['A'].loc[2])),
dbc.Button('Like This One', id='like_val_2', style={'vertical-align': "bottom"}, n_clicks=0),
])
]))])
predict = html.Div([
html.Button ('Predict', id='predict_val', n_clicks=0),
html.Div(id='images_new')
])
container_out = html.Div([html.Div(id='container')])
placeholder = html.Div([html.Div(id='intermediate_value', style={'display': 'none'})])
app.layout = dbc.Container(children=[row_1, html.Br(), html.Br(), placeholder, html.Br(), container_out, html.Br(), predict])
#app.callback(Output('intermediate_value', 'children'),
[Input('like_val_0', 'n_clicks_timestamp'),
Input('like_val_1','n_clicks_timestamp'),
Input('like_val_2', 'n_clicks_timestamp')
])
def construct_preferences(like_val_0,like_val_1, like_val_2):
listedTimestamps = [like_val_0, like_val_1, like_val_2]
listedTimestamps = [0 if v is None else v for v in listedTimestamps]
sortedTimestamps = sorted(listedTimestamps)
if like_val_0 == sortedTimestamps[-1]:
pickedButton = "like_val_0"
print (pickedButton)
sample_output_0 = data.loc[data['A'] == data['A'].loc[0]]
return sample_output_0.to_json()
#sample_that_matches_address_0.to_csv('prefs.csv', columns=list(data), mode='a', header=False)
if like_val_1 == sortedTimestamps[-1]:
pickedButton = "like_val_1"
print (pickedButton)
sample_output_1 = data.loc[data['A'] == data['A'].loc[1]]
return sample_output_1.to_json()
if like_val_2 == sortedTimestamps[-1]:
pickedButton = "like_val_2"
print (pickedButton)
sample_output_2 = data.loc[data['A'] == data['A'].loc[2]]
return sample_output_2.to_json()
#app.callback(Output('container', 'children'),
[Input('intermediate_value', 'children'),
Input('predict_val', 'n_clicks')])
def update_output_images (intermediate_value, n_clicks):
if (n_clicks!=0):
preferences = pd.read_json(intermediate_value)
print (preferences.shape)
if __name__ == '__main__':
app.run_server(host='0.0.0.0', debug=True)