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]:
from threading import Timer

import ipyvuetify as v
import ipywidgets

from traitlets import Any, List, Unicode

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]:
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",
            ],
        ),
    ]
)

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]:
lorum_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
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_, for example 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 json

import ipyvuetify as v
import pandas as pd
import traitlets


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"
    ],
)