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)
Menu#
[2]:
def on_menu_click(widget, event, data):
if len(layout.children) == 1:
layout.children = layout.children + [info]
info.children=[f'Item {items.index(widget)+1} clicked']
items = [v.ListItem(children=[
v.ListItemTitle(children=[
f'Item {i}'])])
for i in range(1, 5)]
for item in items:
item.on_event('click', on_menu_click)
menu = v.Menu(offset_y=True,
v_slots=[{
'name': 'activator',
'variable': 'menuData',
'children': v.Btn(v_on='menuData.on', class_='ma-2', color='primary', children=[
'menu',
v.Icon(right=True, children=[
'arrow_drop_down'
])
]),
}]
,
children=[
v.List(children=items)
]
)
info = v.Chip(class_='ma-2')
layout = v.Layout(children=[
menu
])
layout
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 |
|
|
Child components and text are defined in the child traitlet |
|
|
Flag attributes require a Boolean value |
|
|
Attributes are snake_case |
|
|
The |
|
|
The scope of |
|
|
Event listeners are defined with |
|
|
Regular HTML tags can be created with the |
|
|
An underscore must be added to the |
|
|
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'])