99pi

pyconar

¿Cómo funcionan los Widgets de Jupyter?¶

  • ¿Qué es un Widget?¶

  • ¿Cómo funciona un ipywidget?¶

  • ¿Qué tengo que tener en cuenta al implementar uno?¶

¿Qué es un Widget?¶

ferreteria

Y por qué deberían interesarme los widgets?¶

ipycanvas

ipyleaflet

pythreejs

ipyvolume

ipywebrtc

binary_star

tecla

Advertencia!!!¶

benito_y_charly

¿Cómo funciona un ipywidget?¶

Empecemos con un objeto basico y vemos la representacion

In [1]:
class Cosito:
    
    def __init__(self, nombre):
        self.nombre = nombre
    
ruflete = Cosito('ruflete')    
print(ruflete)
<__main__.Cosito object at 0x000002664553B920>

print_y_repr

In [2]:
class Cosito:
    
    def __init__(self, nombre):
        self.nombre = nombre
    
    def __str__(self):
        return self.nombre
    
    def __repr__(self):
        return f'Cosito("{self.nombre}")'
    
ruflete = Cosito('ruflete')    
print('Esto es str:', ruflete)
print('Esto es repr:',repr(ruflete))
Esto es str: ruflete
Esto es repr: Cosito("ruflete")

lil_mikela

In [3]:
class Cosito:
    
    html_template = '<i class="fa fa-hand-spock-o" style="font-size:48px;color:red">{nombre}</i>'
    
    def __init__(self, nombre):
        self.nombre = nombre
    
    def __str__(self):
        return self.nombre
    
    def __repr__(self):
        return f'Cosito("{self.nombre}")'
    
    def _repr_html_(self):
        return self.html_template.format(nombre=self.nombre)

ruflete = Cosito('ruflete')    
print('Esto es str:', ruflete)
print('Esto es repr:',repr(ruflete))
ruflete
Esto es str: ruflete
Esto es repr: Cosito("ruflete")
Out[3]:
ruflete
In [4]:
from ipywidgets import HTML, VBox, Image, IntSlider, link
from IPython.display import display
In [5]:
class Cosito:
    
    html_template = '<i class="fa fa-hand-spock-o" style="font-size:48px;color:red">{nombre}</i>'
    
    def __init__(self, nombre):
        self.nombre = nombre
    
    def __str__(self):
        return self.nombre
    
    def __repr__(self):
        return f'Cosito("{self.nombre}")'
    
    def _ipython_display_(self):
        html = HTML(self.html_template.format(nombre=self.nombre))
        with open('imagenes/ruflete.jpg','rb') as img:
            imagen_data = img.read()
        slider = IntSlider(min=100,max=300)
        imagen = Image(value=imagen_data,height=200,width=300)
        link((imagen,'width'),(slider,'value'))
        display(VBox([html,imagen,slider]))
In [6]:
ruflete = Cosito('ruflete')    
print('Esto es str:', ruflete)
print('Esto es repr:',repr(ruflete))
ruflete
Esto es str: ruflete
Esto es repr: Cosito("ruflete")
VBox(children=(HTML(value='<i class="fa fa-hand-spock-o" style="font-size:48px;color:red">ruflete</i>'), Image…

angustia

In [7]:
from traitlets import Unicode, Int
from ipywidgets import Widget

class Cosito(Widget):
    
    nombre  = Unicode('cosito').tag(sync=True)
    tamanio = Int(15).tag(sync=True, metadata={'marca':'tres chanchitos'})
    
ruflete = Cosito()
ruflete
Out[7]:
Cosito()

Mencionar los traitlets

lo_keh

descriptors

lo_keh

In [8]:
def llamado(cambio):
    print('Ring ring!')

ruflete.observe(llamado)
ruflete.nombre = 'ruflete'
Ring ring!

lo_keh

Estructura del evento¶

def llamado(cambio):
    print(cambio)
    
cambio = {  'owner' : Cosito(name='ruflete'),       #'la instancia de un objeto HasTraits (traitlets)'
            'old'   : 'cosito', # valor viejo del atributo modificado
            'new'   : 'ruflete',# valor nuevo del atributo modificado
            'name'  : 'nombre'  # nombre del atributo que fue modificado'
            'type'  : 'change'  # tipo del evento observado
         }

siempre_me_decis_lo_que_tengo_que_hacer

In [9]:
rosca = Cosito(nombre='rosca')

def hace_esto(cambio):
    rosca.tamanio -=  cambio['new']
    
ruflete.observe(hace_esto,names='tamanio')

Hay veces que los efectos de los callbacks quedan ocultos

espero

Output widget para capturar la salida de un llamado¶

In [10]:
def intentar_encastrar(cambio):
    raise ValueError('No deberías hacer eso')
    
ruflete.observe(intentar_encastrar)
ruflete.tamanio = 0
ruflete
Ring ring!
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[10], line 5
      2     raise ValueError('No deberías hacer eso')
      4 ruflete.observe(intentar_encastrar)
----> 5 ruflete.tamanio = 0
      6 ruflete

File ~\dev\gh\akielbowicz\presentations\.venv\Lib\site-packages\traitlets\traitlets.py:716, in TraitType.__set__(self, obj, value)
    714 if self.read_only:
    715     raise TraitError('The "%s" trait is read-only.' % self.name)
--> 716 self.set(obj, value)

File ~\dev\gh\akielbowicz\presentations\.venv\Lib\site-packages\traitlets\traitlets.py:706, in TraitType.set(self, obj, value)
    702     silent = False
    703 if silent is not True:
    704     # we explicitly compare silent to True just in case the equality
    705     # comparison above returns something other than True/False
--> 706     obj._notify_trait(self.name, old_value, new_value)

File ~\dev\gh\akielbowicz\presentations\.venv\Lib\site-packages\traitlets\traitlets.py:1513, in HasTraits._notify_trait(self, name, old_value, new_value)
   1512 def _notify_trait(self, name: str, old_value: t.Any, new_value: t.Any) -> None:
-> 1513     self.notify_change(
   1514         Bunch(
   1515             name=name,
   1516             old=old_value,
   1517             new=new_value,
   1518             owner=self,
   1519             type="change",
   1520         )
   1521     )

File ~\dev\gh\akielbowicz\presentations\.venv\Lib\site-packages\ipywidgets\widgets\widget.py:701, in Widget.notify_change(self, change)
    698     if name in self.keys and self._should_send_property(name, getattr(self, name)):
    699         # Send new state to front-end
    700         self.send_state(key=name)
--> 701 super().notify_change(change)

File ~\dev\gh\akielbowicz\presentations\.venv\Lib\site-packages\traitlets\traitlets.py:1525, in HasTraits.notify_change(self, change)
   1523 def notify_change(self, change: Bunch) -> None:
   1524     """Notify observers of a change event"""
-> 1525     return self._notify_observers(change)

File ~\dev\gh\akielbowicz\presentations\.venv\Lib\site-packages\traitlets\traitlets.py:1568, in HasTraits._notify_observers(self, event)
   1565 elif isinstance(c, EventHandler) and c.name is not None:
   1566     c = getattr(self, c.name)
-> 1568 c(event)

Cell In[10], line 2, in intentar_encastrar(cambio)
      1 def intentar_encastrar(cambio):
----> 2     raise ValueError('No deberías hacer eso')

ValueError: No deberías hacer eso
In [11]:
from ipywidgets import Output
output = Output(layout={'border': '1px solid black'})

@output.capture()
def intentar_encastrar_otra_vez(cambio):
    raise ValueError('No deberías hacer eso otra vez')
    
ruflete.observe(intentar_encastrar_otra_vez)
output
Out[11]:
Output(layout=Layout(border_bottom='1px solid black', border_left='1px solid black', border_right='1px solid b…

hasta_ahora_todo_bien

siempre_me_preguntas_como

In [12]:
from traitlets import Unicode, Bool, validate, TraitError
from ipywidgets import DOMWidget, register


@register
class Cosito(DOMWidget):
    _view_name = Unicode('CositoView').tag(sync=True)
    _view_module = Unicode('cosito_widget').tag(sync=True)
    _view_module_version = Unicode('0.1.0').tag(sync=True)
var CositoModel = widgets.DOMWidgetModel.extend({
    defaults : function() { ... };
});

var CositoView = widgets.DOMWidgetView.extend({

   render : function() {
        this.el.appendChild(this.input);
        this.model.on('change:value',this.value_changed,this);
   };        
});

melancolia

https://github.com/jupyter-widgets/widget-ts-cookiecutter¶

bueno_ahora_escucha_mi_llamado

this.model.on('change:value',this.value_changed,this);

deja_de_chatearme

this.listenTo(this.model,'change:value',this.value_changed);

felicidad

class Reloj(DOMWidget):
    value = Date(None, allow_none=True).tag(sync=True, **date_serialization)

chino

Serialización entre python y javascript¶

chino

emoji

Traittypes¶

Serializador de numpy y pandas¶

Cuando empezamos a tener varios widgets que interactuan¶

In [13]:
from ipywidgets import FloatSlider, Dropdown

cosito = Cosito()
precio   = FloatSlider(min=0,max=200)
etiqueta = Dropdown(options=['Nuevo','Usado','Reparado'])

def cambiar_precio(cambio):
    cosito.precio = cambio['new']

def actualizacion_de_estado(cambio):
    if cambio['new'] == 'Usado':
        cosito.precio *=  0.45
        cosito.etiqueta = cambio['new']

precio.observe(cambiar_precio)
etiqueta.observe(actualizacion_de_estado,names='value')

las_estaciones

open_folk

Ipywidgets Issue 2296¶

In [14]:
from traitlets import HasTraits, Float, observe, Unicode

class CositoModelo(HasTraits):
    
    tamanio  = Float()
    nombre   = Unicode()
    precio   = Float()
    etiqueta = Unicode()
    
    def recalcular_precio(self):
       pass

    @observe('tamanio')
    def llamado(self, cambio):
        pass
        
    def __repr__(self):
        pass
In [15]:
import ipywidgets as widgets
from traitlets import link
from IPython.display import display

class CositoVista:
    def __init__(self, modelo):
        self.model    = modelo
        self.tipo     = widgets.Dropdown(options=["plastico", "metal"])
        self.etiqueta = widgets.Label('Original')
        self.tamanio  = widgets.IntSlider()
        self.precio   = widgets.FloatLogSlider()
                
        self.ipyview  = widgets.HBox([widgets.VBox([self.tipo, ]), 
                                      widgets.VBox([self.etiqueta, 
                                                    widgets.HBox([self.precio, self.tamanio])])])
 
        link((modelo, 'tipo'), (self.tipo, 'value'))
        link((modelo, 'etiqueta'), (self.etiqueta, 'value'))
        link((modelo, 'precio'), (self.precio, 'value'))
        link((modelo, 'tamanio'), (self.tamanio, 'value'))

    def _ipython_display_(self):
        display(self.ipyview)

@sashaKile¶

redes

Links¶

https://nosonhorasweb.com.ar/wp-content/uploads/2019/06/Open-Folk-Nsh-69.jpg

https://upload.wikimedia.org/wikipedia/commons/8/8f/Benito_Cerati_y_Charly_García.jpg

https://posta.fm/tecla-cualquiera-90e4fb3ebd8a

https://www.youtube.com/watch?v=QVJow3nwqSA

https://www.youtube.com/watch?v=uhq0ZHpunB4

https://www.youtube.com/watch?v=IZ7qVoO-l-E

https://twitter.com/furorpodcast

https://github.com/maartenbreddels/ipywebrtc

https://github.com/jupyter-widgets/pythreejs

https://github.com/jupyter-widgets/ipyleaflet

https://github.com/maartenbreddels/ipyvolume

https://github.com/martinRenou/ipycanvas

https://github.com/JuanCab/AstroInteractives

https://github.com/jupyter-widgets/tutorial

http://www.centrofersrl.com/wp-content/uploads/2016/11/GRN.jpg