ipyvuetify#

ipyvuetify provides Jupyter widgets based on vuetify UI components and implementing Google’s Material Design with the Vue.js-Framework framework.

Installation#

$ pipenv install ipyvuetify
Installing ipyvuetify…
…
$ pipenv run jupyter nbextension enable --py --sys-prefix ipyvuetify
Enabling notebook extension jupyter-vuetify/extension...
      - Validating: OK

Examples#

Imports#

[1]:
import ipywidgets
import ipyvuetify as v
from threading import Timer

from traitlets import (Any, Unicode, List)

Buttons#

[3]:
v.Layout(children=[
    v.Btn(color='primary', children=['primary']),
    v.Btn(color='error', children=['error']),
    v.Btn(disabled=True, children=['disabled']),
    v.Btn(children=['reset']),
])
[4]:
v.Layout(children=[
    v.Btn(color='primary', flat=True, children=['flat']),
    v.Btn(color='primary', round=True, children=['round']),
    v.Btn(color='primary', flat=True, icon=True, children=[v.Icon(children=['thumb_up'])]),
    v.Btn(color='primary', outline=True, children=['outline']),
    v.Btn(color='primary', fab=True, large=True, children=[v.Icon(children=['edit'])]),
])
[5]:
def toggleLoading():
    button2.loading = not button2.loading
    button2.disabled = button2.loading

def on_loader_click(*args):
    toggleLoading()
    Timer(2.0, toggleLoading).start()

button2 = v.Btn(loading=False, children=['loader'])
button2.on_event('click', on_loader_click)

v.Layout(children=[button2])
[6]:
toggle_single = v.BtnToggle(v_model=2, class_='mr-3', children=[
    v.Btn(flat=True, children=[v.Icon(children=['format_align_left'])]),
    v.Btn(flat=True, children=[v.Icon(children=['format_align_center'])]),
    v.Btn(flat=True, children=[v.Icon(children=['format_align_right'])]),
    v.Btn(flat=True, children=[v.Icon(children=['format_align_justify'])]),
])

toggle_multi = v.BtnToggle(v_model=[0,2], multiple=True, children=[
    v.Btn(flat=True, children=[v.Icon(children=['format_bold'])]),
    v.Btn(flat=True, children=[v.Icon(children=['format_italic'])]),
    v.Btn(flat=True, children=[v.Icon(children=['format_underline'])]),
    v.Btn(flat=True, children=[v.Icon(children=['format_color_fill'])]),
])

v.Layout(children=[
    toggle_single,
    toggle_multi,
])
[7]:
v.Layout(children=[
    v.Btn(color='primary', children=[
        v.Icon(left=True, children=['fingerprint']),
        'Icon left'
    ]),
    v.Btn(color='primary', children=[
        'Icon right',
        v.Icon(right=True, children=['fingerprint']),
    ]),
    v.Tooltip(bottom=True, children=[
        v.Btn(slot='activator', color='primary', children=[
           'tooltip'
        ]),
        'Insert tooltip text here'
    ])
])
[8]:
lorum_ipsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'

v.Layout(children=[
    v.Dialog(width='500', v_slots=[{
        'name': 'activator',
        'variable': 'x',
        'children': v.Btn(v_on='x.on', color='success', dark=True, children=[
            'Open dialog'
        ]),
    }],
    children=[
        v.Card(children=[
            v.CardTitle(class_='headline gray lighten-2', primary_title=True, children=[
                "Lorem ipsum"]),
            v.CardText(children=[
                lorum_ipsum])
        ])
    ])
])

Slider#

[9]:
slider = v.Slider(v_model=25)
slider2 = v.Slider(thumb_label=True, v_model=25)
slider3 = v.Slider(thumb_label='always', v_model=25)

ipywidgets.jslink((slider, 'v_model'), (slider2, 'v_model'))

v.Container(children=[
    slider,
    slider2,
])

Tabs#

[10]:
tab_list = [v.Tab(children=['Tab ' + str(i)]) for i in range(1,4)]
content_list = [v.TabItem(children=[lorum_ipsum]) for i in range(1,4)]
tabs = v.Tabs(
    v_model=1,
    children=tab_list + content_list)
tabs

Accordion#

[11]:
vepc1 = v.ExpansionPanel(children=[
    v.ExpansionPanelHeader(children=['item1']),
    v.ExpansionPanelContent(children=['First Text'])])

vepc2 = v.ExpansionPanel(children=[
    v.ExpansionPanelHeader(children=['item2']),
    v.ExpansionPanelContent(children=['Second Text'])])

vep = v.ExpansionPanels(children=[vepc1, vepc2])
vl = v.Layout(class_='pa-4', children=[vep])
vl

You can search for all available components and attributes in the Vuetify documentation. Ipyvuetify is based on the syntax of Vue.js- and Vuetify, but there are also some differences:

Description

Vuetify

ipyvuetify

Component names are written in CamelCase and the v-prefix is removed

<v-list-tile …/>

ListTile(…)

Child components and text are defined in the child traitlet

<v-btn>text <v-icon …/></v-btn>

Btn(children=['text', Icon(…)])

Flag attributes require a Boolean value

<v-btn round

Btn(round=True

Attributes are snake_case

<v-menu offset-y

Menu(offset_y=True

The v_model attribute (value in ipywidgets) receives the value directly

<v-slider v-model="some_property"

Slider(v_model=25…

The scope of slot cannot currently be specified

<v-menu><template slot:activator="{ on }"><v-btn v-on=on>

Menu(children=[Btn(slot='activator',…), …]

Event listeners are defined with on_event

<v-btn @click='someMethod()'

def some_method (widget, event, data): mit button.on_event('click', some_method)

Regular HTML tags can be created with the Html class

<div>…</div>

Html(tag='div', children=[…])

An underscore must be added to the class and style attributes

<v-btn class="mr-3" style="…" >

Btn(class_='mr-3', style_='…')

VuetifyTemplate#

You can get a closer match with the Vue/Vuetify API with VuetifyTemplate. For this you create a subclass of VuetifyTemplate and define your own traitlets. The traitlets can be accessed via the template as if they were in a Vue model. Methods can be defined with the prefix vue_, e.g. def vue_button_click(self, data), which can then be called with @click="button_click(e)". In the following I show you a table with search, sorting and number of lines:

[12]:
import pandas as pd
import traitlets
import ipyvuetify as v
import json

class PandasDataFrame(v.VuetifyTemplate):
    """
    Vuetify DataTable rendering of a pandas DataFrame

    Args:
        data (DataFrame) - the data to render
        title (str) - optional title
    """

    headers = traitlets.List([]).tag(sync=True, allow_null=True)
    items = traitlets.List([]).tag(sync=True, allow_null=True)
    search = traitlets.Unicode('').tag(sync=True)
    title = traitlets.Unicode('DataFrame').tag(sync=True)
    index_col = traitlets.Unicode('').tag(sync=True)
    template = traitlets.Unicode('''
        <template>
          <v-card>
            <v-card-title>
              <span class="title font-weight-bold">{{ title }}</span>
              <v-spacer></v-spacer>
                <v-text-field
                    v-model="search"
                    append-icon="search"
                    label="Search ..."
                    single-line
                    hide-details
                ></v-text-field>
            </v-card-title>
            <v-data-table
                :headers="headers"
                :items="items"
                :search="search"
                :item-key="index_col"
                :rows-per-page-items="[25, 50, 250, 500]"
            >
                <template v-slot:no-data>
                  <v-alert :value="true" color="error" icon="warning">
                    Sorry, nothing to display here :(
                  </v-alert>
                </template>
                <template v-slot:no-results>
                    <v-alert :value="true" color="error" icon="warning">
                      Your search for "{{ search }}" found no results.
                    </v-alert>
                </template>
                <template v-slot:items="rows">
                  <td v-for="(element, label, index) in rows.item"
                      @click=cell_click(element)
                      >
                    {{ element }}
                  </td>
                </template>
            </v-data-table>
          </v-card>
        </template>
        ''').tag(sync=True)

    def __init__(self, *args,
                 data=pd.DataFrame(),
                 title=None,
                 **kwargs):
        super().__init__(*args, **kwargs)
        data = data.reset_index()
        self.index_col = data.columns[0]
        headers = [{
              "text": col,
              "value": col
            } for col in data.columns]
        headers[0].update({'align': 'left', 'sortable': True})
        self.headers = headers
        self.items = json.loads(
            data.to_json(orient='records'))
        if title is not None:
            self.title = title

iris = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
test = PandasDataFrame(data = iris, title='Iris')
test
[13]:
v.Banner(single_line=True,
    v_slots=[{
        'name': 'icon',
        'children': v.Icon(children=['thumb_up'])
    }, {
        'name': 'actions',
        'children': v.Btn(text=True, color='deep-purple accent-4', children=['Action'])
    }],
    children=['One line message text string with two actions on tablet / Desktop'])