Dynamically adjust axes in bqplot

Viewed 1721

I'm working on a jupyter based dashboard for data analysis and am planning on using bqplot for plotting the data. Part of the spec for the dashboard is to be able to adjust the axes to be able to zoom in/out on the data. So far I've been able to get this to update dynamically without needing to reload the figure entirely. Is there a way to to do this? If so, how? Below is a snippet of roughly what I mean:

def updateXAxis(values):
    #Update X-axis min/max value here

x_sc = LinearScale(min=float(x_data[0]))
y_sc = LinearScale()

ax_x = Axis(label='X', scale=x_sc, grid_lines='solid', tick_format='0f')
ax_y = Axis(label='Y', scale=y_sc, orientation='vertical', tick_format='0.2f')

m_fig = dict(left=100, top=50, bottom=50, right=100)
fig = Figure(axes=[ax_x, ax_y], marks=data_values, fig_margin=m_fig)

x_range = IntRangeSlider(value=[0,1000],
                        min=0,
                        max=2000,
                        step=1,
                        description="X Axis",
                        disabled=False,
                        continuous_update=False,
                        orientation='horizontal',
                        readout=True)
interactive(updateXAxis, values=x_range)
fig
2 Answers

The issue here ended up being that the interactive function is not very flexible. Instead observe should be used, below is an example:

def updateXAxis(values):
    if change['type'] == 'change' and change['name'] == 'value':
        x_sc.min = change['new'][0]
        x_sc.max = change['new'][1]

x_sc = LinearScale(min=float(x_data[0]))
y_sc = LinearScale()

ax_x = Axis(label='X', scale=x_sc, grid_lines='solid', tick_format='0f')
ax_y = Axis(label='Y', scale=y_sc, orientation='vertical', tick_format='0.2f')

m_fig = dict(left=100, top=50, bottom=50, right=100)
fig = Figure(axes=[ax_x, ax_y], marks=data_values, fig_margin=m_fig)

x_range = IntRangeSlider(value=[0,1000],
                        min=0,
                        max=2000,
                        step=1,
                        description="X Axis",
                        disabled=False,
                        continuous_update=False,
                        orientation='horizontal',
                        readout=True)

x_range.observe(updateXAxis)
widgets.VBox([fig, x_range])

There's a slightly more detailed answer to this at the git issue I filed here: https://github.com/bloomberg/bqplot/issues/712

There is an interact for panning and zooming charts in bqplot already built in, I don't think you need to construct your own interacts. Have a look at the examples in this notebook.

https://github.com/bloomberg/bqplot/blob/master/examples/Interactions/Interaction%20Layer.ipynb.

You need to add in an extra line to build the interaction. You can pass it one or two scales in the dictionary, I've restricted it to x here. Then pass the PanZoom object with the interaction kwarg when you create the Figure.

panzoom = PanZoom(scales={'x': [x_sc]})
fig = Figure(axes=[ax_x, ax_y], marks=[data_values], fig_margin=m_fig, interaction=panzoom)

Complete example:

from bqplot import *
from ipywidgets import *
import numpy as np

x_data = np.linspace(1,101)
y_data = np.linspace(1,101)
x_sc = LinearScale()
y_sc = LinearScale()

ax_x = Axis(label='X', scale=x_sc, grid_lines='solid', tick_format='0f')
ax_y = Axis(label='Y', scale=y_sc, orientation='vertical', tick_format='0.2f')

scatter = Scatter(x=x_data, y=y_data, scales={'x': x_sc, 'y': y_sc})

m_fig = dict(left=100, top=50, bottom=50, right=100)
panzoom = PanZoom(scales={'x': [x_sc]})
fig = Figure(axes=[ax_x, ax_y], marks=[scatter], fig_margin=m_fig, interaction=panzoom)

x_range = IntRangeSlider(value=[0,1000],
                        min=0,
                        max=2000,
                        step=1,
                        description="X Axis",
                        disabled=False,
                        continuous_update=False,
                        orientation='horizontal',
                        readout=True)

fig
Related