Benutzerdefiniertes Widget

Das Widget-Framework basiert auf dem Comms-Framework, das dem Kernel ermöglicht, JSON an das Frontend zu senden und zu empfangen. Um nun ein benutzerdefiniertes Widget zu erstellen, muss das Widget sowohl im Browser als auch im Python-Kernel definiert werden.

Weitere Informationen zum Comms-Framework erhaltet ihr im Low Level Widget Tutorial.

Python-Kernel

DOMWidget

Um ein Widget zu definieren, muss es von der Basisklasse Widget oder DOMWidget erben. Wenn das Widget im Jupyter-Notebook angezeigt werden soll, sollte euer Widget von DOMWidget erben. Dabei erbt Die DOMWidget-Klasse selbst von der Widget-Klasse.

_view_name

Durch die Übernahme von DOMWidget wird dem Widget-Framework nicht mitgeteilt, welches Frontend-Widget mit dem Backend-Widget verknüpft werden soll.

Stattdessen müsst ihr dies selbst angeben durch eines der folgenden Attribute:

  • _view_name

  • _view_module

  • _view_module_version

und gegebenenfalls

  • _model_name

  • _model_module

[1]:
import ipywidgets as widgets
from traitlets import Unicode, validate

class HelloWidget(widgets.DOMWidget):
    _view_name = Unicode('HelloView').tag(sync=True)
    _view_module = Unicode('hello').tag(sync=True)
    _view_module_version = Unicode('0.1.0').tag(sync=True)

sync=True-Traitlets

Traitlets ist ein Framework, mit dem Python-Klassen Attribute mit Typprüfung, dynamisch berechneten Standardwerten und Callbacks bei Änderung haben können. Das sync=True- Keyword-Argument weist das Widget-Framework an, den Wert mit dem Browser zu synchronisieren; ohne würde der Browser nichts von _view_name oder _view_module erfahren.

Frontend (JavaScript)

Models und Views

Das Frontend des IPython-Widget-Frameworks hängt stark von Backbone.js ab. Backbone.js ist ein MVC-Framework (Model View Controller), das im Backend definierte Widgets automatisch mit generischen Backbone.js-Modellen im Frontend synchronisiert: das vorher definierte _view_name-Merkmal wird vom Widget-Framework verwendet, um die entsprechende Backbone.js-View zu erstellen und diese mit dem Model zu verknüpfen.

@jupyter-widgets/base importieren

Ihr müsst zuerst das @jupyter-widgets/base-Modul mit der define-Methode von RequireJS.

[2]:
%%javascript
define('hello', ["@jupyter-widgets/base"], function(widgets) {

});

View definieren

Als nächstes definieren wir die Widget-View-Klasse wobei wir von DOMWidgetView mit der .extend-Methode erben.

[3]:
%%javascript
require.undef('hello');

define('hello', ["@jupyter-widgets/base"], function(widgets) {
    // Define the HelloView
    var HelloView = widgets.DOMWidgetView.extend({
    });
    return {
        HelloView: HelloView
    }
});

render-Methode

Zum Schluss müssen wir noch die Basismethode render überschreiben um eine benutzerdefinierte Rendering-Logik zu definieren. Ein Handle auf das Standard-DOM-Element des Widgets kann mit this.el aufgerufen werden. Die el-Eigenschaft ist das DOM-Element, das der Ansicht zugeordnet ist.

[4]:
%%javascript
require.undef('hello');

define('hello', ["@jupyter-widgets/base"], function(widgets) {
    var HelloView = widgets.DOMWidgetView.extend({
        // Render the view.
        render: function() {
            this.el.textContent = 'Hello World!';
        },
    });
    return {
        HelloView: HelloView
    };
});

Test

Das Widget lässt sich jetzt wie jedes andere Widget anzeigen mit

[5]:
HelloWidget()

Stateful Widget

Mit dem obigen Beispiel könnt ihr noch nicht viel tun. Um dies zu ändern, müsst ihr das Widget stateful machen. Anstelle einer statischen Hello World!-Meldung soll eine vom Backend festgelegter String angezeigt werden. Hierzu wird zunächst ein neues Traitlet hinzugefügt. Verwendet hierbei den Namen von value, um mit dem Rest des Widget-Frameworks konsistent zu bleiben und die Verwendung eures Widgets mit Interaktion zu ermöglichen.

Jupyter Widgets aus einem Template erstellen

Mit widget-cookiecutter ist ein Cookiecutter-Template verfügbar. Es enthält eine Implementierung für ein Platzhalter-Widget Hello World. Darüberhinaus erleichtert es euch das Packen und Verteilen eurer Jupyter Widgets.