Figures with the plotly module

Apart from matplotlib, there exists many other useful packages. In this notebook, we are going to present the plotly module, that can help us to create elegant and interactive figures.

The syntax of plotly is quite different from that of matplotlib, therefore, we are going to present it through some examples.

Online and offline modes of plotly

Plotly is basically a web interface, where after a free registration and login, everyone has the possibility to upload some data and create interactive figures from it, sharing these figures thereafter. This method enables smoother collaboration within a group, because member not only have acces to the figures, but also to the data and the pieces of code creating the figures. Therefore, if one would like to change the color of a line, it is not necessary to ask the colleague in e-mail, but it is possible to rewrite the code itself.

Sometimes the data cannot be uploaded to a public storage space, and to use a private storage, one has to create a Pro accound, that is obviously not free. It is also common to have very large datafiles, that are tedious to move. In such cases, a local figure making software if preferred, where the data does not have to go to plotly, but plotly comes to the data. This is why there is a plotly offline version, where datafiles are located on our own computers. The following examples are going to use this version. In the online documentation of plotly, we can find a detailed description of the figure-making routines.

Plotly figures have a very similar syntax in JavaScript and R, if anyone is interested, but here, we use its Python version.

Importing the module, loading offline functions

In [1]:
# usual pylab import
%pylab inline 
# plotly-specific import and initialization
from plotly import *
from plotly.offline import *
init_notebook_mode()
Populating the interactive namespace from numpy and matplotlib
IOPub data rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
`--NotebookApp.iopub_data_rate_limit`.

Creating a simple figure

Creating data

As we have already seen in the matplotlib module, every figure begins with loading the data or creating datapoints. Let us now take our usual example: the sine function between $0$ and $2\pi$.

In [2]:
x_points = linspace(0,2*np.pi,10)
y_points = sin(x_points)

Creating the figure

Plotly behaves slightly differently, than what we've been used to in the case of matplotlib. Here, a figure is created from a multi-level dictionary. Every single propery of the figure can be controlled through key-value dictionary pairs.

The highest level of the figure hierarchy is represented through two main categories: traces and layout. A trace is an object that contains the description of one data series, such as a Scatter or a Heatmap object. A figure may contain several traces, for example, if we would like to put two series of data on one figure. traces might also be combined, we can present bar charts next to scattered measurement points. layout contains the parameters controlling the overall appeareance of the figure, such as figure title, background color, axis labels, and further annotations, for example texts.

The documentation of plotly can be of great help.

Creating traces

First, we have to create our traces from the data. In the example, the figure shows the points stored in the y_points array as a function of the points stored in the x_points array. The points are going to be linked by a continuous line:

In [3]:
trace_sin_curve = graph_objs.Scatter(x=x_points, y=y_points, mode='lines')
trace_sin_curve
Out[3]:
{'mode': 'lines',
 'type': 'scatter',
 'x': array([ 0.        ,  0.6981317 ,  1.3962634 ,  2.0943951 ,  2.7925268 ,
         3.4906585 ,  4.1887902 ,  4.88692191,  5.58505361,  6.28318531]),
 'y': array([  0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
          8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
         -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
         -2.44929360e-16])}

Here, we've created a "graph" object, that is of Scatter type. From the print we can see that altough we've defined the graph as an object, it is basically a dict, in which the value 'scatter' belongs to the keyword 'type'. Thus, we could also give the same graph with the folowing dict, using objects is just because of convenience:

In [4]:
trace_sine = {'mode': 'lines',
                  'type' : 'scatter',
                  'x': x_points,
                  'y': y_points}

We have to be aware to separate key-value entries by a : if use the dict definition, and by a =, if we use the object-oriented notation.

The 'lines' value at the 'mode' keyword makes our points connected by a line. If we just want the scattered datapoints, we have to use 'markers' instead.

We have to put the trace objects into a list, here, it is the sine_data list. Because in this example, we only used one trace, we could in theory leave this step out, but if we have more, the list is compulsory.

In [5]:
sine_data = [trace_sine]

2. Defining the layout

Let us give a title to our figure, and let us put labels on the axes by specifying the Layout object.

In [6]:
layout_sine = graph_objs.Layout(title='This is the title of the figure.',
                                    xaxis=graph_objs.XAxis(title='x'), 
                                    yaxis=graph_objs.YAxis(title='sin(x)'))
layout_sine
Out[6]:
{'title': 'Ez az ábra címe',
 'xaxis': {'title': 'x'},
 'yaxis': {'title': 'sin(x)'}}

The xaxis variable of the Layout object if the XAxis object, in which we can directly give the value of the title variable. It goes similarly for the yaxis variable. Just as in the case of the trace, these objects can also be given with a dictionary.

In [7]:
layout_sine = {'title': 'This is the title of the figure.',
                  'xaxis': {'title': 'x'},
                  'yaxis': {'title': 'sin(x)'}}

3. Creating the Figure object

If we are done with all necessary objects (traces from the data, and layout for the formatting), we can put them together into a Figure object:

In [8]:
figure_sine = graph_objs.Figure(data=sine_data, layout=layout_sine)
figure_sine
Out[8]:
{'data': [{'mode': 'lines',
   'type': 'scatter',
   'x': array([ 0.        ,  0.6981317 ,  1.3962634 ,  2.0943951 ,  2.7925268 ,
           3.4906585 ,  4.1887902 ,  4.88692191,  5.58505361,  6.28318531]),
   'y': array([  0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
            8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
           -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
           -2.44929360e-16])}],
 'layout': {'title': 'Ez az ábra címe',
  'xaxis': {'title': 'x'},
  'yaxis': {'title': 'sin(x)'}}}

This is also just a multi-level dict, that we could have defined through the traditional dict construction.


4. Plotting the figure

We can plot our Figure object now.

In [9]:
iplot(figure_sine)

Summary:

It may look overcomplicated, but we can create our figure in a few lines. We've seen that the graph objects are always created from the graph_objs submodule. Thus, if we load all functions from this submodule, we won't have to write graph_objs. anymore.

The above figure is not very smooth for a real sine function, but we can help it: we increase the sample size in x, and then replot the figure, but now together with the cosine function. Now, we already have to make two trace objects.

In [10]:
from plotly.graph_objs import *
In [11]:
x_points_new = linspace(0,2*np.pi,50)
y_points_sin = sin(x_points_new)
y_points_cos = cos(x_points_new)
trace_sin = Scatter(x=x_points_new, y=y_points_sin, mode='lines')
trace_cos = Scatter(x=x_points_new, y=y_points_cos, mode='lines')
data = [trace_sin, trace_cos]
layout_sin = Layout(title='New title',
                          xaxis=XAxis(title='x'), 
                          yaxis=YAxis(title='sin(x), cos(x)'))
figure_new = Figure(data=data, layout=layout_sin)
iplot(figure_new)

What nice smooth curves we got! Let us check, if this is really the case. There are some button in the top right corner of the figure, let's try to zoom into the picture! We can see, that by increasing the scale, this figure can also get "edgy".

It is a great opportunity, that plotly offers these interactive viewing tools. If there are many datapoints on a figure, then we can only trace the difference between them by zooming in. In the legend, by clicking on the trace_0 and trace_1 labels, we can make the sine and the cosine functions appear and disappear.

Creating a bar chart

We only have to alter the type of the trace:

In [12]:
trace_sin = Scatter(x=x_points_new, y=y_points_sin, mode='lines')
trace_cos = Bar(x=x_points_new, y=y_points_cos)
data = [trace_sin, trace_cos]
layout_bar = Layout(title='Title of barchart',
                          xaxis=XAxis(title='x'), 
                          yaxis=YAxis(title='sin(x), cos(x)'))
figure_bar = Figure(data=data, layout=layout_bar)
iplot(figure_bar)

3D figures

Let us now see some examples for plotly 3D figures.

In [13]:
t=linspace(0,2*pi,100) # sampling points
xp=cos(3*t)            # parametrizing a spiral
yp=sin(3*t)
zp=t

Instead of the Scatter object, we now have to use its 3D variant, Scatter3d.

In [14]:
trace = Scatter3d(x=xp, y=yp, z=zp, mode='lines') # data to a trace
data = [trace]
layout3d=Layout(title='Spiral')
fig_3D = Figure(data=data,layout=layout3d) # figure object
iplot(fig_3D) # plot

For the next 3D figure, the coordinates of the points are stored in the plotly_3D.txt textfile. This is the source of the data, similar datasets can be found here.

The first three columns of the datafile are the x, y and z coordinates, respectively. First, let's read the data with the loadtxt function of the numpy module.

In [15]:
data_file = loadtxt('data/plotly_3D.txt')
xa = data_file[:,0]
ya = data_file[:,1]
za = data_file[:,2]

Similarly to the spiral, we define the trace, layout and figure objects. What effect do the different options have, that we give to Scatter3d and Layout?

In [17]:
# trace object
trace_3D = Scatter3d(x=xa, y=ya, z=za, mode='markers', marker = dict(size=2))
data_3D = [trace_3D]
#layout object
layout_3D = Layout(width=900,height=500,scene=dict(aspectmode='manual', aspectratio = dict(x=0.2, y=1, z=2/3)))
#figure object and display
fig_3D = Figure(data=data_3D, layout=layout_3D)
iplot(fig_3D)

In the last example, we are going to create surfaces with the help of plotly. First, let's create a simple data series, that samples a 2D Gaussian $z=e^{-x^2-y^2}$.

In [18]:
x,y=meshgrid(linspace(-5,5,50),linspace(-5,5,50)) # sampling in the x0y plane
z=exp(-x**2-y**2) # z coordinates as a function of x and y

The used function and object routines have many very elaborate default values, therefore, a quick construction also gives a reasonable result:

In [19]:
iplot(Figure(data=[Surface(x=x,y=y,z=z)]))