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.
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.
# usual pylab import
%pylab inline
# plotly-specific import and initialization
from plotly import *
from plotly.offline import *
init_notebook_mode()
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$.
x_points = linspace(0,2*np.pi,10)
y_points = sin(x_points)
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 trace
s
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:
trace_sin_curve = graph_objs.Scatter(x=x_points, y=y_points, mode='lines')
trace_sin_curve
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:
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.
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.
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
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.
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 (trace
s from the data, and layout
for the formatting), we can put them together into a Figure
object:
figure_sine = graph_objs.Figure(data=sine_data, layout=layout_sine)
figure_sine
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.
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.
from plotly.graph_objs import *
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.
We only have to alter the type of the trace:
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)
Let us now see some examples for plotly 3D figures.
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
.
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.
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
?
# 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}$.
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:
iplot(Figure(data=[Surface(x=x,y=y,z=z)]))