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

ipyvolume: 3d bar chart

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

Following https://ipyvolume.readthedocs.io/en/latest/examples/bars.html we take a similar approach to create a 3d bar chart.

[1]:
import vaex
import numpy as np
import vaex.jupyter.model as vjm
[2]:
import ipyvolume as ipv
import bqplot

class IpyvolumeBarChart:
    def __init__(self, x_axis, y_axis):
        self.x_axis = x_axis
        self.y_axis = y_axis
        self.fig = ipv.figure()
        self.color_scale = bqplot.ColorScale(scheme='Reds', min=0, max=1)
        ipv.style.set_style_dark()
        ipv.style.box_off()
        ipv.style.use({'axes': {'y': {'visible': False}}})
        self.scatter = None

    def _scale_change(self, change):
        self.last1 = self.x_axis.max
        self.last2 = self.fig.scales['x'].max
        self.x_axis.min = self.fig.scales['x'].min
        self.x_axis.max = self.fig.scales['x'].max
        self.y_axis.min = self.fig.scales['z'].min
        self.y_axis.max = self.fig.scales['z'].max

    def __call__(self, da):
        ar = da.data
        assert ar.ndim == 2
        dim_x = da.dims[0]
        dim_y = da.dims[1]

        Nx, Ny = ar.shape
        x0, x1 = da.coords[dim_x].attrs['min'], da.coords[dim_x].attrs['max']
        y0, y1 = da.coords[dim_y].attrs['min'], da.coords[dim_y].attrs['max']
        x = np.linspace(x0, x1, Nx)
        y = np.linspace(y0, y1, Ny)

        X, Y = np.meshgrid(x, y, indexing='ij')
        xf = X.flatten()
        yf = Y.flatten()
        ar = np.log1p(ar)
        zf = ar.flatten().astype('f8')

        self.dx = dx = x[1] - x[0]
        self.dy = dy = y[1] - y[0]
        if self.scatter is None:
            with self.fig:
                self.scatter = ipv.scatter(xf, 0, yf, aux=zf,
                                           color=zf,
                                           marker="box",
                                           size=1,
                                           color_scale=self.color_scale,
                                           size_x_scale=self.fig.scales['x'],
                                           size_y_scale=self.fig.scales['y'],
                                           size_z_scale=self.fig.scales['z'])
            self.scatter.shader_snippets = {'size': 'size_vector.y = SCALE_SIZE_Y(aux_current) - SCALE_SIZE_Y(0.0) ; '}
            # since we see the boxes with negative sizes inside out, we made the material double sided
            self.scatter.material.side = "DoubleSide"
            ipv.xlim(x0, x1)
            ipv.zlim(y0, y1)
            # only start observing now that the limits have been set to avoid an initial re-gridding
            for scale in [self.fig.scales['x'], self.fig.scales['z']]:
                scale.observe(self._scale_change, ['min', 'max'])
        else:
            with self.scatter.hold_sync():
                self.scatter.x = xf
                self.scatter.z = yf
                self.scatter.aux = zf
                self.scatter.color = zf
        # we patch holes by making the boxes larger
        patch = 1.05
        self.scatter.geo_matrix = [dx*patch, 0, 0, 0,   0, 1, 0, 0,   0, 0, dy*patch, 0,  0.0, 0.5, 0, 1]
        self.color_scale.max = zf.max().item()
        with self.fig:
            # make the x and z lim half a 'box' larger
            ipv.xlim(x0, x1)
            ipv.zlim(y0, y1)
            ipv.ylim(0, zf.max() * 1.2)
            ipv.xlabel(dim_x)
            ipv.zlabel(dim_y)
            ipv.ylabel('counts')
# barchart3d = IpyvolumeBarChart(x_axis, y_axis)

[3]:
# x_limits, y_limits = limits = df.limits([df.pickup_longitude, df.pickup_latitude], '95%')

# pre calculated values:
x_limits, y_limits = [-74.37857997, -73.53860359], [40.49456025, 40.91851631]

[4]:
# Data is hosted on S3
# df = vaex.open('s3://vaex/taxi/yellow_taxi_2009_2015_f32.hdf5?anon=true')[:800_000_000]

# Or use the Vaex DataFrame server to do the computations!
df = vaex.open('wss://dataframe.vaex.io/yellow_taxi_2009_2015_f32')

x_axis = vjm.Axis(df=df, expression=df.pickup_longitude, min=x_limits[0], max=x_limits[1])
y_axis = vjm.Axis(df=df, expression=df.pickup_latitude, min=y_limits[0], max=y_limits[1])

barchart3dtaxi = IpyvolumeBarChart(x_axis, y_axis)

# we use `barchart3d` as a callable function
da_view = df.widget.data_array(axes=[x_axis, y_axis], display_function=barchart3dtaxi, shape=400)

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

# and the figure widget, display(barchart3d.fig) would also have worked
with barchart3dtaxi.fig:
    ipv.show()

[5]:
await vaex.jupyter.gather()

Voila-vuetify setup

[6]:
import traitlets
import ipywidgets as widgets
import ipyvuetify as v
from vaex.jupyter.widgets import ContainerCard, Html, LinkList, VuetifyTemplate

[7]:
class SchemeTemplate(VuetifyTemplate):
    value = traitlets.Unicode('Reds').tag(sync=True)
    @traitlets.default('template')
    def _template(self):
         return """
    <v-btn-toggle v-model="value">
      <v-btn :value="'Reds'" text >
          <v-icon color="red">mdi-palette</v-icon>
      </v-btn>
      <v-btn :value="'Blues'" text>
          <v-icon color="blue">mdi-palette</v-icon>
      </v-btn>
    </v-btn-toggle>sdd
        """
scheme_widget = SchemeTemplate()
widgets.jslink((scheme_widget, 'value'), (barchart3dtaxi.color_scale, 'scheme'))
scheme_widget
[8]:
card_widget = ContainerCard(title=f'{len(df):,} Taxi pickup locations',
                            subtitle="using vaex-jupyter",
                            main=barchart3dtaxi.fig,
                            controls=[scheme_widget],
                            show_controls=True,
                            card_props={'style': 'width: 520px;', 'class': 'pa-2 ma-4'},
                            _metadata={'mount_id': 'content-main'},
                            text='<i>Hold the control key to zoom in and out</i>'
                           )
[9]:
# You do not have to render the widget for it to show up in voila-vuetify
card_widget
[11]:
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': 'ipyvolume', 'url': 'https://github.com/maartenbreddels/ipyvolume', 'img': 'https://raw.githubusercontent.com/maartenbreddels/ipyvolume/master/misc/icon.svg'},
     {'title': 'Voila (dashboard)', 'url': 'https://github.com/voila-dashboards/voila', 'icon': 'dashboard'},
     {'title': 'jupyter widgets', 'url': 'https://github.com/jupyter-widgets/ipywidgets', 'icon': 'widgets'},
    ], _metadata={'mount_id': 'content-nav'})
[15]:
v.theme.dark = True
[16]:
Html(tag='span',
     children=['New york taxi dataset with ipyvolume'],
     _metadata={'mount_id': 'content-bar'});

Html(tag='span',
     children=['Resources'],
     _metadata={'mount_id': 'content-title'});

screenshot