bqplot https://github.com/bloomberg/bqplot

A Jupyter - d3.js bridge

bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.

  • Apache Licensed

bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.

bqplot provides both

  • high-level plotting procedures with relevant defaults for common chart types,
  • lower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.

Installation:

conda install -c conda-forge bqplot

In [1]:
from __future__ import print_function
from IPython.display import display
from ipywidgets import *
from traitlets import *

import numpy as np
import pandas as pd
import bqplot as bq
import datetime as dt

In [2]:
np.random.seed(0)
size = 100
y_data = np.cumsum(np.random.randn(size) * 100.0)
y_data_2 = np.cumsum(np.random.randn(size))
y_data_3 = np.cumsum(np.random.randn(size) * 100.)

x = np.linspace(0.0, 10.0, size)

price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.8], [0.8, 1.0]]), axis=0) + 100,
                          columns=['Security 1', 'Security 2'],
                          index=pd.date_range(start='01-01-2007', periods=150))

symbol = 'Security 1'
dates_all = price_data.index.values
final_prices = price_data[symbol].values.flatten()

A simple plot with the pyplot API


In [3]:
from bqplot import pyplot as plt

In [4]:
plt.figure(1)
n = 100
plt.plot(np.linspace(0.0, 10.0, n), np.cumsum(np.random.randn(n)), 
         axes_options={'y': {'grid_lines': 'dashed'}})
plt.show()


Scatter Plot


In [5]:
plt.figure(title='Scatter Plot with colors')
plt.scatter(y_data_2, y_data_3, color=y_data)
plt.show()


Histogram


In [6]:
plt.figure()
plt.hist(y_data, colors=['OrangeRed'])
plt.show()


Every component of the figure is an independent widget


In [7]:
xs = bq.LinearScale()
ys = bq.LinearScale()
x = np.arange(100)
y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks

line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])
xax = bq.Axis(scale=xs, label='x', grid_lines='solid')
yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')

fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)
display(fig)



In [8]:
# update data of the line mark
line.y = np.cumsum(np.random.randn(2, 100), axis=1)

In [9]:
xs = bq.LinearScale()
ys = bq.LinearScale()
x, y = np.random.rand(2, 20)
scatt = bq.Scatter(x=x, y=y, scales={'x': xs, 'y': ys}, default_colors=['blue'])
xax = bq.Axis(scale=xs, label='x', grid_lines='solid')
yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')

fig = bq.Figure(marks=[scatt], axes=[xax, yax], animation_duration=1000)
display(fig)



In [10]:
#data updates
scatt.x = np.random.rand(20) * 10
scatt.y = np.random.rand(20)

The same holds for the attributes of scales, axes


In [11]:
xs.min = 4

In [12]:
xs.min = None

In [13]:
xax.label = 'Some label for the x axis'

Use bqplot figures as input widgets


In [14]:
xs = bq.LinearScale()
ys = bq.LinearScale()
x = np.arange(100)
y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks

line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])
xax = bq.Axis(scale=xs, label='x', grid_lines='solid')
yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')

Selections


In [15]:
def interval_change_callback(change):
    db.value = str(change['new'])

intsel = bq.interacts.FastIntervalSelector(scale=xs, marks=[line])
intsel.observe(interval_change_callback, names=['selected'] )

db = widgets.Label()
db.value = str(intsel.selected)
display(db)



In [16]:
fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000, interaction=intsel)
display(fig)



In [17]:
line.selected


Out[17]:
[]

Handdraw


In [18]:
handdraw = bq.interacts.HandDraw(lines=line)
fig.interaction = handdraw

In [19]:
line.y[0]


Out[19]:
array([  0.83265074,   1.15971695,   2.79131438,   3.16907355,
         3.40894065,   3.56789933,   3.76076328,   2.603746  ,
         3.37441906,   3.24397932,   5.06589442,   4.99024395,
         5.41116223,   5.65776442,   5.03220738,   6.02434421,
         7.92940785,   7.91463063,   7.61415185,   7.25912312,
         5.36676122,   5.18894808,   5.4399462 ,   6.49470412,
         7.45475186,   7.03825278,   6.76142978,   7.88533509,
         7.71187119,   7.20184165,   8.5943601 ,   9.63194577,
         9.65073756,   9.05696011,   7.04507979,   7.6347834 ,
         6.73841368,   4.77568167,   6.3605022 ,   7.00846999,
         5.86946179,   4.65506041,   5.52602219,   4.64805158,
         5.94420144,   6.56066076,   7.09725728,   7.50195273,
         7.6934036 ,   8.5739148 ,   8.11983444,   8.20578642,
         8.957733  ,   9.52072272,   8.32573592,   7.82532625,
         8.07812975,   7.67011505,   9.44477361,   9.05162041,
         8.88940196,   9.65883214,   9.98936489,   9.84409043,
         9.0875969 ,   9.38911096,  10.4282074 ,  10.90730262,
        10.1291191 ,  11.86589406,  10.41931617,   8.83663052,
         9.79718775,  10.02302823,   9.47352968,   8.37495895,
        10.69575879,  10.81284967,  11.34705084,  11.66493593,
        12.09974389,  12.63983835,  13.37226236,  12.99703996,
        12.70539797,  10.96437517,  10.18407076,  10.45518356,
        11.50020693,  12.09924646,  11.75855411,  10.4953812 ,
         7.71802206,   8.86975603,   8.28052704,   7.83206204,
         7.96363601,   6.55807596,   6.20829378,   8.23176573])

Moving points around


In [20]:
from bqplot import *

size = 100
np.random.seed(0)
x_data = range(size)
y_data = np.cumsum(np.random.randn(size) * 100.0)

## Enabling moving of points in scatter. Try to click and drag any of the points in the scatter and 
## notice the line representing the mean of the data update

sc_x = LinearScale()
sc_y = LinearScale()

scat = Scatter(x=x_data[:10], y=y_data[:10], scales={'x': sc_x, 'y': sc_y}, default_colors=['blue'],
               enable_move=True)
lin = Lines(scales={'x': sc_x, 'y': sc_y}, stroke_width=4, line_style='dashed', colors=['orange'])
m = Label(value='Mean is %s'%np.mean(scat.y))

def update_line(change):
    with lin.hold_sync():
        lin.x = [np.min(scat.x), np.max(scat.x)]
        lin.y = [np.mean(scat.y), np.mean(scat.y)]
        m.value='Mean is %s'%np.mean(scat.y)
        

update_line(None)

# update line on change of x or y of scatter
scat.observe(update_line, names='x')
scat.observe(update_line, names='y')

ax_x = Axis(scale=sc_x)
ax_y = Axis(scale=sc_y, tick_format='0.2f', orientation='vertical')

fig = Figure(marks=[scat, lin], axes=[ax_x, ax_y])

## In this case on drag, the line updates as you move the points.
with scat.hold_sync():
    scat.enable_move = True
    scat.update_on_move = True
    scat.enable_add = False

display(m, fig)


Label(colors=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'], interactions={'hover': 'tooltip'}, scales_metadata={'x': {'orientation': 'horizontal', 'dimension': 'x'}, 'y': {'orientation': 'vertical', 'dimension': 'y'}, 'color': {'dimension': 'color'}, 'size': {'dimension': 'size'}, 'opacity': {'dimension': 'opacity'}, 'rotation': {'dimension': 'rotation'}}, tooltip_style={'opacity': 0.9})