Dynamic update Dash Datatable from df - python

I'm creating an auto-update Dash datatable. The data is obtained from a SQL Server Query, passed to a Dataframe and displayed in the datatable:
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
import pandas as pd
import numpy as np
import pyodbc
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.MINTY, 'https://use.fontawesome.com/releases/v5.9.0/css/all.css'])
sql_query = ('''SELECT * FROM HOSVITAL.dbo.Censo_Diario
ORDER BY Dias_Estancia DESC''')
server = '#srv'
database = '#db'
username = '#usr'
password = '#pwd'
conn = pyodbc.connect('DRIVER={SQL Server};SERVER='+server+';DATABASE='+database+';UID='+username+';PWD='+ password)
df = pd.read_sql(sql_query,conn)
df = df.apply(lambda x: x.str.strip()
if x.dtype == "object" else x) # Trim whitespaces
After that, i'm defining a function for connect to my DB and another function for get and clean the data and return it as a dict:
def connectSQLServer(conn):
connSQLServer = conn
return connSQLServer
def getData():
df2 = pd.DataFrame()
for idx in range(10):
data = pd.read_sql(sql_query,conn)
df2 = df.apply(lambda x: x.str.strip()
if x.dtype == "object" else x)
df2 = df2.append(data, ignore_index=True)
df2 = df2.drop_duplicates().sort_index()
return df2.to_dict('records')
I´m giving custom name to the df columns:
tblcols=[{'name': 'Pabellon', 'id': 'Pabellon'},
{'name': 'Cama', 'id': 'Cama'},
{'name': 'Cedula', 'id': 'Cedula'},
{'name': 'Tipo', 'id': 'Tipo'},
{'name': 'EPS', 'id': 'EPS'},
{'name': 'Nivel', 'id': 'Nivel'},
{'name': 'Ingreso', 'id': 'Ingreso'},
{'name': 'Nombre', 'id': 'Nombre'},
{'name': 'Edad', 'id': 'Edad'},
{'name': 'Cod', 'id': 'Cod'},
{'name': 'Diagnostico', 'id': 'Diagnostico'},
{'name': 'Fecha Ingreso', 'id': 'Fecha_Ingreso'},
{'name': 'Dias Estancia', 'id': 'Dias_Estancia'}
]
Create my layout adding a Dcc.interval for update the data every 5 seconds:
app.layout = html.Div([
html.H4('CN Dashboard'),
dcc.Interval('graph-update', interval = 5000, n_intervals = 0),
dbc.Container([
dash_table.DataTable(
sort_action='native',
id = 'table',
css=[{
'selector': '.dash-cell div.dash-cell-value',
'rule': 'display: inline; white-space: inherit; overflow: inherit; text-overflow: inherit;'
}],
data = getData(),
columns=tblcols,]
)
Finally, I create this callback for update the table:
#app.callback(
dash.dependencies.Output('table','data'),
[dash.dependencies.Input('graph-update', 'n_intervals')])
def updateTable(n):
return getData()
if __name__ == '__main__':
app.run_server(debug=False, host='0.0.0.0', port = 8070)
app.title = 'Tablero CN' # appears in browser title bar
So, this App is displaying the data and it´s updating as expected, but the problem is that all rows are being duplicated in the Output.
Any suggestions?
Thanks in advance.

Error(Invalid prop for this component) - basically it is stating that dash_bootstrap_components.Table does not support data argument where you are trying to push update using callback. dash table has this feature. seems you imported it in code but didn't use. As far as I know it can't be solved with dbc. you can use dash_table if you really want this callback.
Query Re-usability - if both queries are same why not define query as variable in top as you did with conn and pass it as argument.
example:
query = '''select * from table'''

Related

How to set validation in dash?

The following code has first two columns with getpass.getuser() values and rest columns are normal with editable cells
import pandas as pd
import dash
from dash import dash_table, html
from dash.dependencies import Input, Output, State
import getpass
df = pd.read_csv('df.csv')
current_user = getpass.getuser()
df = df[(df.iloc[:, 0] == current_user) | (df.iloc[:, 1] == current_user)]
app = dash.Dash(__name__)
app.layout = html.Div([
dash_table.DataTable(
id='datatable',
columns=[
{'name': df.columns[0], 'id': df.columns[0], 'editable': False},
{'name': df.columns[1], 'id': df.columns[1], 'editable': False},
*[{'name': i, 'id': i, 'editable': True} for i in df.columns[2:]]
],
data=df.to_dict('records'),
editable=True
),
html.Button('Save Changes', id='save-button'),
html.Div(id='output')
])
#app.callback(Output('datatable', 'data'),
Output('output', 'children'),
Input('save-button', 'n_clicks'),
State('datatable', 'data'))
def save_changes(n_clicks, data):
if n_clicks:
df_new = pd.DataFrame.from_dict(data)
df_new = df_new[(df_new.iloc[:, 0] == current_user) | (df_new.iloc[:, 1] == current_user)]
df_new.to_csv('df.csv', index=False)
df_check = pd.read_csv('df.csv')
if df_check.equals(df_new):
return df_new.to_dict('records'), 'Changes saved!'
else:
raise Exception('Error saving changes.')
return data, ''
if __name__ == '__main__':
app.run_server(debug=True)
how to put validation in such a way that -
if the current user has getpass.getuser() values in first column, they can only edit and save data table values in df.csv only if they put "Sz", "Tx", "Ux" as values
if the current user has getpass.getuser() values in second column, they can only edit and save data table values in df.csv only if they put "Qr", "Fd", "Wv" as values

Use list as column input in dash datatable with dash version 2.4?

Is there a way to input a list into a newer dash version? I have seen some older examples online e.g. here that seem to be able to do it. If I just try to run the example- I keep on getting an Invalid error argument [...]- Expected one of type [string, number, boolean]. I am using the dash version 2.4.1
Using the example mentioned in the post above- I get the error
import dash
import dash_bootstrap_components as dbc
import pandas as pd
brand_name = ['merc', 'bmw']
driver = [['driver1', 'driver2'], ['driver3', 'driver14']]
df = pd.DataFrame({'brand_name': brand_name, 'driver': driver})
print(df)
df_dict = df.to_dict('records')
app = dash.Dash(__name__)
app.layout = dbc.Card(
dbc.CardBody(
[
dash.dash_table.DataTable(
id='homepage-table',
data=df_dict,
columns=[
{'name': 'brand_name', 'id': 'brand_name'},
{'name': 'driver', 'id': 'driver', 'presentation': 'markdown'}
],
)]))
if __name__ == '__main__':
app.run_server(debug=True, port=8080)

Bar graph with editable dash table

I'm trying to make a bar graph with editable dash table but graph changes for just once time. After changing data in table, graph be updated but not like my expectation.
Below is my sample code:
from dash_table import DataTable
from dash.dependencies import Input, Output
import dash
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
import plotly.graph_objs as go
raw_data = {'Type': ["Cash", "Credit Card"],
'Rate': [50,50]}
test_df = pd.DataFrame(raw_data)
test_df['id'] = test_df['Type']
test_df.set_index('id', inplace=True, drop=False)
app = dash.Dash(__name__)
app.layout = html.Div(children=[
dash_table.DataTable(
id='table',
data=test_df.to_dict('records'),editable=True,
columns=[
{"name": i, "id": i, "deletable": True, "selectable": True, "hideable": True}
if i == "Type" or i == "Rate"
else {"name": i, "id": i, "deletable": True, "selectable": True}
for i in test_df.columns
],
style_cell={
'minWidth': '0px',
'maxWidth': '180px',
'whiteSpace': 'no-wrap',
'overflow': 'hidden',
'textOverflow': 'ellipsis'},
style_table={'overflowX': 'scroll'},
row_deletable=True
),
dcc.Graph(
id='plot',
style={"max-width": "600px",
"margin": "auto",
"display": "inline-block"})
])
#app.callback(Output('plot', 'figure'),
[Input('table', 'data'),
Input('table', 'columns')])
def update_graph(data, cols):
df = pd.DataFrame(data, columns=[c['name'] for c in cols])
figure_2 = go.Figure(data=[
go.Bar(x=df['Type'],
y=df['Rate'],
width=0.45,
text = df['Rate'],
textposition='inside',
marker_color='indianred')])
return figure_2
if __name__ == '__main__':
app.run_server(port=1211, debug=False)
My first time change, graph looking like this:
But from the second time, graph looking like this:
What should I do to fix this problem.
Actually I read editable docs but I still not get it. The Graph in docs is generated like this:
def display_output(rows, columns):
return {
'data': [{
'type': 'heatmap',
'z': [[row.get(c['id'], None) for c in columns] for row in rows],
'x': [c['name'] for c in columns]
}]
}
I don't know how to apply it for bar graph.
Thank you.
If you put a print statement inside your callback of data you will see on initial load the data is as expected
[{'Type': 'Cash', 'Rate': 50, 'id': 'Cash'}, {'Type': 'Credit Card', 'Rate': 50, 'id': 'Credit Card'}]
Rate holds a numeric value.
But when editing values in the datatable the value could be anything so dash table treats your input as a string and not a number.
So after editing a value in the Rate column data could now look like this
[{'Type': 'Cash', 'Rate': 50, 'id': 'Cash'}, {'Type': 'Credit Card', 'Rate': '200', 'id': 'Credit Card'}]
The value I filled in 200 is now a string in data.
It seems that when both Rate values are string values plotly doesn't know how it should draw the bars anymore.
What you could do is to convert the Rate column of df to numeric.
df['Rate'] = pd.to_numeric(df['Rate'])

Dash Plotly error : Stuck on Loading... page after server run

Could you please help me with this error.
The page stuck with loading.... message but never loads.
There's no error on server run.
This is my code:
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objects as go
import numpy as np
df1 = pd.read_csv('lines.csv', encoding='latin-1', low_memory=False)
df1.rename(columns={"Order Type": "OrderType"}, inplace=True)
df1.loc[(df1.Processed != '?'), 'OrderTypeProcessed'] = df1['Qty']
df1.loc[(df1.Processed == '?'), 'OrderTypeProcessed'] = 0
df2 = df1.groupby('OrderType').sum()
df3 = df1.groupby(' Packout station Number').sum()
df4 = df1.groupby('Packout station Operator').sum()
df5 = df1.groupby('Product Category').sum()
df1.rename(columns={df1.columns[12]:'Received Time'}, inplace=True)
df6 = df1.groupby('Received Time').sum()
df7 = df1.groupby('Cut Off Time').sum()
df2.reset_index(inplace=True)
df3.reset_index(inplace=True)
df4.reset_index(inplace=True)
df5.reset_index(inplace=True)
df6.reset_index(inplace=True)
df7.reset_index(inplace=True)
df5['Product Category'] = df5['Product Category'].str.upper()
app = dash.Dash()
app.layout = html.Div([
html.H1(children = "Dashboard Para Gestão De Produção - Caio",
style = {'textAlign' : 'center',}),
html.Div(children = "_______________________________",
style = {'textAlign' : 'center',}),
dcc.Graph(
id = 'lines-chart',
figure = {
'data' : [
{'x': df2['OrderType'], 'y': df2['Qty'], 'type': 'bar', 'name': 'Dropado'},
{'x': df2['OrderType'], 'y': df2['OrderTypeProcessed'], 'type': 'bar', 'name': 'Realizado'}
],
'layout' : {
'title': 'Grafico'
}
}
)
])
if __name__ == '__main__':
app.run_server(port =4050)
Could you please take a look, I tried call assets in app, however it also didn't work.
Here is the page after server run.
Here is the image that not load in question.

Plotly Dash Display Dynamic Number of Plots Based on SQL Query

I am trying to get the app to display multiple plots in grid format whenever a user changes the date input. This is what I have thus far. Although, when I run the app right now it only displays one, not ALL, of the graphs. I am not sure how to code this so that the number of graphs displayed is dynamic and that they take up just enough space on the screen of whoever is running the app.
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import pyodbc
from datetime import datetime as dt
app = dash.Dash()
app.layout = html.Div(children=[
html.Div(children='''
Enter Date:
'''),
dcc.DatePickerSingle(id='date_picker_single', date=dt(2017, 12, 18)),
html.Div(id='output-graphs'),
])
def connect_sql_server(driver, server, db):
conn_sql_server = pyodbc.connect(
r'DRIVER={' + driver + '};'
r'SERVER=' + server + ';'
r'DATABASE=' + db + ';'
r'Trusted_Connection=yes;',
autocommit=True
)
return conn_sql_server
#app.callback(
Output(component_id='output-graphs', component_property='children'),
[Input(component_id='date_picker_single', component_property='date')]
)
def update_graphs(input_date):
sql_conn = connect_sql_server('ODBC Driver 13 for SQL Server', 'Server', 'Database')
cursor = sql_conn.cursor()
cursor.execute(
"""
exec QCMonotonicityGraphs ?
""", [input_date])
rows = cursor.fetchall()
sql_data = []
for row in rows:
sql_data.append(list(row))
labels = ['strike', 'last', 'call_put', 'title']
df = pd.DataFrame.from_records(sql_data, columns=labels)
unique_titles = df.title.unique()
graphs = []
for unique_title in unique_titles:
title = unique_title
call_strike = []
call_last = []
for row in rows:
if row[2] == 'C' and row[3] == unique_title:
call_strike.append(row[0])
call_last.append(row[1])
put_strike = []
put_last = []
for row in rows:
if row[2] == 'P' and row[3] == unique_title:
put_strike.append(row[0])
put_last.append(row[1])
graphs.append(dcc.Graph(
id='example-graph',
figure={
'data': [
{
'x': call_strike,
'y': call_last,
'mode': 'lines+markers',
'name': 'call'
},
{
'x': put_strike,
'y': put_last,
'mode': 'lines+markers',
'name': 'put'
}
],
'layout': {
'title': title
}
}
))
return graphs
if __name__ == '__main__':
app.run_server(debug=True)
Example

Categories

Resources