Interactive Visualization with Dash and Plotly

Alper Aydın
Towards Data Science
7 min readApr 7, 2019

--

Interactive data visualization has an important impact on exploratory data analysis. Before applying any descriptive or predictive algorithm to a dataset we must first understand how the features are related with each other and how they are distributed inside. It is obvious that many visualization libraries provide numerous types of charts that satisfy this requirement. But another obvious thing is that it is a hard job to do the same plotting work for each feature and scroll over each chart to compare findings for each feature.

For the last couple of weeks, I had to do this job so much that I had to find a shortcut for this. Yes, it is true that I am a lazy man, and yes it is true that laziness is a key to creativity. That is how I met dash and plotly as a solution to my problem. In this post you will find how this couple would be a good solution for exploratory data analysis.

Let me first explain what dash and plotly are for whom did not hear before. Plotly is a data analytics and visualization company. In this writing, we are interested with the two python libraries of this company; plotly.py and dash. Plotly.py library provides interactive visualization for python applications. As indicated on their website, you can “Create interactive, D3 and WebGL charts in Python. All the chart types of matplotlib and more.”

Dash is also another product of the same company, providing a framework for building web based applications for Python. If you are working with a team or just want share your work with others, a web application is the simplest way, eliminating the library version or interface issues. We will see how convenient sharing our findings over the web is, during the rest of this writing.

So, let’s start coding…

A Simple Dash App

Below is a simple dash web application consisting of six lines of code. Just write it down into a .py file and call the file and your app is up and running, that’s all.

#this is the dash_test.py fileimport dash
import dash_html_components as html
app = dash.Dash(__name__)app.layout = html.H1('hello dash')if __name__ == '__main__':
app.run_server(debug=True, port=8080)

Call the file from command prompt as follows, with the exact path of your file. You will see a console windows that tells the server is running.

python "c:\users\alper\documents\dash_test.py"

We can now open a web browser and navigate to the localhost url with the given port number: 127.0.0.1:8080.

In the first two lines of the code, we simply import the required dash libraries. The third line initializes the dash app, fourth line prepares the page layout with a header tag which we will be displaying on the page, and the last two lines run the server with debug and port options. (See the detailed explanation on stackoverflow for the “if __name__ … ” line)

Yes, we are far from both interactivity and visuality but be patient, we are on the way. First, we place the required elements. For this, we will modify app.layout and insert a button and a label element into a div. Note that the two elements are placed in a list as the children of the div element. Dash stores html elements in dash_html_components library, you can find the whole list on their website and github repo.

app.layout = html.Div(
[
html.Button('create random number', id='button1'),
html.Label('...', id='label1')
]
)

When we save the file, we will see a new line on the console window with a new debugger pin. If there is a problem in the code, then we will see the error message instead. In this case, we need to call the file again and refresh the browser.

Now, lets add some styling to the elements we had insert. I can’t say I am good at styling, but I’m sure you can do better. We can add style to an element with style attribute accepting a dictionary of css tags.

  html.Button('create random number', 
id='button1',
style={'display':'block', 'background-color':'#aabbcc'}
),
html.Label('...',
id='label1',
style={'display':'inline-block', 'margin':'10'}
)

And it’s time to go a step further and add some responsiveness. First we import the required libraries

from dash.dependencies import Input, Output
import random

Then we add the callback decorator and the function we want to execute on callback.

@app.callback(
Output(component_id=’label1', component_property=’children’),
[Input(component_id=’button1', component_property=’n_clicks’)]
)
def update_output(input_value):
return random.random()

update_output function simply generates a random number and returns it as result.

@app.callback decorator binds the button click event to the update_output function, and the result of the function to the label1 element. This is the core part of the responsiveness. There will be another post on callbacks and state parameters.

Adding a Simple Chart

Since we covered the interactivity enough for introduction, it is time to add some charts. First, we will keep it simple and put a bar chart with random values on each button click. So, we need to add a graph object to our layout:

app.layout = html.Div(
[
html.Button(‘create random number’,
id=’button1',
style={‘display’:’block’, ‘padding’:’5', ‘background-color’:’#aabbcc’}),
html.Label(‘…’,
id=’label1',
style={‘display’:’inline-block’, ‘margin’:’10'} ),
dcc.Graph(id=’graph1') # this is the graph we add
]
)

And we need to modify our callback function to produce the chart:

@app.callback(
Output(component_id='graph1', component_property='figure'),
[Input(component_id='button1', component_property='n_clicks')]
)
def update_output(input_value):
random_x = [i for i in range(5)]
random_y = [random.random() for _ in range(5)]
figure = {
'data': [
{'x':random_x, 'y':random_y, 'type':'bar', 'name': 'Series1'}
],
'layout': {
'title': 'Dash Data Visualization'
}
}
return figure

In the callback decorator, we first replace the label in our Output statement with the graph object we recently added to our layout. Then inside the function we crate x and y values for the chart, and the figure object. That is all. The result is an interactive bar chart inside your browser.

Some more complexity

If the above chart is not fancy enough for you, don’t worry, here is another example for you. Let’s get some deeper.

Was it too fast? Ok, let’s look at the code then.

# coding=utf8import random
import pandas as pd
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
app = dash.Dash(__name__)
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class']
data = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', names=names)
app.layout = html.Div(
[
html.Div([
dcc.Dropdown(
id='ddl_x',
options=[{'label': i, 'value': i} for i in names],
value='sepal-width',
style={'width':'50%'}
),
dcc.Dropdown(
id='ddl_y',
options=[{'label': i, 'value': i} for i in names],
value='petal-width',
style={'width':'50%'}
),
],style={'width':'100%','display':'inline-block'}),
html.Div([
dcc.Graph(id='graph1')
],style={'width':'100%','display':'inline-block'})
]
)
@app.callback(
Output(component_id='graph1', component_property='figure'),
[
Input(component_id='ddl_x', component_property='value'),
Input(component_id='ddl_y', component_property='value')
]
)
def update_output(ddl_x_value, ddl_y_value):
figure={
'data': [
go.Scatter(
x=data[data['class'] == cls][ddl_x_value],
y=data[data['class'] == cls][ddl_y_value],
mode='markers',
marker={ 'size': 15 },
name=cls
) for cls in data['class'].unique()
],
'layout':
go.Layout(
height= 350,
hovermode= 'closest',
title=go.layout.Title(text='Dash Interactive Data Visualization',xref='paper', x=0)
)

}
return figure
if __name__ == '__main__':
app.run_server(debug=True, port=8080)

The code structure is exactly the same as the previous. After initializing the app,

  • we added two lines for data reading.
  • in the app.layout section, we added two dropdown lists, and fill the options with a loop of data columns.
  • in the @app.callback decorator, we added these two dropdowns as input components
  • and in the update_output function, we draw a scatter plot graph with the data and the columns selected by the dropdown lists. Here, there is a tricky part. We draw the scatter plot for each class. You see, there is a for loop at the end of the go.Scatter() function and inside the ‘data’ list. And this for loop, also called as list comprehension, returns Scatter() objects n times, where n is the number of unique records in the ‘class’ column of the data. And following line is for the layout properties of the chart.

The code is ready to run. Just;

  • save it into a file with .py extension, -> “c:\…\dash_test.py”
  • call it via command prompt using python -> python “c:\…\dash_test.py”
  • open a browser and navigate to the app -> http://localhost:8080

Your interactive data visualization application is ready in 60 lines of code.

That is all for my first writing on Medium. I will keep on writing what I’ve learned. Please share your feelings, so I may improve myself.

Resources:

Edit:

  • go.Layout value was passed inside an array in figure object under update_output function. This caused javascript error in some versions. Removing the array and passing the go.Layout object directly solved the problem. 2019/06/20

--

--