Warning: This notebook needs a running kernel to be fully interactive, please run it locally or run it on mybinder.

Binder

Dashboard: Or get a dashboard by rendering this notebook with Voila:

voila

A Plotly heatmap

Make sure you go through the Vaex-jupyter tutorial first.

The easiest way to create your own visualizations is to follow a similar approach as described in the Vaex-jupyter tutorial where we used matplotlib to create the figures. When using plotly however, we can first construct the widgets, and at each callback update the relevant components. This is much more efficient than creating an entirely new widget on each update.

To solve this two step process (initialization and updating), we write a wrapper class that implement the dunder call method, such that it acts as a callable (like a function).

[1]:
import vaex
import numpy as np
import vaex.jupyter.model as vjm
import matplotlib.pyplot as plt

# Fetch a dataset
df = vaex.datasets.helmi_de_zeeuw.fetch()
[2]:
# Define the axes
extend = 50
x_axis = vjm.Axis(df=df, expression=df.x, shape=100, min=-extend, max=extend)
y_axis = vjm.Axis(df=df, expression=df.y, shape=140, min=-extend, max=extend)
# in this case we need to know the min and max directly
await vaex.jupyter.gather()
[3]:
import plotly.graph_objs as go

class PlotlyHeatmap:
    def __init__(self, x_axis, y_axis, figure_height=500, figure_width=400, title="Hi vaex, hi plotly"):
        self.x_axis = x_axis
        self.y_axis = y_axis
        self.heatmap = go.Heatmap()
        self.layout = go.Layout(height=figure_height,
                                width=figure_width,
                                title=title,
                                xaxis=go.layout.XAxis(title=str(x_axis.expression),
                                                      range=[x_axis.min, x_axis.max]
                                                     ),
                                yaxis=go.layout.YAxis(title=str(y_axis.expression),
                                                      range=[y_axis.min, y_axis.max]
                                                     )
                               )
        self.fig = go.FigureWidget(data=[self.heatmap], layout=self.layout)
        # we respond to zoom/pan
        self.fig.layout.on_change(self._pan_and_zoom, 'xaxis.range', 'yaxis.range')

    def _pan_and_zoom(self, layout, xrange, yrange):
        self.x_axis.min, self.x_axis.max = xrange
        self.y_axis.min, self.y_axis.max = yrange

    def __call__(self, data_array):
        ar = data_array.data  # take the numpy array data
        assert data_array.ndim == 2
        dim_x = data_array.dims[0]
        dim_y = data_array.dims[1]
        x0, x1 = data_array.coords[dim_x].attrs['min'], data_array.coords[dim_x].attrs['max']
        y0, y1 = data_array.coords[dim_y].attrs['min'], data_array.coords[dim_y].attrs['max']
        dx = (x1 - x0)/data_array.shape[0]
        dy = (y1 - y0)/data_array.shape[1]

        z = np.log1p(ar).T
        self.fig.update_traces(dict(z=z, x0=x0, y0=y0, dx=dx, dy=dy))
        heatmap_plotly.fig.update_layout(
            xaxis=go.layout.XAxis(title=dim_x, range=[x0, x1]),
            yaxis=go.layout.YAxis(title=dim_y, range=[y0, y1])
        )


heatmap_plotly = PlotlyHeatmap(x_axis, y_axis)
[4]:
# we use `heatmap_plotly` as a callable function
da_view = df.widget.data_array(axes=[x_axis, y_axis], display_function=heatmap_plotly)

# we display the progress bar and possible output (stack traces)
display(da_view)

# and the plotly figure widget
display(heatmap_plotly.fig)

We can also create expression widgets to directly edit the axis on the figure above

[5]:
x_widget = df.widget.expression(x_axis)
y_widget = df.widget.expression(y_axis)
display(x_widget)
display(y_widget)

Using ipyvuetify we can create pretty buttons and assign them some functionality:

[6]:
import ipyvuetify as v

# A button to reset the figure ot its initial state
button_reset = v.Btn(children=['reset'])

def reset(*ignore_arguments):
    x_axis.expression = df.x
    y_axis.expression = df.y
button_reset.on_event('click', reset)

# A button that presents a specific figure
button_fireball = v.Btn(children=['fireball'])

def fireball(*ignore_arguments):
    x_axis.expression = np.log(df.x**2)
    y_axis.expression = df.y
button_fireball.on_event('click', fireball)

preset_widget = v.Col(children=[button_reset, button_fireball])
preset_widget

Voila vuetify setup

We can more elegantly present the visualisations created in this notebook using Voila.

[7]:
from vaex.jupyter.widgets import ContainerCard, Html, LinkList
[9]:
LinkList(items=
    [{'title': 'Vaex', 'url': 'https://vaex.io', 'img': 'https://vaex.io/img/logos/logo-grey.svg', },
     {'title': 'Vaex on GitHub', 'url': 'https://github.com/vaexio/vaex', 'img': 'https://github.githubassets.com/pinned-octocat.svg'},
     {'title': 'Vaex DataFrame server', 'url': 'http://dataframe.vaex.io/', 'icon': 'mdi-database'},
     {'title': 'Voila (dashboard)', 'url': 'https://github.com/voila-dashboards/voila', 'icon': 'dashboard'},
     {'title': 'Plotly', 'url': 'https://plotly.com/', 'img': 'https://plotly.com/img/favicon.ico'},
    ], _metadata={'mount_id': 'content-nav'})
[10]:
card_widget = ContainerCard(title=f'{len(df):,} Simulated stars',
                            subtitle="using vaex-jupyter",
                            main=heatmap_plotly.fig,
                            controls=[x_widget, y_widget, preset_widget],
                            show_controls=True,
                            card_props={'style': 'width: 420px;', 'class': 'pa-2 ma-4'},
                            _metadata={'mount_id': 'content-main'}
                           )
[11]:
# You do not have to render the widget for it to show up in voila-vuetify
card_widget
[12]:
Html(tag='span',
     children=['Simulated stars'],
     _metadata={'mount_id': 'content-bar'})
Html(tag='span',
     children=['Resources'],
     _metadata={'mount_id': 'content-title'});

screenshot