I have a Dash app with 2 Tabs and on one Tab I have an upload button while on the other Tab the uploaded dataset is being shown. After uploading the data, it is shown on the second tab but when I switch to the first Tab and come back again to the second Tab, the data table is not there anymore. I have tried using persistence and persistence-type but it doesn't work. Here is the code for the data table
#du.callback(
output=Output('output-datatable', 'children'),
id='upload-data',
)
def get_a_list(filenames):
data1=pd.read_excel(filenames[0])
return dash_table.DataTable(
data = data1.to_dict('records'),
columns = [{'name': i, 'id': i} for i in data1.columns],
page_size =15, persistence = True, persistence_type = 'memory')
Instead of persistence, use dcc.store
In the layout:
dcc.Store(id='store-data', data=[], storage_type='local')
Callback function:
#du.callback(
output=Output('store-data', 'data'),
input = Input(id='upload-data','children')
)
Also check out this video: https://www.youtube.com/watch?v=dLykSQNIM1E
Related
The following code reads a simple model (3 columns 50 rows) from a CSV file for editing in a table in my (larger) dash app. Editing a cell writes the whole table back to file as expected. However, reloading the page displays the table as it was originally loaded from file, thus losing any edits. Any clues about how to keep the edits between page reloads?
df_topic_list=pd.read_csv(model_file)
app.layout = html.Div([
dcc.Store(id='memory-output'),
html.Div([
dash_table.DataTable(df_topic_list.to_dict('records'),
id='memory-table',
columns=[{"name": i, "id": i} for i in df_topic_list.columns],editable=True
),
])
])
#app.callback(Output('memory-output', 'data'),
Input('memory-table', 'data'))
def on_data_set_table(data):
pd.DataFrame(data).to_csv(model_file,index=False)
return data
app.run_server(port=8052)
When you refresh page then it doesn't run all code again but it only sends again app.layout which it generated only once and which has original data from file. And when you update data in cell in table then it updates only values in browser (using JavaScript) but not in code app.layout.
But it has options to presist values in browser memory and it should use these values after reloading.
app.layout = html.Div([
dcc.Store(id='memory-output'),
html.Div([
dash_table.DataTable(
df_topic_list.to_dict('records'),
id='memory-table',
columns=[{"name": i, "id": i} for i in df_topic_list.columns],
editable=True,
persistence=True, # <---
persisted_props=["data"], # <---
)
])
])
It works for me but it seems some people had problem with this.
See issues: Dash table edited data not persisting · Issue #684 · plotly/dash-table
But I found other method to keep it.
I assign table to separated variable - ie. table - and in callback I replace table.data in this table.
from dash import Dash, Input, Output, callback
from dash import dcc, html, dash_table
import pandas as pd
model_file = 'data.csv'
df_topic_list = pd.read_csv(model_file)
app = Dash(__name__)
table = dash_table.DataTable(
df_topic_list.to_dict('records'),
id='memory-table',
columns=[{"name": i, "id": i} for i in df_topic_list.columns],
editable=True,
)
app.layout = html.Div([
dcc.Store(id='memory-output'),
html.Div([table])
])
#app.callback(
Output('memory-output', 'data'),
Input('memory-table', 'data')
)
def on_data_set_table(data):
pd.DataFrame(data).to_csv(model_file, index=False)
table.data = data # <--- replace data
return data
app.run_server(port=8052)
I am working on an NLP project analyzing the words spoken by characters in The Office. Part of this project involves making a network diagram of which characters talk to each other for a given episode.
This will be shown in a Dash app by allowing a user to select dropdowns for 4 parameters: season, episode, character1, and character2.
Here is a relevant snippet of my code so far:
#Import libraries
import pandas as pd
import numpy as np
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, Output, State
#Load data
sheet_url = 'https://docs.google.com/spreadsheets/d/18wS5AAwOh8QO95RwHLS95POmSNKA2jjzdt0phrxeAE0/edit#gid=747974534'
url = sheet_url.replace('/edit#gid=', '/export?format=csv&gid=')
df = pd.read_csv(url)
#Set parameters
choose_season = df['season'].unique()
choose_episode = df['episode'].unique()
choose_character = ['Andy','Angela', 'Darryl', 'Dwight', 'Jan', 'Jim','Kelly','Kevin','Meredith','Michael','Oscar','Pam','Phyllis','Roy','Ryan','Stanley','Toby']
#Define app layout
app = dash.Dash()
server = app.server
app.layout = html.Div([
dbc.Row([
dbc.Col(
dcc.Dropdown(
id='dropdown1',
options=[{'label': i, 'value': i} for i in choose_season],
value=choose_season[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown2',
options=[{'label': i, 'value': i} for i in choose_episode],
value=choose_episode[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown3',
options=[{'label': i, 'value': i} for i in choose_character],
value=choose_character[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown4',
options=[{'label': i, 'value': i} for i in choose_character],
value=choose_character[1]
), width=3
)
])
])
if __name__=='__main__':
app.run_server()
In order to have this work efficiently, I would like to have the following dependencies in the dropdown menus:
1.) The selection of the first dropdown menu updates the dropdown menu
ie: Season updates possible episodes
2.) The selection of the first two dropdown menus updates the 3rd and 4th dropdown menus
ie: Season, Episode updates possible characters (if a character was not in that episode, they will not appear)
3.) The selection of the third dropdown menu updates the fourth dropdown menu
ie: If a character is selected in the third dropdown menu, they can not be selected in the fourth (can't select the same character twice)
I understand one way to do this is to make a massive season to episode dictionary and then an even larger season to episode to character dictionary.
I've already made the code to process the season to episode dictionary:
#app.callback(
Output('dropdown2', 'options'), #--> filter episodes
Output('dropdown2', 'value'),
Input('dropdown1', 'value') #--> choose season
)
def set_episode_options(selected_season):
return [{'label': i, 'value': i} for i in season_episode_dict[selected_season]], season_episode_dict[selected_season][0]
I can definitely build these dictionaries, but this seems like a really inefficient use of time. Does anyone know of a way to build these dictionaries with just a few lines of code? Not sure how to approach building these in the easiest way possible. Also, if you have an idea for a better way to approach this problem, please let me know that too.
Any help would be appreciated! Thank you!
I think I see what you're asking about now. Something like this should get you a basic dictionary, which you could then modify for the options param for the dropdowns.
df = pd.read_csv(url)
season_episode_character_dictionary = {}
for season in df['season'].unique.tolist():
df_season = df[df['season'].eq(season)]
season_episode_character_dictionary[season] = {}
for episode in df_season['episode'].unique.tolist():
df_episode = df_season[df_season['episode'].eq(episode)]
characters = df_episode['characters'].unique.tolist()
season_episode_character_dictionary[season][episode] = characters
I'm working on an app in python that displays data in a plotly DataTable (see https://dash.plot.ly/datatable). In multiple places, the documentation refers to an export or copy/paste functionality that is supposed to be included in the DataTable. But I can't find any documentation how the user interface for this might work.
If I have a DataTable like this:
dash_table.DataTable(
id='rating-summary-table',
data=df_summary.to_dict('records)'),
columns=columns,
style_cell_conditional=[
{'if': dict(column_id='Name'), 'textAlign': 'left'},
],
)
it is displayed in the web UI, but how do I invoke the copy/paste feature? It should simply copy all data displayed (with headers) on the clipboard to be pasted into an Excel spreadsheet.
I am working on Windows 10.
You can use the component component_property derived_virtual_data in a callback, and write something like :
df = pd.DataFrame(virtual_data)
example
#app.callback(
Output('saved-results', 'children'),
[Input('save-button', 'n_clicks')],
[State(component_id='rating-summary-table', component_property="derived_virtual_data")],
)
def save_results(n_clicks, virtual_data):
if n_clicks is not None:
df = pd.DataFrame(virtual_data)
df.rename(columns={v: k for k, v in col_dict.items()}, inplace=True)
filename = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + '_results.csv'
saved_results.append(filename)
df.to_csv(RESULTS_DIRECTORY + filename,
encoding='utf-8',
index=False,
sep=';')
return files_list
else:
return [html.Li("Dataframe saved")]
i developed python dash based application for monitoring. as a part of the project i want to display live graph and change the live graph value based on user input. i am stuck in this part. the live graph getting update when i start typing in input box (eg:temp) the graph keep on updating for each letter like t,te,tem,temp. so i created a button to submit the input value. still the graph updating for each letter.
the code for the same:
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Input(id='input-value', value='example', type='text'),
html.Button('Submit', id="submit-button"),
dcc.Graph(id='live-graph', animate=False),
dcc.Interval(
id='graph-update',
interval=1*1000
),
]
)
call back function is like below
#app.callback(Output('live-graph', 'figure'),
[Input('submit-button','n_clicks')],
state=[State(component_id='sentiment_term', component_property='value')],
events=[Event('graph-update', 'interval')])
def update_graph_scatter(n_clicks, input_value):
conn = sqlite3.connect('database.db')
c = conn.cursor()
df = pd.read_sql("SELECT * FROM table WHERE colume LIKE ? ORDER BY unix DESC LIMIT 1000", conn ,params=('%' + input_value+ '%',))
df.sort_values('unix', inplace=True)
df['date'] = pd.to_datetime(df['unix'],unit='ms')
df.set_index('date', inplace=True)
X = df.index
Y = df.column
data = plotly.graph_objs.Scatter(
x=X,
y=Y,
name='Scatter',
mode= 'lines+markers'
)
return {'data': [data],'layout' : go.Layout(xaxis=dict(range= [min(X),max(X)]),
yaxis=dict(range=[min(Y),max(Y)])}
Note: If i removed the interval the button start working.but i want to be live update as well as button
You could use an intermediate component like a div to save the input from the text field and update that div only on button click.
So you would have
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Input(id='input-value', value='example', type='text'),
html.Div(['example'], id='input-div', style={'display': 'none'}),
html.Button('Submit', id="submit-button"),
dcc.Graph(id='live-graph', animate=False),
dcc.Interval(
id='graph-update',
interval=1*1000
),
])
Now you update the div only on button click:
#app.callback(Output('input-div', 'children'),
[Input('submit-button', 'n_clicks')],
state=[State(component_id='input-value', component_property='value')])
def update_div(n_clicks, input_value):
return input_value
And the Graph always uses the the div content to query your database (either when the interval triggers or the div changes):
#app.callback(Output('live-graph', 'figure'),
[Input('graph-update', 'interval'),
Input('input-div', 'children')])
def update_graph_scatter(n, input_value):
...
Are you sure the updates on each letter are because of the input? Sounds like the interval updates the graph with the not finished input you are typing.
P.S.: I guess you have a name discrepancy between you Input and State id.
I am trying to pass input value to another with Dash Plot.
The main page has a list of strategies :
First_page = html.Div([
html.Div([dcc.Dropdown(id='strategy', options=[{'label': i, 'value': i} for i in [strat1, start2]], multi=True)], value = [strat1]),
html.Div([dcc.Input(id='date_start', type='text', value='1990-01-01')]),
html.Button('Start Calculation', id='button'),
])
And my pages 1 and 2 are the following :
for i in range(2) :
layout = html.Div([
html.Div([dcc.Dropdown(id='strategy'+str(i), options=[{'label': i, 'value': i} for i in [strat1, start2]]])], value = strat+str(i)),
html.Div([dcc.Input(id='date_start'+str(i), type='text', value='1990-01-01')]),
html.Button('Start Calculation', id='button'+str(i)),
+ other options not listed in main page
])
The goal is the following : when the user is on the main page he can choose the list of strategies he want to see, as well as the starting date.
Then when he press the button, it should open pages for each strategy selected (In the example we have 2 strategies so I should have 2 pages : localhost:port/page-strat1 and localhost:port/page-strat2) where the graph shown on each page starts with the selected date.
I succeed to open the pages localhost:port/strat1 and/or the page localhost:port/strat2 depending on the list of selected strategies.
list_event = [Event('button', 'click')]
list_state = [State('strategy', 'value')]
#app.callback(Output('hidden-div', 'children'),events=list_event, state=list_state)
def create_callback_share(datestart, list_strategies_used):
for _strat in list_strategies_used:
time.sleep(1)
webbrowser.open('http://localhost:port/page-'+_strat)
But I do not succeed to send the selected date. I try the following callback :
for i in range(2) :
#app.callback(Output('date_start'+str(i), 'value'),inputs=[Input('date_start', 'value')])
def set_display_children(selected_element):
return "{}".format(selected_element)
But the page localhost:port/strat1 and localhost:port/strat2 allow open with the default value which is '1990-01-01' even if I enter another value in the main page.
Is it possible to send value from one page to the other ?
Use dcc.Store() as in the answer here:
Plotly Dash Share Callback Input in another page with dcc.Store
And here is the Dash documentation:
https://dash.plotly.com/dash-core-components/store