Here is my code:
import os
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State
from plotly import tools
from demo_utils import demo_components, demo_callbacks, demo_explanation
names = [‘step’, ‘var1’,‘var2’,‘var3’]
LOGFILE = ‘data.csv’
app = dash.Dash(name)
server = app.server
def chunk_generator(filename, header=False, chunk_size=1):
for chunk in pd.read_csv(filename, delimiter=’,’,iterator=True,chunksize=chunk_size,parse_dates=[1]):
yield chunk
def generator1(filename, header=False, chunk_size=1):
chunk = chunk_generator(filename, header=False, chunk_size=1)
for row in chunk:
yield row
run_log_df = generator1(filename=LOGFILE)
Custom Script for Heroku, switch to demo mode when hosted on Heroku
if ‘DYNO’ in os.environ:
app.scripts.append_script({
‘external_url’: ‘https://cdn.rawgit.com/chriddyp/ca0d8f02a1659981a0ea7f013a378bbd/raw/e79f3f789517deec58f41251f7dbb6bee72c44ab/plotly_ga.js’
})
demo_mode = True
else:
demo_mode = False
def div_graph(name):
“”“Generates an html Div containing graph and control options for smoothing and display, given the name”""
return html.Div([
html.Div(
id=f’div-{name}-graph’,
className=“ten columns”
),
html.Div([
html.Div([
html.P(f'{name}: ', style={'font-weight': 'bold', 'margin-bottom': '0px'}),
],
style={'margin-top': '10px'}
),
html.Div([
html.P("Plot Display mode:", style={'font-weight': 'bold', 'margin-bottom': '0px'}),
dcc.RadioItems(
options=[
{'label': ' Overlapping', 'value': 'overlap'},
{'label': ' Separate (Vertical)', 'value': 'separate_vertical'},
{'label': ' Separate (Horizontal)', 'value': 'separate_horizontal'}
],
value='overlap',
id=f'radio-display-mode-{name}'
),
html.Div(id=f'div-current-{name}-value')
]),
],
className="two columns"
),
],
className="row"
)
traces=[]
app.layout = html.Div([
# Banner display
html.Div([
html.H2(
‘Live Model Training Viewer’,
id=‘title’
),
html.Img(
src=“https://s3-us-west-1.amazonaws.com/plotly-tutorials/logo/new-branding/dash-logo-by-plotly-stripe-inverted.png”
)
],
className=“banner”
),
# Body
html.Div([
html.Div([
dcc.Dropdown(
id='dropdown-interval-control',
options=[
{'label': 'No Updates', 'value': 'no'},
{'label': 'Slow Updates', 'value': 'slow'},
{'label': 'Regular Updates', 'value': 'regular'},
{'label': 'Fast Updates', 'value': 'fast'}
],
value='regular',
className='ten columns',
clearable=False,
searchable=False
),
html.Div(
id="div-step-display",
className="two columns"
)
],
id='div-interval-control',
className='row'
),
dcc.Interval(
id="interval-log-update",
interval=1*1000,
n_intervals=0
),
# Hidden Div Storing JSON-serialized dataframe of run log
html.Div(id='run-log-storage', style={'display': 'none'}),
# The html divs storing the graphs and display parameters
div_graph('accuracy'),
#div_graph('cross-entropy'),
# Explanation for the demo version of the app
#demo_explanation(demo_mode)
],
className="container"
)
])
def update_graph(graph_id,
graph_title,
run_log_json,
display_mode,
yaxis_title):
“”"
:param graph_id: ID for Dash callbacks
:param graph_title: Displayed on layout
:param y_train_index: name of column index for y train we want to retrieve
:param y_val_index: name of column index for y val we want to retrieve
:param run_log_json: the json file containing the data
:param display_mode: ‘separate’ or ‘overlap’
:param checklist_smoothing_options: ‘train’ or ‘val’
:param slider_smoothing: value between 0 and 1, at interval of 0.05
:return: dcc Graph object containing the updated figures
“”"
if run_log_json: # exists
layout = go.Layout(title=graph_title,showlegend=False,margin=go.Margin(l=50, r=50, b=50, t=50),yaxis={'title': yaxis_title})
run_log_df = pd.read_json(run_log_json, orient='split')
step = run_log_df['step']
y_train = run_log_df['var1']
y_val = run_log_df['var2']
trace_train = go.Scatter(
x=step,
y=y_train,
mode='lines+markers',
name='Training'
)
traces.append(trace_train)
trace_val = go.Scatter(
x=step,
y=y_val,
mode='lines+markers',
name='Validation'
)
traces.append(trace_val)
if display_mode == 'separate_vertical':
figure = tools.make_subplots(rows=2,
cols=1,
print_grid=False,
shared_yaxes=True)
figure.append_trace(trace_train, 1, 1)
figure.append_trace(trace_val, 2, 1)
figure['layout'].update(title=layout.title,
margin=layout.margin,
scene={'domain': {'x': (0., 0.5), 'y': (0.5,1)}})
elif display_mode == 'separate_horizontal':
figure = tools.make_subplots(rows=1,
cols=2,
shared_yaxes=True,
print_grid=False)
figure.append_trace(trace_train, 1, 1)
figure.append_trace(trace_val, 1, 2)
figure['layout'].update(title=layout.title,
margin=layout.margin)
elif display_mode == 'overlap':
figure = go.Figure(
data=traces,
layout=layout
)
else:
figure = None
return dcc.Graph(figure=figure, id=graph_id)
return dcc.Graph(id=graph_id)
@app.callback(Output(‘interval-log-update’, ‘interval’),
[Input(‘dropdown-interval-control’, ‘value’)])
def update_interval_log_update(interval_rate):
if interval_rate == ‘fast’:
return 500
elif interval_rate == 'regular':
return 1000
elif interval_rate == 'slow':
return 5 * 1000
# Refreshes every 24 hours
elif interval_rate == 'no':
return 24 * 60 * 60 * 1000
if not demo_mode:
@app.callback(Output(‘run-log-storage’, ‘children’),
[Input(‘interval-log-update’, ‘n_intervals’)])
def get_run_log(_):
names = [‘step’, ‘var1’,‘var2’,‘var3’]
try:
temp = next(run_log_df).values.tolist()
temp_df = pd.DataFrame(temp, columns=names)
json = temp_df.to_json(orient='split')
except FileNotFoundError as error:
print(error)
print("Please verify if the csv file generated by your model is placed in the correct directory.")
return None
return json
@app.callback(Output(‘div-step-display’, ‘children’),
[Input(‘run-log-storage’, ‘children’)])
def update_div_step_display(run_log_json):
if run_log_json:
run_log_df = pd.read_json(run_log_json, orient=‘split’)
return html.H6(f"Step: {run_log_df[‘step’].iloc[-1]}", style={‘margin-top’: ‘3px’})
@app.callback(Output(‘div-accuracy-graph’, ‘children’),
[Input(‘run-log-storage’, ‘children’),
Input(‘radio-display-mode-accuracy’, ‘value’)])
def update_accuracy_graph(run_log_json,
display_mode):
graph = update_graph(‘accuracy-graph’,
‘Prediction Accuracy’,
run_log_json,
display_mode,
‘Accuracy’)
# try:
# if display_mode in ['separate_horizontal', 'overlap']:
# graph.figure.layout.yaxis['range'] = [0, 1]
# else:
# graph.figure.layout.yaxis1['range'] = [0, 1]
# graph.figure.layout.yaxis2['range'] = [0, 1]
# except AttributeError:
# pass
return [graph]
@app.callback(Output(‘div-current-accuracy-value’, ‘children’),
[Input(‘run-log-storage’, ‘children’)])
def update_div_current_accuracy_value(run_log_json):
if run_log_json:
run_log_df = pd.read_json(run_log_json, orient=‘split’)
return [
html.P(
“Current Accuracy:”,
style={
‘font-weight’: ‘bold’,
‘margin-top’: ‘15px’,
‘margin-bottom’: ‘0px’
}
),
html.Div(f"Training: {run_log_df[‘var1’].iloc[-1]:.4f}"),
html.Div(f"Validation: {run_log_df[‘var2’].iloc[-1]:.4f}")
]
external_css = [
“https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css”, # Normalize the CSS
“https://fonts.googleapis.com/css?family=Open+Sans|Roboto” # Fonts
“https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css”,
“https://cdn.rawgit.com/xhlulu/0acba79000a3fd1e6f552ed82edb8a64/raw/dash_template.css”,
“https://rawgit.com/plotly/dash-live-model-training/master/custom_styles.css”
]
for css in external_css:
app.css.append_css({“external_url”: css})
Running the server
if name == ‘main’:
app.run_server(debug=True)