import sys, time from IPython.utils.traitlets import HasTraits, Integer, Unicode, Bool, Instance, Float from IPython.display import * from IPython.kernel.comm import Comm %%javascript var TestWidget = function (comm) { this.comm = comm; this.comm.on_msg($.proxy(this.handler, this)); // get the cell that was probably executed // msg_id:cell mapping will make this possible without guessing this.cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1); this.callbacks = { iopub : { output : $.proxy(this.cell.output_area.handle_output, this.cell.output_area) } }; }; TestWidget.prototype.handler = function(msg) { console.log('handle', this, msg, this.cell.output_area); this.comm.send({ b:10 }, this.callbacks); }; IPython.notebook.kernel.comm_manager.register_target('test', IPython.utils.always_new(TestWidget)); comm = Comm(target_name='test') comm.send(dict(a=5)) def handler(msg): print >> sys.__stderr__, msg print msg comm.on_msg(handler) comm.send(dict(a=10)) import uuid class Widget(HasTraits): target_name = Unicode("widget") id = Unicode() def _id_default(self): return 'widget-%s' % uuid.uuid4().hex comm = Instance(Comm) def _comm_default(self): data = self.data data['id'] = self.id return Comm(data, target_name=self.target_name) @property def data(self): return {} class RangeWidget(Widget): target_name = Unicode("range") min = Float(0) max = Float(100) value = Float(50) step = Float(1) _keys = ['min', 'max', 'value', 'step'] _in_handler = Bool(False) def _validate_and_update(self, name, old, new): if self.value > self.max: raise ValueError("value %d exceeds max %d" % (self.value, self.max)) if new < self.min: raise ValueError("value %d below min %d" % (self.value, self.min)) if not self._in_handler: self.update() def __init__(self, **kwargs): super(RangeWidget, self).__init__(**kwargs) self.comm.on_msg(self.handle_msg) # register on_trait_change after init # otherwise default values can't be specified self.on_trait_change(self._validate_and_update, self._keys) @property def data(self): return {key:getattr(self, key) for key in self._keys} def update(self): self.comm.send(self.data) def __repr__(self): return "" % (self.value, self.min, self.max, self.step) def handle_msg(self, msg): self._in_handler = True data = msg['content']['data'] try: for key in self._keys: if key in data: setattr(self, key, data[key]) finally: self._in_handler = False sys.stdout.write('\r%s' % self) sys.stdout.flush() def _repr_html_(self): return """
""" % self.id def display(self): display(self) self.update() %%javascript var RangeWidget = function (comm, msg) { this.comm = comm; comm.on_msg($.proxy(this.handle_msg, this)); // get the cell that was probably executed // msg_id:cell mapping will make this possible without guessing this.cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1); this.callbacks = { iopub : { output : $.proxy(this.cell.output_area.handle_output, this.cell.output_area) } }; this.keys = ['min', 'max', 'step']; this.data = msg.content.data; this.id = this.data.id; this.get_div(); }; RangeWidget.prototype.get_div = function () { var div = $("div." + this.id); if (div.length === 0) { return null; } if (div.find("input").length === 0) { this.create_range(div); } return div; }; RangeWidget.prototype.create_range = function (thediv) { var range = $('').attr('type', 'range'); var data = this.data; for (var i=0; i < this.keys.length; i++) { var key = this.keys[i]; range.attr(key, data[key]); } range.val(data.value); thediv.append( $("").addClass("min").text(data.min) ).append( range ).append( $("").addClass("max").text(data.max) ).append( $("
") ).append( $("").addClass("value").text(data.value) ); range.on("change", $.proxy(this.value_changed, this)); } RangeWidget.prototype.value_changed = function (evt) { var now = new Date(); if (now - this.last_changed < 100) { // only update every 0.1s, max // return; } var div = this.get_div(); var range = div.find("input"); var data = {}; for (var i=0; i < this.keys.length; i++) { var key = this.keys[i]; data[key] = parseFloat(range.attr(key)); } data.value = parseFloat(range.val()); div.find("span.min").text(data.min); div.find("span.max").text(data.max); div.find("span.value").text(data.value); this.comm.send(data, this.callbacks); this.last_changed = now; }; RangeWidget.prototype.handle_msg = function (msg) { var data = msg.content.data; this.data = data; var div = this.get_div(); if (!div) { return; } var range = div.find("input"); for (var i=0; i < this.keys.length; i++) { var key = this.keys[i]; range.attr(key, data[key]); } div.find("span.min").text(data.min); div.find("span.max").text(data.max); div.find("span.value").text(data.value); range.val(data.value); }; IPython.notebook.kernel.comm_manager.register_target('range', IPython.utils.always_new(RangeWidget)); r = RangeWidget() r.display() r.value = 10 print r import math, time import numpy as np x = np.linspace(0,10,1000) y = 50 + (np.sin(x) * 50) for n in y: r.value = (n) time.sleep(0.005) from IPython.utils.traitlets import List class FlotWidget(Widget): lines = List() target_name = Unicode('flotplot') def show(self): self.comm.send(dict(lines=self.lines)) def plot(self, x, y): self.lines.append(list(zip(x,y))) self.show() def clear(self): self.lines = [] self.show() def display(self): display(self) self.clear() def _repr_html_(self): return '
' % self.id %%javascript $.getScript('//cdnjs.cloudflare.com/ajax/libs/flot/0.8.1/jquery.flot.min.js'); $("").appendTo("head"); var FlotWidget = function (comm, msg) { this.comm = comm; this.id = msg.content.data.id; comm.on_msg($.proxy(this.handle_msg, this)); }; FlotWidget.prototype.handle_msg = function (msg) { console.log(msg) $.plot($('#' + this.id), msg.content.data.lines); } IPython.notebook.kernel.comm_manager.register_target('flotplot', IPython.utils.always_new(FlotWidget)); flt = FlotWidget() flt.display() x = np.linspace(0,5,200) y = np.sin(x) flt.plot(x,np.sin(x)) flt.plot(x,np.cos(x)) flt.plot(x, np.sin(2*x)) flt.plot(x, np.sin(3*x)) flt.clear() from IPython.utils.traitlets import HasTraits, Instance, Any class SineOmegaT(HasTraits): omega = Instance(RangeWidget, kw=dict(min=0, max=10, step=0.1, value=1), allow_none=False) flot = Instance(FlotWidget, args=()) # can't use traitlets with numpy arrays t = None y = None _in_omega_changed = False def _omega_value_changed(self, name, old, new): self.y = np.sin(new * self.t) self.show() def __init__(self): super(SineOmegaT, self).__init__() self.omega.on_trait_change(self._omega_value_changed, 'value') self.t = np.linspace(0,10,200) self.y = np.sin(self.omega.value * self.t) # add HTML to the dom display(self) # ensure omega slider is drawn self.omega.update() self.last_draw = 0 self.show() def show(self): now = time.time() if False and (now - self.last_draw) < 0.1: return self.last_draw = now self.flot.lines = [] self.flot.plot(self.t, self.y) def display(self): display(self) self.show() def _repr_html_(self): return u"
$sin(\omega t)$

%s
$\omega$: %s" % (self.flot._repr_html_(), self.omega._repr_html_()) sino = SineOmegaT() sino.omega.max = 30 sino.omega.step = 1 sino.t = np.linspace(0,10,10) sino.show() class RPCWidget(object): def __init__(self, comm, msg): self.comm = comm self.comm.on_msg(self.handle_msg) @property def shell(self): return get_ipython() def add(self, a, b): return a + b def mul(self, x, y): return x * y def get_execution_count(self): return self.shell.execution_count def handle_msg(self, msg): data = msg['content']['data'] method = getattr(self, data['method']) args = data.get('args', ()) kwargs = data.get('kwargs', {}) result = method(*args, **kwargs) self.comm.send(dict(result=result, method=data['method'])) get_ipython().comm_manager.register_target('rpc', RPCWidget) %%javascript var RPCWidget = function (comm) { this.comm = comm; // get the cell that was probably executed // msg_id:cell mapping will make this possible without guessing this.comm.on_msg($.proxy(this.handle_msg, this)); this.cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1); this.callbacks = { iopub : { output : $.proxy(this.cell.output_area.handle_output, this.cell.output_area) } }; this.target = 'rpc'; }; RPCWidget.prototype.handle_msg = function (msg) { this.cell.output_area.handle_output({ header : { msg_type : 'stream', msg_id : '', }, parent_header : msg.parent_header, content : { name: 'stdout', data: JSON.stringify(msg.content.data) + "\n" } }); } RPCWidget.prototype.add = function (a,b) { this.comm.send({method : 'add', args : [a,b]}, this.callbacks); } RPCWidget.prototype.mul = function (a,b) { this.comm.send({method : 'mul', args : [a,b]}, this.callbacks); } RPCWidget.prototype.get_ec = function () { this.comm.send({method : 'get_execution_count'}, this.callbacks); } var comm = new IPython.Comm(IPython.utils.uuid(), 'rpc'); IPython.notebook.kernel.comm_manager.register_comm(comm); comm.open(); var rpc = new RPCWidget(comm); rpc.add(5,3); rpc.get_ec(); rpc.mul(6,6); window.rpc = rpc; %%javascript window.rpc.mul(10,500);