In this post, we will be building a data visualization using Plotly Dash 2.0 (in fact, it will be the same regression visualization that was created in these two blog posts: HERE and HERE). As a reminder from those two posts, this visualization will demonstrate linear regression on random data by creating a sample dataset using the scikit-learn function "make_regression", which will actually generate the data behind-the-scenes. Plotly controls will be used to supply the required parameters to the function.
The first section below contains the header of the function (with useful information about what it does, who wrote it, when it was last updated), along with importing all required libraries.
In [1]:
### Plotly Linear Regression Example
### Written By: Eric Strong
### Last Updated: 2017/07/02
import dash
import numpy as np
import plotly.graph_objs as go
import dash_core_components as dcc
import dash_html_components as html
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression as LR
As one of the first things that will be seen when the code is opened, a parameter defaults section allows the controls to be easily changed, without digging too deeply into the code. In the code below, the defaults and ranges for the number of samples, the bias, and the amount of noise can be adjusted easily. These will be inputs to the "make_regression" function.
In [2]:
###------------------------------------------------------------------------###
###------------------------PARAMETER DEFAULTS------------------------------###
### This section contains defaults and ranges for the Plotly controls and ###
### may be modified without concern, if required. ###
###------------------------------------------------------------------------###
# The format for this section is: default, range[Lower, Upper, Step Size]
d_nsamp, r_nsamp = 100, [50, 500, 50] # Number of samples
d_bias, r_bias = 0, [-50, 50, 5] # Bias
d_noise, r_noise = 3, [0, 20, 1] # Amount of noise
Based on the different way that Plotly apps are laid out, the order of the sections will be changed somewhat, compared to the Bokeh example. The next section contains the base level function(s), which in this case will be used to generate data.
In [ ]:
###------------------------------------------------------------------------###
###-----------------------BASE-LEVEL FUNCTIONS-----------------------------###
### This section contains the low-level calculations required for the ###
### regression modeling. ###
###------------------------------------------------------------------------###
def create_data(n_samp, bias, noise):
# Creates a set of random data based on user parameters
data = make_regression(n_samp, 1, 1, 1, bias, noise=noise)
x_data = np.array([i[0] for i in data[0]]) # Because it's an array of arrays
y_data = data[1]
return x_data, y_data
The next section defines the layout of the Plotly Dash app, including the controls and graphs that will be present in the GUI. This layout includes a plot of the data and the sliders for the parameters (number of samples, bias, and noise). Note that the defaults and ranges for the controls were defined in the previous section, so this section should not need modification unless new controls are being added.
In [3]:
###------------------------------------------------------------------------###
###----------------------GRAPHICAL USER INTERFACE--------------------------###
### This code defines the Plotly controls that are used for the user ###
### interface. All the defaults for the controls are above. This code ###
### should not need to be modified. ###
###------------------------------------------------------------------------###
# Generate example data to be initialized in the graph
d_xdata, d_ydata = create_data(d_nsamp, d_bias, d_noise)
# App defines the entire Dash application, containing the layout and controls
# for the visualization (in app.layout)
app = dash.Dash()
app.layout = html.Div(children=[
html.Div('Sample Size'),
dcc.Slider(min=r_nsamp[0], max=r_nsamp[1], value=d_nsamp, id="samp_slider",
marks={i:str(i) for i in range(r_nsamp[0], r_nsamp[1], r_nsamp[2])}),
html.Div('Bias'),
dcc.Slider(min=r_bias[0], max=r_bias[1], value=d_bias, id="bias_slider",
marks={i:str(i) for i in range(r_bias[0], r_bias[1], r_bias[2])}),
html.Div('Noise'),
dcc.Slider(min=r_noise[0], max=r_noise[1], value=d_noise, id="noise_slider",
marks={i:str(i) for i in range(r_noise[0], r_noise[1], r_noise[2])}),
# Define the graph which is updated based on the controls
dcc.Graph(id='regression-example',
figure={
'data': [go.Scatter(x=d_xdata, y=d_ydata, mode='markers',
marker={
'size': 15,
'opacity': 0.5,
'line': {'width': 0.5, 'color': 'white'}
})],
'layout': {'title': 'Regression Data Example in Plotly'}})
])
Finally, the "Callbacks" section defines what happens when the user controls are interacted with (sample size, noise, and bias sliders). If the user controls are changed in any way, new data will be generated based on their values and the figure will be updated automatically. Plotly Dash does this using a function decorator called @app.callback. It's important to remember that the inputs specified in the decorator will be in the same order as the parameters to the function.
In [6]:
###-----------------------------------------------------------------------###
###----------------------------CALLBACKS----------------------------------###
### This section defines the behavior of the GUI as the user interacts ###
### with the controls. ###
###-----------------------------------------------------------------------###
# Define which inputs (the sliders) go to which outputs (the figure)
@app.callback(
dash.dependencies.Output('regression-example', 'figure'),
[dash.dependencies.Input('samp_slider', 'value'),
dash.dependencies.Input('bias_slider', 'value'),
dash.dependencies.Input('noise_slider', 'value')])
def update_graph(sampling_rate, bias, noise):
xdata, ydata = create_data(sampling_rate, bias, noise)
return {
'data': [go.Scatter(x=xdata, y=ydata, mode='markers',
marker={
'size': 15,
'opacity': 0.5,
'line': {'width': 0.5, 'color': 'white'}
})],
'layout': {'title': 'Regression Data Example in Plotly'}}
if __name__ == '__main__':
app.run_server()
Overall, the Plotly Dash code is very easy to understand and clear to read. Using a function decorator for callbacks provides a simple way to update the plots.
The final visualization will look like this: