Selectors


In [ ]:
import pandas as pd
import numpy as np

symbol = 'Security 1'
symbol2 = 'Security 2'

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

dates_actual = price_data.index.values
prices = price_data[symbol].values

In [ ]:
from bqplot import *
from bqplot.interacts import (
    FastIntervalSelector, IndexSelector, BrushIntervalSelector,
    BrushSelector, MultiSelector, LassoSelector,
)

from ipywidgets import ToggleButtons, VBox, HTML

Introduction

Selectors are part of the Interaction Layer (link). They are used to select subparts of Marks, that correspond to different regions on the Figure canvas. Different types of selectors select different types of regions:

  • BrushSelector, FastIntervalSelector and MultiSelector select rectangular regions
  • IndexSelector selects the elements closest to an abcissa
  • LassoSelector selects elements in a region drawn by the user

How they work

bqplot Selectors need to be tied to two other widgets:

  • One or several marks. Their selected attribute, a list of data indices, will be set by the Selector instance.
  • One (1d selection) or two (2d selection) Scales. These are the scales that the Selector operates on. The Selector's selected attribute will be expressed as values of those scales.

The Selector must then be passed to the desired Figure, as its interaction attribute.

Hopefully this will be clear in the following examples.


In [ ]:
# Define scales for the rest of the notebook
scales = {'x': DateScale(), 'y': LinearScale()}

Brush Selectors

Selects a rectangular region of the Figure.

Usage:

  • Click and drag to create a new brush
  • Drag the edge of the brush to change its width
  • Drag the inside of the brush to translate it
  • Clicking and dragging outside of the brush deletes it and creates a new one.

In [ ]:
# The Mark we want to select subsamples of
scatter = Scatter(x=dates_actual, y=prices, scales=scales, colors=['orange'],
                 selected_style={'opacity': '1'}, unselected_style={'opacity': '0.2'})
# Create the brush selector, passing it its corresponding scale.
# Notice that we do not pass it any marks for now
brushintsel = BrushIntervalSelector(scale=scales['x'])

x_ax = Axis(label='Index', scale=scales['x'])
x_ay = Axis(label=(symbol + ' Price'), scale=scales['y'], orientation='vertical')
# Pass the Selector instance to the Figure
fig = Figure(marks=[scatter], axes=[x_ax, x_ay],
             title='''Brush Interval Selector Example. Click and drag on the Figure to action.''',
             interaction=brushintsel)

# The following text widgets are used to display the `selected` attributes
text_brush = HTML()
text_scatter = HTML()

# This function updates the text, triggered by a change in the selector
def update_brush_text(*args):
    text_brush.value = "The Brush's selected attribute is {}".format(brushintsel.selected)
def update_scatter_text(*args):
    text_scatter.value = "The scatter's selected indices are {}".format(scatter.selected)
brushintsel.observe(update_brush_text, 'selected')
scatter.observe(update_scatter_text, 'selected')

update_brush_text()
update_scatter_text()

# Display
VBox([fig, text_brush, text_scatter])

Linking the brush to the scatter

Passing a mark (or several) to the selector, will link the mark's selected indices to the selector.


In [ ]:
brushintsel.marks = [scatter]

From now on we will stop printing out the selected indices, but rather use the selected_style and unselected_style attributes of the Marks to check which elements are selected.


In [ ]:
def create_figure(selector, **selector_kwargs):
    '''
    Returns a Figure with a Scatter and a Selector.
    
    Arguments
    ---------
    selector: The type of Selector, one of
        {'BrushIntervalSelector', 'BrushSelector', 'FastIntervalSelector', 'IndexSelector', 'LassoSelector'}
    selector_kwargs: Arguments to be passed to the Selector
    '''
    scatter = Scatter(x=dates_actual, y=prices, scales=scales, colors=['orange'],
                      selected_style={'opacity': '1'}, unselected_style={'opacity': '0.2'})
    sel = selector(marks=[scatter], **selector_kwargs)
    
    text_brush = HTML()
    if selector != LassoSelector:
        def update_text(*args):
            text_brush.value = '{}.selected = {}'.format(selector.__name__, sel.selected)
        sel.observe(update_text, 'selected')
        update_text()

    x_ax = Axis(label='Index', scale=scales['x'])
    x_ay = Axis(label=(symbol + ' Price'), scale=scales['y'], orientation='vertical')
    fig = Figure(marks=[scatter], axes=[x_ax, x_ay], title='{} Example'.format(selector.__name__),
                 interaction=sel)
    return VBox([fig, text_brush])

BrushIntervalSelector on the y-axis

The attribute orientation can be set to 'vertical' to select on the y-axis. Be careful to pass the corresponding y-scale.


In [ ]:
create_figure(BrushIntervalSelector, orientation='vertical', scale=scales['y'])

2d BrushSelector

The BrushSelector is 2d, and must be fed 2 scales, x_scale and y_scale.

Note that BrushSelector.selected is now 2x2. It is the coordinates of the lower left-hand and upper right-hand corners of the rectangle.


In [ ]:
create_figure(BrushSelector, x_scale=scales['x'], y_scale=scales['y'])

FastIntervalSelector

The FastIntervalSelector is functionally like a BrushIntervalSelector, but provides a more fluid and rapid interaction.

Usage:

  • The first click creates the selector.
  • Moving the mouse up and down widens and narrows the interval width.
  • Moving the mouse left and right translates the interval left and right.
  • Subsequent clicks will freeze/unfreeze the interval width
  • A double-click will freeze both the width and the translation

Experiment and get a feel for it in the example below.


In [ ]:
create_figure(FastIntervalSelector, scale=scales['x'])

As of the latest version, FastIntervalSelector is only supported for 1d interaction along the x-axis

LassoSelector

This 2-D selector enables the user to select multiple sets of data points by drawing lassos on the figure.

Usage:

  • Click and drag to draw a new lasso
  • Click a lasso to select (de-select) it. Mult
  • Press the 'Delete' button to delete the selected lassos

In [ ]:
create_figure(LassoSelector)

IndexSelector

This 1-D selector selects a unique value on its scale. The attached Mark's selected element is the closest element to that value.

Usage:

  • First click creates and activates the selector
  • Moving the mouse translates the selector
  • Subsequent clicks freeze/unfreeze the selector

In [ ]:
create_figure(IndexSelector, scale=scales['x'])

As of the latest version, IndexSelector is only supported for interaction along the x-axis.

MultiSelector

This 1-D selector is equivalent to multiple brush selectors.

Usage:

  • The first brush works like a regular brush.
  • Ctrl + click creates a new brush, which works like the regular brush.
  • The active brush has a Green border while all the inactive brushes have a Red border.
  • Shift + click deactivates the current active brush. Now, click on any inactive brush to make it active.
  • Ctrl + Shift + click clears and resets all the brushes.

Each brush has a name (0, 1, 2, ... by default), and the selected attribute is a dict {brush_name: brush_extent}


In [ ]:
create_figure(MultiSelector, scale=scales['x'])