Maarten Breddels

Motivation

Glue Jupyter

  • Glue in the notebook
  • Comes from Qt -> GUI Challenges for ipywidgets

In [ ]:
import glue_jupyter as gj
import ipywidgets
import ipywidgets as widgets

In [ ]:
data = gj.example_data_xyz()
app = gj.jglue(data=data)

In [ ]:
app.histogram1d();

Oliver Borderies - SocGen

  • Olivier: I want to put widget into a modern component pages (Vue)
  • Me: I want more of these React based MaterialUI widgets
  • Olivier: but Vue is better
  • Me: But React is more popular
  • Me & Olivier: lets autogen MaterialUI & Vuetify widgets
  • Mario: I can make it!
  • QuantStack project

Plan

  • Wrap both
    • MaterialUI (React based)
    • Vuetify (Vue based)
  • Both are Material Design component libraries
  • All code is autogenerated
    • ipyvuetify
    • xvuetify?
    • jlvuetify?
    • jvuetify
  • Enable modern Single Page Applications (SPA) with widget support.
    • With kernel (voila)
    • Without kernel, plain html (nbconvert?)
    • (for free it renders on mobile)

ipymaterialui

  • $ pip install ipymaterialui
  • Wraps MaterialUI
    • React based
    • Material Design
  • ~15 widgets manually wrapped
  • Mario is working on wrapping it all
  • (future: ipyreact + cookiecutter/manual how to wrap new/existing React components)

In [ ]:
import ipymaterialui as mui

In [ ]:
text1 = "Jupyter"
text2 = "Jupyter Widgets"
text3 = "Material UI"
text4 = "React"
texts = [text1, text2, text3, text4]

In [ ]:
# the baseclass is just a 
chips = [mui.Chip(label=text) for text in texts]
chips_div = mui.Div(children=chips)
chips_div

In [ ]:
# Nice looking lists, the 3rd acting like a button
list_items = [
    mui.ListItem(children=[mui.ListItemText(primary=text1, secondary=text3)], divider=True),
    mui.ListItem(children=[mui.ListItemText(primary=text2, secondary=text4)], divider=True),
    mui.ListItem(children=[mui.ListItemText(primary=text3, secondary=text1)], divider=True, button=True),
    mui.ListItem(children=[mui.ListItemText(primary=text4, secondary=text2)], divider=True)
]
mui.List(children=list_items)

In [ ]:
# For the moment only list items can be used for popup menus
# This needs a more generic solution?
menuitems = [
    mui.MenuItem(description=text1, value='1'),
    mui.MenuItem(description=text2, value='2'),
    mui.MenuItem(description=text3, value='3')
]
menu = mui.Menu(children=menuitems)
list_item_text = mui.ListItemText(primary=text4, secondary=text1, button=True)
list_item = mui.ListItem(children=[list_item_text], button=True, menu=menu)
list_item

Sure nice, but Olivier wants Vue(tify)

Ipyvuetify

  • $ pip install ipyvuetify
  • QuantStack/SocGen project (Olivier Borderier)
  • Made by Mario Buikhuizen
  • Wraps Vuetify
    • Vue based
    • Material Design

In [ ]:
import ipyvuetify as v
import ipywidgets as widgets
from threading import Timer
lorum_ipsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'

In [ ]:
v.Layout(children=[
    v.Btn(color='primary', children=['primary']),
    v.Btn(color='error', children=['error']),
    v.Btn(color='pink lighten-4', children=['custom']),
    v.Btn(color='#654321', dark=True, children=['hex']),
    v.Btn(color='#654321', disabled=True, children=['disabled']),

])

In [ ]:
v.Layout(children=[
    v.Btn(color='primary', flat=True, children=['flat']),
    v.Btn(color='primary', flat=True, disabled=True, children=['flat']),
    v.Btn(color='primary', round=True, children=['round']),
    v.Btn(color='primary', round=True, disabled=True, children=['round']),
    v.Btn(color='primary', depressed=True, children=['depressed']),
    v.Btn(color='primary', flat=True, icon=True, children=[v.Icon(children=['thumb_up'])]),
    v.Btn(color='primary', outline=True, children=['outline']),
])

In [ ]:
v.Layout(children=[
    v.Btn(color='primary', small=True, children=['small']),
    v.Btn(color='primary', children=['normal']),
    v.Btn(color='primary', large=True, children=['large']),
    v.Btn(color='primary', small=True, fab=True, children=[v.Icon(children=['edit'])]),
    v.Btn(color='primary', fab=True, children=[v.Icon(children=['edit'])]),
    v.Btn(color='primary', fab=True, large=True, children=[v.Icon(children=['edit'])]),
])

In [ ]:
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])

In [ ]:
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(pa_1=True, children=[
    toggle_single,
    toggle_multi,
])

In [ ]:
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'
    ])    
])

In [ ]:
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.ListTile(children=[
    v.ListTileTitle(children=[
        f'Click me {i}'])]) 
         for i in range(1, 5)]

for item in items:
    item.on_event('click', on_menu_click)

menu = v.Menu(offset_y=True, children=[
    v.Btn(slot='activator', color='primary', children=[
        'menu', 
        v.Icon(right=True, children=[
            'arrow_drop_down'
        ])
    ]),
    v.List(children=items)
])

info = v.Chip()

layout = v.Layout(children=[
    menu
])
layout

In [ ]:
v.Dialog(v_model=False, width='500', children=[
        v.Btn(slot="activator", color='success', dark=True, children=[
            "Open dialog"
        ]),
        v.Card(children=[
            v.CardTitle(class_='headline gray lighten-2', primary_title=True, children=[
                "Lorem ipsum"]),
            v.CardText(children=[
                lorum_ipsum])
        ])
    ])

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

widgets.jslink((slider, 'v_model'), (slider2, 'v_model'))
widgets.jslink((slider, 'v_model'), (slider3, 'v_model'))

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

In [ ]:
select1=v.Select(label="Choose option", items=['Option a', 'Option b', 'Option c'])
v.Layout(children=[select1])

In [ ]:
tab_list = [v.Tab(children=[f'Tab {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

In [ ]:
vepc1 = v.ExpansionPanelContent(children=[
    v.Html(tag='div', slot='header', children=['item1']),
    v.Card(children=[
        v.CardText(children=['First Text'])])])

vepc2 = v.ExpansionPanelContent(children=[
    v.Html(tag='div', slot='header', children=['item2']),
    v.Card(children=[
        v.CardText(children=['Second Text'])])])

vep = v.ExpansionPanel(children=[vepc1, vepc2])
vl = v.Layout(children=[vep])
vl

In [ ]:
import ipyvuetify as v

from traitlets import (Unicode, List, Bool, Any)

class MyApp(v.VuetifyTemplate):
    dark = Bool(True).tag(sync=True)
    drawers = Any(['Default (no property)', 'Permanent', 'Temporary']).tag(sync=True)
    model = Any(None).tag(sync=True)
    type = Unicode('default (no property)').tag(sync=True)
    clipped = Bool(False).tag(sync=True)
    floating = Bool(True).tag(sync=True)
    mini = Bool(False).tag(sync=True)
    inset = Bool(False).tag(sync=True)
    
    template = Unicode('''
        <template>
  <v-app id="sandbox" :dark="dark">
    <v-navigation-drawer
      v-model="model"
      :permanent="type === 'permanent'"
      :temporary="type === 'temporary'"
      :clipped="clipped"
      :floating="floating"
      :mini-variant="mini"
      absolute
      overflow
      app
    >
    </v-navigation-drawer>
    <v-toolbar :clipped-left="clipped" app absolute>
      <v-toolbar-side-icon
        v-if="type !== 'permanent'"
        @click.stop="model = !model"
      ></v-toolbar-side-icon>
      <v-toolbar-title>Vuetify</v-toolbar-title>
    </v-toolbar>
    <v-content>
      <v-container fluid>
        <v-layout align-center justify-center>
          <v-flex xs10>
            <v-card>
              <v-card-text>
                <v-layout row wrap>
                  <v-flex xs12 md6>
                    <span>Scheme</span>
                    <v-switch v-model="dark" primary label="Dark"></v-switch>
                  </v-flex>
                  <v-flex xs12 md6>
                    <span>Drawer</span>
                    <v-radio-group v-model="type" column>
                      <v-radio
                        v-for="drawer in drawers"
                        :key="drawer"
                        :label="drawer"
                        :value="drawer.toLowerCase()"
                        primary
                      ></v-radio>
                    </v-radio-group>
                    <v-switch v-model="clipped" label="Clipped" primary></v-switch>
                    <v-switch v-model="floating" label="Floating" primary></v-switch>
                    <v-switch v-model="mini" label="Mini" primary></v-switch>
                  </v-flex>
                  <v-flex xs12 md6>
                    <span>Footer</span>
                    <v-switch v-model="inset" label="Inset" primary></v-switch>
                  </v-flex>
                </v-layout>
              </v-card-text>
              <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn flat>Cancel</v-btn>
                <v-btn flat color="primary">Submit</v-btn>
              </v-card-actions>
            </v-card>
          </v-flex>
        </v-layout>
      </v-container>
    </v-content>
    <v-footer :inset="inset" app>
      <span class="px-3">&copy; {{ new Date().getFullYear() }}</span>
    </v-footer>
  </v-app>
</template>''').tag(sync=True)
    
    
    def vue_menu_click(self, data):
        self.color = self.items[data]
        self.button_text = self.items[data]
    
    
app = MyApp()
app

In [ ]:
app.inset = True

In [ ]:
app.dark = True

In [ ]:
app.type = 'permanent'

core ipywidgets vs ipyvuetify

  • Composible vs verbosity

In [ ]:
options = ['pepperoni', 'pineapple', 'anchovies']

In [ ]:
v.RadioGroup(children=[v.Radio(label=k, value=k) for k in options], v_model=options[0])

In [ ]:
widgets.RadioButtons(options=options, value=options[0], description='Pizza topping:')

In [ ]:
v.Btn(color='primary', children=[
    v.Icon(left=True, children=['fingerprint']),
    'Icon left'
])

In [ ]:
widgets.Button(color='primary', description='icon left', icon='home')

In [ ]:
menu = v.Menu(offset_y=True, children=[
    v.Btn(slot='activator', color='primary', children=[
        'menu', 
        v.Icon(right=True, chi ldren=[
            'arrow_drop_down'
        ])
    ]),
    v.List(children=items)
])
menu

In [ ]: