In [ ]:
from __future__ import print_function
import numpy as np
import pandas as pd

import ipywidgets

from bqplot import (ColorScale, DateColorScale, OrdinalColorScale, 
                    LinearScale, Tooltip)
import bqplot.pyplot as plt

Get Data


In [ ]:
price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[1.0, -0.8], [-0.8, 1.0]]), axis=0) + 100,
                          columns=['Security 1', 'Security 2'], index=pd.date_range(start='01-01-2007', periods=150))
size = 100
np.random.seed(0)
x_data = range(size)
y_data = np.cumsum(np.random.randn(size) * 100.0)
ord_keys = np.array(['A', 'B', 'C', 'D', 'E', 'F'])
ordinal_data = np.random.randint(5, size=size)

In [ ]:
symbols = ['Security 1', 'Security 2']

dates_all = price_data.index.values
dates_all_t = dates_all[1:]
sec1_levels = np.array(price_data[symbols[0]].values.flatten())
log_sec1 = np.log(sec1_levels)
sec1_returns = log_sec1[1:] - log_sec1[:-1]

sec2_levels = np.array(price_data[symbols[1]].values.flatten())

Basic Scatter


In [ ]:
fig = plt.figure()
axes_options = {'x': {'label': 'Date'}, 'y': {'label': 'Security 2'}}
scatt = plt.scatter(dates_all, sec2_levels, axes_options=axes_options, stroke='black')
fig

Changing the marker and adding text to each point of the scatter


In [ ]:
fig = plt.figure(padding_x=0.025)
scatt = plt.scatter(x_data[:10], y_data[:10], names=np.arange(10),
                    colors=['red'], marker='cross')
fig

Changing the opacity of each marker


In [ ]:
scatt.default_opacities = [0.3, 0.5, 1.]

Representing additional dimensions of data

Linear Scale for Color Data


In [ ]:
# give extra margin on the right to accommodate the color axis
fig_margin = dict(top=50, bottom=70, left=50, right=100)
fig = plt.figure(title='Scatter', fig_margin=fig_margin)
plt.scales(scales={'color': ColorScale()})

axes_options = {'x': dict(label='Date', num_ticks=10, label_location='end'), 
                'y': dict(label='Security 2', sid='left'),
                'color': dict(tick_format='0.2%', 
                              label='Returns', 
                              orientation='vertical', 
                              side='right')}
scatter = plt.scatter(dates_all, sec2_levels, color=sec1_returns, 
                      stroke='black', axes_options=axes_options)
fig

In [ ]:
## Changing the default color. 
scatter.colors = ['blue']  # In this case, the dot with the highest X changes to blue.

In [ ]:
## setting the fill to be empty
scatter.stroke = None
scatter.fill = False

In [ ]:
## Setting the fill back
scatter.stroke = 'black'
scatter.fill = True

In [ ]:
## Changing the color to a different variable
scatter.color = sec2_levels
color_axis = [a for a in fig.axes if type(a.scale) == ColorScale][0]
color_axis.tick_format = '0.0f'
color_axis.label = 'Security 2'

In [ ]:
## Changing the range of the color scale
color_axis.scale.colors = ['blue', 'green', 'orange']

Date Scale for Color Data


In [ ]:
fig = plt.figure(fig_margin=dict(top=50, bottom=80, left=50, right=50))
plt.scales(scales={'color': DateColorScale(scheme='Reds')})

axes_options = {'x': dict(label='Security 2'),
                'y': dict(label='Security 1'),
                'color': dict(tick_format='0.2%', label='Date', num_ticks=5)
               }
scatter = plt.scatter(sec2_levels, sec1_levels, color=dates_all, 
                      default_size=128, stroke='black',
                      axes_options=axes_options)
fig

Ordinal Scale for Color


In [ ]:
factor = int(np.ceil(len(sec2_levels) * 1.0 / len(ordinal_data)))
ordinal_data = np.tile(ordinal_data, factor)

fig = plt.figure(fig_margin=dict(top=50, bottom=70, left=100, right=100))
plt.scales(scales={'color': OrdinalColorScale(colors=['DodgerBlue', 'SeaGreen', 'Yellow', 'HotPink', 'OrangeRed'])})

axes_options = {'x': dict(label='Security 2', label_location='end'),
                'y': dict(label='Security 1 Returns', tick_format='.0%'),
                'color': dict(label='Class', side='right')
               }
scatter2 = plt.scatter(sec2_levels[1:],
                       sec1_returns,
                       color=ordinal_data,
                       stroke='black',
                       axes_options=axes_options)
fig

In [ ]:
color_axis = [a for a in fig.axes if isinstance(a.scale, ColorScale)][0]
color_axis.tick_format = '0.2f'
color_axis.scale.colors = ['blue', 'red', 'green', 'yellow', 'orange']

Setting size and opacity based on data


In [ ]:
fig = plt.figure()
plt.scales(scales={'opacity': LinearScale(), 'size': LinearScale()})
axes_options = {'x': {'label': 'Security 2'}, 'y': {'label': 'Security 1'}}

scatter2 = plt.scatter(sec2_levels[1:], sec1_levels, opacity=[], 
                       size=sec1_returns,
                       default_size=128, colors=['orangered'], 
                       stroke='black', axes_options=axes_options)
fig

In [ ]:
## Changing the opacity of the scatter
scatter2.default_opacities = [0.5, 0.3, 0.1]

In [ ]:
## Resetting the size for the scatter
scatter2.size=None

In [ ]:
## Resetting the opacity and setting the opacity according to the date
scatter2.default_opacities = [1.0]

In [ ]:
scatter2.opacity = dates_all

Changing the skew of the marker


In [ ]:
fig = plt.figure(animation_duration=1000)
plt.scales(scales={'skew': LinearScale()})
axes_options = {'x': {'label': 'Security 2'}, 'y': {'label': 'Security 1'}}
scatter = plt.scatter(sec2_levels[1:], sec1_levels,
                      skew=sec1_returns, stroke="black",
                      colors=['gold'], default_size=200, 
                      marker='rectangle', default_skew=0,
                      axes_options=axes_options)
fig

In [ ]:
scatter.skew = None

In [ ]:
scatter.skew = sec1_returns

Rotation scale


In [ ]:
x1 = np.linspace(-1, 1, 30)
y1 = np.linspace(-1, 1, 30)
x, y = np.meshgrid(x1,y1)
x, y = x.flatten(), y.flatten()
rot = x**2 + y**2
color = x - y

fig = plt.figure(animation_duration=1000)
plt.scales(scales={'color': ColorScale(scheme='Reds'), 'rotation': LinearScale()})
scatter = plt.scatter(x, y, rotation=rot, color=color,
                      stroke="black", default_size=200, 
                      marker='arrow', default_skew=0.5,)
fig

In [ ]:
scatter.rotation = 1.0 / (x ** 2 + y ** 2 + 1)

Scatter Chart Interactions

Moving points in Scatter


In [ ]:
## 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
fig = plt.figure()
scat = plt.scatter(x_data[:10], y_data[:10], colors=['orange'], enable_move=True)
lin = plt.plot([], [], line_style='dotted', colors=['orange'])

def update_line(change=None):
    with lin.hold_sync():
        lin.x = [np.min(scat.x), np.max(scat.x)]
        lin.y = [np.mean(scat.y), np.mean(scat.y)]

update_line()

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

fig

In [ ]:
latex_widget = ipywidgets.Label()

def callback_help(name, value):
    latex_widget.value = str(value)
    
latex_widget

In [ ]:
scat.on_drag_start(callback_help)

In [ ]:
scat.on_drag(callback_help)

In [ ]:
scat.on_drag_end(callback_help)

In [ ]:
## Restricting movement to only along the Y-axis
scat.restrict_y = True

Adding points to Scatter


In [ ]:
## Enabling adding the points to Scatter. Try clicking anywhere on the scatter to add points
with scat.hold_sync():
    scat.enable_move = False
    scat.interactions = {'click': 'add'}

Updating X and Y while moving the point


In [ ]:
## 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.interactions = {'click': None}

Custom event on end of drag


In [ ]:
## Whenever drag is ended, there is a custom event dispatched which can be listened to.
## try dragging a point and see the data associated with the event being printed
def test_func(self, content):
    print("received drag end", content)

scat.on_drag_end(test_func)

Adding tooltip and custom hover style


In [ ]:
x_data = x_data[:50]
y_data = y_data[:50]

fig = plt.figure()
def_tt = Tooltip(fields=['x', 'y'], formats=['', '.2f'])
scatter_chart = plt.scatter(x_data, y_data, colors=['dodgerblue'],
                            tooltip=def_tt, stroke='black',
                            unhovered_style={'opacity': 0.5})
fig

In [ ]:
## removing field names from the tooltip
def_tt.show_labels = False

In [ ]:
## changing the fields displayed in the tooltip
def_tt.fields = ['y']