From 34c5b9388f96a70e48dd8782434d2ea5d77c9aa1 Mon Sep 17 00:00:00 2001 From: Eric Hunsberger Date: Tue, 19 May 2015 15:29:42 -0400 Subject: [PATCH 01/14] WIP: Basic sparkle plot, a bit slow --- nengo_gui/components/__init__.py | 1 + nengo_gui/components/spike_grid.py | 57 +++++++++ nengo_gui/static/components/netgraph_item.js | 21 ++- nengo_gui/static/image.js | 127 +++++++++++++++++++ nengo_gui/templates/page.html | 1 + 5 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 nengo_gui/components/spike_grid.py create mode 100644 nengo_gui/static/image.js diff --git a/nengo_gui/components/__init__.py b/nengo_gui/components/__init__.py index 67167e7d..7a5935ab 100644 --- a/nengo_gui/components/__init__.py +++ b/nengo_gui/components/__init__.py @@ -9,6 +9,7 @@ from .netgraph import NetGraph from .ace_editor import AceEditor from .htmlview import HTMLView +from .spike_grid import SpikeGrid # Old versions of the .cfg files used Templates which had slightly different # names than the Components currently use. This code allows us to diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py new file mode 100644 index 00000000..989d6420 --- /dev/null +++ b/nengo_gui/components/spike_grid.py @@ -0,0 +1,57 @@ +import nengo +import numpy as np +import struct + +from nengo_gui.components.component import Component, Template + + +class SpikeGrid(Component): + def __init__(self, viz, config, uid, obj, n_neurons=None): + super(SpikeGrid, self).__init__(viz, config, uid) + self.obj = obj.neurons + self.data = [] + self.label = viz.viz.get_label(obj) + self.max_neurons = self.obj.size_out + if n_neurons is None: + n_neurons = self.max_neurons + self.n_neurons = n_neurons + self.pixels_x = np.ceil(np.sqrt(self.n_neurons)) + self.pixels_y = np.ceil(float(self.n_neurons) / self.pixels_x) + self.n_pixels = self.pixels_x * self.pixels_y + self.struct = struct.Struct('<%df' % (1 + self.n_pixels)) + + def add_nengo_objects(self, viz): + with viz.model: + self.node = nengo.Node(self.gather_data, size_in=self.obj.size_out) + self.conn = nengo.Connection(self.obj, self.node, synapse=None) + + def remove_nengo_objects(self, viz): + viz.model.connections.remove(self.conn) + viz.model.nodes.remove(self.node) + + def gather_data(self, t, x): + # TODO: pass only spiking neurons, using subclass of Nengo.Image? + # Considerations include how to filter if we're only passing spike + # times, i.e. need to write a new DataStore, or filter on server + # side, but filtering server-side means we no longer have spikes + # and have to send a lot more data. + y = np.zeros(self.n_pixels, dtype=x.dtype) + y[:x.size] = (x > 0.0) * 255. + data = self.struct.pack(t, *y) + self.data.append(data) + + def update_client(self, client): + while len(self.data) > 0: + data = self.data.pop(0) + client.write(data, binary=True) + + def javascript(self): + info = dict(uid=self.uid, label=self.label, + pixels_x=self.pixels_x, pixels_y=self.pixels_y) + json = self.javascript_config(info) + return 'new Nengo.Image(main, sim, %s);' % json + + +class SpikeGridTemplate(Template): + cls = SpikeGrid + config_params = dict(**Template.default_params) diff --git a/nengo_gui/static/components/netgraph_item.js b/nengo_gui/static/components/netgraph_item.js index 971a6d88..3e071f77 100644 --- a/nengo_gui/static/components/netgraph_item.js +++ b/nengo_gui/static/components/netgraph_item.js @@ -336,20 +336,21 @@ Nengo.NetGraphItem.prototype.generate_menu = function () { } } if (this.type == 'ens') { - items.push(['Value', function() {self.create_graph('Value');}]) + items.push(['Value', function() {self.create_graph('Value');}]); if (this.dimensions > 1) { - items.push(['XY-value', function() {self.create_graph('XYValue');}]) + items.push(['XY-value', function() {self.create_graph('XYValue');}]); } - items.push(['Spikes', function() {self.create_graph('Raster');}]) - items.push(['Voltages', function() {self.create_graph('Voltage');}]) + items.push(['Spikes', function() {self.create_graph('Raster');}]); + items.push(['Voltages', function() {self.create_graph('Voltage');}]); + items.push(['Spikes (grid)', function() {self.create_graph('SpikeGrid');}]); } if (this.type == 'node') { - items.push(['Slider', function() {self.create_graph('Slider');}]) + items.push(['Slider', function() {self.create_graph('Slider');}]); if (this.dimensions > 0) { - items.push(['Value', function() {self.create_graph('Value');}]) + items.push(['Value', function() {self.create_graph('Value');}]); } if (this.dimensions > 1) { - items.push(['XY-value', function() {self.create_graph('XYValue');}]) + items.push(['XY-value', function() {self.create_graph('XYValue');}]); } if (this.html_node) { items.push(['HTML', function() {self.create_graph('HTMLView');}]) @@ -357,9 +358,9 @@ Nengo.NetGraphItem.prototype.generate_menu = function () { } if (this.sp_targets.length > 0) { items.push(['Semantic pointer', - function() {self.create_graph('Pointer', self.sp_targets[0]);}]) + function() {self.create_graph('Pointer', self.sp_targets[0]);}]); } - items.push(['Details ...', function() {self.create_modal();}]) + items.push(['Details ...', function() {self.create_modal();}]); return items; }; @@ -644,7 +645,6 @@ Nengo.NetGraphItem.prototype.redraw_child_connections = function() { }; - Nengo.NetGraphItem.prototype.redraw_connections = function() { /** update any connections into and out of this */ for (var i in this.conn_in) { @@ -779,7 +779,6 @@ Nengo.NetGraphItem.prototype.get_height = function() { } - /** force a redraw of the item */ Nengo.NetGraphItem.prototype.redraw = function() { this.set_position(this.pos[0], this.pos[1]); diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js new file mode 100644 index 00000000..6670f0b7 --- /dev/null +++ b/nengo_gui/static/image.js @@ -0,0 +1,127 @@ +/** + * Shows an image or pixel grid over time + * @constructor + * + * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {int} args.n_lines - number of decoded values + * @param {float} args.miny - minimum value on y-axis + * @param {float} args.maxy - maximum value on y-axis + * @param {Nengo.SimControl} args.sim - the simulation controller + */ + +Nengo.Image = function(parent, sim, args) { + var self = this; + + Nengo.Component.call(self, parent, args); + self.sim = sim; + self.display_time = args.display_time; + self.pixels_x = args.pixels_x; + self.pixels_y = args.pixels_y; + self.n_pixels = self.pixels_x * self.pixels_y; + + /** for storing the accumulated data */ + self.data_store = new Nengo.DataStore(self.n_pixels, self.sim, 0.01); + + /** spacing between the graph and the outside edges (in pixels) */ + self.margin_top = 30; + self.margin_bottom = 0; + self.margin_left = 0; + self.margin_right = 0; + + /** draw the plot as an SVG */ + self.svg = d3.select(self.div).append('svg') + .attr('width', '100%') + .attr('height', '100%') + .attr('style', [ + 'margin-top:', self.margin_top, 'px;', + 'margin-bottom:', self.margin_bottom, 'px;', + 'margin-left:', self.margin_left, 'px;', + 'margin-right:', self.margin_right, 'px;' + ].join("")); + + /** call schedule_update whenever the time is adjusted in the SimControl */ + self.sim.div.addEventListener('adjust_time', + function(e) {self.schedule_update();}, false); + + /** create the image */ + self.image = self.svg.append("image") + .attr("x", 0) + .attr("y", 0) + .attr("width", "100%") + .attr("height", "100%") + .attr("style", [ + "image-rendering: -webkit-optimize-contrast;", + "image-rendering: -moz-crisp-edges;", + "image-rendering: -o-crisp-edges;", + "image-rendering: crisp-edges;" + ].join("")); + + self.canvas = document.createElement('CANVAS'); + self.canvas.width = self.pixels_x; + self.canvas.height = self.pixels_y; + + self.on_resize(args.width, args.height); + +}; +Nengo.Image.prototype = Object.create(Nengo.Component.prototype); +Nengo.Image.prototype.constructor = Nengo.Image; + +/** + * Receive new line data from the server + */ +Nengo.Image.prototype.on_message = function(event) { + var self = this; + var data = new Float32Array(event.data); + self.data_store.push(data); + self.schedule_update(); +} + +/** + * Redraw the lines and axis due to changed data + */ +Nengo.Image.prototype.update = function() { + var self = this; + + /** let the data store clear out old values */ + self.data_store.update(); + + var data = self.data_store.get_last_data(); + var ctx = self.canvas.getContext("2d"); + var imgData = ctx.getImageData(0, 0, self.pixels_x, self.pixels_y); + for (var i = 0; i < self.n_pixels; i++) { + imgData.data[4*i + 0] = data[i]; + imgData.data[4*i + 1] = data[i]; + imgData.data[4*i + 2] = data[i]; + imgData.data[4*i + 3] = 255; + } + ctx.putImageData(imgData, 0, 0); + var dataURL = self.canvas.toDataURL("image/png"); + + self.image.attr("xlink:href", dataURL); +}; + +/** + * Adjust the graph layout due to changed size + */ +Nengo.Image.prototype.on_resize = function(width, height) { + var self = this; + if (width < self.minWidth) { + width = self.minWidth; + } + if (height < self.minHeight) { + height = self.minHeight; + }; + + self.svg + .attr("width", width - self.margin_left - self.margin_right) + .attr("height", height - self.margin_top - self.margin_bottom); + + self.update(); + + self.label.style.width = width; + + self.width = width; + self.height = height; + self.div.style.width = width; + self.div.style.height = height; +}; diff --git a/nengo_gui/templates/page.html b/nengo_gui/templates/page.html index fe4d84bd..1f7b95db 100644 --- a/nengo_gui/templates/page.html +++ b/nengo_gui/templates/page.html @@ -129,6 +129,7 @@ + From a91e0e6b61372ba85061bdffd63e1c64c430d7f4 Mon Sep 17 00:00:00 2001 From: Jan Gosmann Date: Tue, 2 Jun 2015 14:52:03 -0400 Subject: [PATCH 02/14] Use pixelated sparkle plot where available. Reference of availability: https://developer.mozilla.org/en/docs/Web/CSS/image-rendering --- nengo_gui/static/image.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js index 6670f0b7..86215a4f 100644 --- a/nengo_gui/static/image.js +++ b/nengo_gui/static/image.js @@ -52,8 +52,7 @@ Nengo.Image = function(parent, sim, args) { .attr("style", [ "image-rendering: -webkit-optimize-contrast;", "image-rendering: -moz-crisp-edges;", - "image-rendering: -o-crisp-edges;", - "image-rendering: crisp-edges;" + "image-rendering: pixelated;" ].join("")); self.canvas = document.createElement('CANVAS'); From 676c21af07b507be082c4f2a634b91b5f40cccb3 Mon Sep 17 00:00:00 2001 From: Jan Gosmann Date: Wed, 3 Jun 2015 17:42:29 -0400 Subject: [PATCH 03/14] Use relative units for sparkle plot margins. --- nengo_gui/static/image.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js index 86215a4f..ecb2af7c 100644 --- a/nengo_gui/static/image.js +++ b/nengo_gui/static/image.js @@ -22,21 +22,12 @@ Nengo.Image = function(parent, sim, args) { /** for storing the accumulated data */ self.data_store = new Nengo.DataStore(self.n_pixels, self.sim, 0.01); - /** spacing between the graph and the outside edges (in pixels) */ - self.margin_top = 30; - self.margin_bottom = 0; - self.margin_left = 0; - self.margin_right = 0; - /** draw the plot as an SVG */ self.svg = d3.select(self.div).append('svg') .attr('width', '100%') .attr('height', '100%') .attr('style', [ - 'margin-top:', self.margin_top, 'px;', - 'margin-bottom:', self.margin_bottom, 'px;', - 'margin-left:', self.margin_left, 'px;', - 'margin-right:', self.margin_right, 'px;' + 'padding-top:', '2em', ].join("")); /** call schedule_update whenever the time is adjusted in the SimControl */ @@ -112,8 +103,8 @@ Nengo.Image.prototype.on_resize = function(width, height) { }; self.svg - .attr("width", width - self.margin_left - self.margin_right) - .attr("height", height - self.margin_top - self.margin_bottom); + .attr("width", width) + .attr("height", height); self.update(); From 6c8be483e24a37752358651fa81622ae95943b8b Mon Sep 17 00:00:00 2001 From: Jan Gosmann Date: Thu, 4 Jun 2015 17:54:21 -0400 Subject: [PATCH 04/14] Fix initial size. --- nengo_gui/static/image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js index ecb2af7c..cc38f752 100644 --- a/nengo_gui/static/image.js +++ b/nengo_gui/static/image.js @@ -50,7 +50,7 @@ Nengo.Image = function(parent, sim, args) { self.canvas.width = self.pixels_x; self.canvas.height = self.pixels_y; - self.on_resize(args.width, args.height); + self.on_resize(this.get_screen_width(), this.get_screen_height()); }; Nengo.Image.prototype = Object.create(Nengo.Component.prototype); From ab542825776f698c947293ff3babe272ce42c26a Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Tue, 28 Jul 2015 17:56:20 -0400 Subject: [PATCH 05/14] Improved communication --- nengo_gui/components/spike_grid.py | 22 ++++++++++++++-------- nengo_gui/static/image.js | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 989d6420..2bc178cc 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -18,32 +18,38 @@ def __init__(self, viz, config, uid, obj, n_neurons=None): self.pixels_x = np.ceil(np.sqrt(self.n_neurons)) self.pixels_y = np.ceil(float(self.n_neurons) / self.pixels_x) self.n_pixels = self.pixels_x * self.pixels_y - self.struct = struct.Struct('<%df' % (1 + self.n_pixels)) + self.struct = struct.Struct('<%dB' % (1 + self.n_pixels)) + self.max_value = 1.0 def add_nengo_objects(self, viz): with viz.model: self.node = nengo.Node(self.gather_data, size_in=self.obj.size_out) - self.conn = nengo.Connection(self.obj, self.node, synapse=None) + self.conn = nengo.Connection(self.obj, self.node, synapse=0.01) def remove_nengo_objects(self, viz): viz.model.connections.remove(self.conn) viz.model.nodes.remove(self.node) def gather_data(self, t, x): + self.max_value = max(self.max_value, np.max(x)) + # TODO: pass only spiking neurons, using subclass of Nengo.Image? # Considerations include how to filter if we're only passing spike - # times, i.e. need to write a new DataStore, or filter on server - # side, but filtering server-side means we no longer have spikes - # and have to send a lot more data. - y = np.zeros(self.n_pixels, dtype=x.dtype) - y[:x.size] = (x > 0.0) * 255. + # times, i.e. need to write a new DataStore. + y = np.zeros(self.n_pixels, dtype=np.uint8) + y[:x.size] = x * 255 / self.max_value data = self.struct.pack(t, *y) self.data.append(data) def update_client(self, client): while len(self.data) > 0: data = self.data.pop(0) - client.write(data, binary=True) + try: + client.write(data, binary=True) + except: + # if there is a communication problem, just drop the frame + # (this usually happens when there is too much data to send) + pass def javascript(self): info = dict(uid=self.uid, label=self.label, diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js index cc38f752..1e4395eb 100644 --- a/nengo_gui/static/image.js +++ b/nengo_gui/static/image.js @@ -20,7 +20,7 @@ Nengo.Image = function(parent, sim, args) { self.n_pixels = self.pixels_x * self.pixels_y; /** for storing the accumulated data */ - self.data_store = new Nengo.DataStore(self.n_pixels, self.sim, 0.01); + self.data_store = new Nengo.DataStore(self.n_pixels, self.sim, 0); /** draw the plot as an SVG */ self.svg = d3.select(self.div).append('svg') @@ -61,7 +61,7 @@ Nengo.Image.prototype.constructor = Nengo.Image; */ Nengo.Image.prototype.on_message = function(event) { var self = this; - var data = new Float32Array(event.data); + var data = new Uint8Array(event.data); self.data_store.push(data); self.schedule_update(); } From dbe43fd90c9165fc6e71e830172c8fc7ff02ac59 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Wed, 5 Aug 2015 17:16:28 -0400 Subject: [PATCH 06/14] Changed name of graph to 'Firing pattern' --- nengo_gui/static/components/netgraph_item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nengo_gui/static/components/netgraph_item.js b/nengo_gui/static/components/netgraph_item.js index 3e071f77..80634012 100644 --- a/nengo_gui/static/components/netgraph_item.js +++ b/nengo_gui/static/components/netgraph_item.js @@ -342,7 +342,7 @@ Nengo.NetGraphItem.prototype.generate_menu = function () { } items.push(['Spikes', function() {self.create_graph('Raster');}]); items.push(['Voltages', function() {self.create_graph('Voltage');}]); - items.push(['Spikes (grid)', function() {self.create_graph('SpikeGrid');}]); + items.push(['Firing pattern', function() {self.create_graph('SpikeGrid');}]); } if (this.type == 'node') { items.push(['Slider', function() {self.create_graph('Slider');}]); From 247bd201626b0fcec621760c151552bafc6029e3 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Wed, 5 Aug 2015 17:35:05 -0400 Subject: [PATCH 07/14] Updated to refactored Components --- nengo_gui/components/spike_grid.py | 40 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 2bc178cc..6ecf8ef4 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -2,16 +2,14 @@ import numpy as np import struct -from nengo_gui.components.component import Component, Template - +from nengo_gui.components.component import Component class SpikeGrid(Component): - def __init__(self, viz, config, uid, obj, n_neurons=None): - super(SpikeGrid, self).__init__(viz, config, uid) - self.obj = obj.neurons + def __init__(self, obj, n_neurons=None): + super(SpikeGrid, self).__init__() + self.obj = obj self.data = [] - self.label = viz.viz.get_label(obj) - self.max_neurons = self.obj.size_out + self.max_neurons = self.obj.neurons.size_out if n_neurons is None: n_neurons = self.max_neurons self.n_neurons = n_neurons @@ -21,14 +19,20 @@ def __init__(self, viz, config, uid, obj, n_neurons=None): self.struct = struct.Struct('<%dB' % (1 + self.n_pixels)) self.max_value = 1.0 - def add_nengo_objects(self, viz): - with viz.model: - self.node = nengo.Node(self.gather_data, size_in=self.obj.size_out) - self.conn = nengo.Connection(self.obj, self.node, synapse=0.01) + def attach(self, page, config, uid): + super(SpikeGrid, self).attach(page, config, uid) + self.label = page.get_label(self.obj) + + def add_nengo_objects(self, page): + with page.model: + self.node = nengo.Node(self.gather_data, + size_in=self.obj.neurons.size_out) + self.conn = nengo.Connection(self.obj.neurons, + self.node, synapse=0.01) - def remove_nengo_objects(self, viz): - viz.model.connections.remove(self.conn) - viz.model.nodes.remove(self.node) + def remove_nengo_objects(self, page): + page.model.connections.remove(self.conn) + page.model.nodes.remove(self.node) def gather_data(self, t, x): self.max_value = max(self.max_value, np.max(x)) @@ -52,12 +56,10 @@ def update_client(self, client): pass def javascript(self): - info = dict(uid=self.uid, label=self.label, + info = dict(uid=id(self), label=self.label, pixels_x=self.pixels_x, pixels_y=self.pixels_y) json = self.javascript_config(info) return 'new Nengo.Image(main, sim, %s);' % json - -class SpikeGridTemplate(Template): - cls = SpikeGrid - config_params = dict(**Template.default_params) + def code_python_args(self, uids): + return [uids[self.obj], 'n_neurons=%d' % self.n_neurons] From 3205f5a88c0de0a1d675b0a936a34c091aebf3e4 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Fri, 7 Aug 2015 22:40:13 -0400 Subject: [PATCH 08/14] Don't crash on increasing n_neurons --- nengo_gui/components/spike_grid.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 6ecf8ef4..f8b4b2bd 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -25,9 +25,9 @@ def attach(self, page, config, uid): def add_nengo_objects(self, page): with page.model: - self.node = nengo.Node(self.gather_data, + self.node = nengo.Node(self.gather_data, size_in=self.obj.neurons.size_out) - self.conn = nengo.Connection(self.obj.neurons, + self.conn = nengo.Connection(self.obj.neurons, self.node, synapse=0.01) def remove_nengo_objects(self, page): @@ -40,6 +40,8 @@ def gather_data(self, t, x): # TODO: pass only spiking neurons, using subclass of Nengo.Image? # Considerations include how to filter if we're only passing spike # times, i.e. need to write a new DataStore. + if len(x) > self.n_neurons: + x = x[:self.n_neurons] y = np.zeros(self.n_pixels, dtype=np.uint8) y[:x.size] = x * 255 / self.max_value data = self.struct.pack(t, *y) From f98e24ee3427bc015dc46254c7fba0366e11874e Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Fri, 7 Aug 2015 22:48:44 -0400 Subject: [PATCH 09/14] Handled changing number of neurons --- nengo_gui/components/netgraph.py | 1 + nengo_gui/components/spike_grid.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/nengo_gui/components/netgraph.py b/nengo_gui/components/netgraph.py index 122b78e6..81eab98e 100644 --- a/nengo_gui/components/netgraph.py +++ b/nengo_gui/components/netgraph.py @@ -468,6 +468,7 @@ def get_extra_info(self, obj): info['dimensions'] = int(obj.size_out) elif isinstance(obj, nengo.Ensemble): info['dimensions'] = int(obj.size_out) + info['n_neurons'] = int(obj.n_neurons) info['sp_targets'] = ( nengo_gui.components.pointer.Pointer.applicable_targets(obj)) return info diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index f8b4b2bd..77fa5cb5 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -64,4 +64,7 @@ def javascript(self): return 'new Nengo.Image(main, sim, %s);' % json def code_python_args(self, uids): - return [uids[self.obj], 'n_neurons=%d' % self.n_neurons] + args = [uids[self.obj]] + if self.n_neurons != self.max_neurons: + args.append('n_neurons=%d' % self.n_neurons) + return args From a1981651acc684efcefb3219ea65449c1e035ee2 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Fri, 7 Aug 2015 23:07:55 -0400 Subject: [PATCH 10/14] Fixed sparkle plot looking backwards in time --- nengo_gui/components/spike_grid.py | 5 +++-- nengo_gui/static/image.js | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 77fa5cb5..3f96cdcb 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -16,7 +16,7 @@ def __init__(self, obj, n_neurons=None): self.pixels_x = np.ceil(np.sqrt(self.n_neurons)) self.pixels_y = np.ceil(float(self.n_neurons) / self.pixels_x) self.n_pixels = self.pixels_x * self.pixels_y - self.struct = struct.Struct('<%dB' % (1 + self.n_pixels)) + self.struct = struct.Struct(' self.n_neurons: x = x[:self.n_neurons] y = np.zeros(self.n_pixels, dtype=np.uint8) - y[:x.size] = x * 255 / self.max_value + if self.max_value > 0: + y[:x.size] = x * 255 / self.max_value data = self.struct.pack(t, *y) self.data.append(data) diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js index 1e4395eb..0debbc90 100644 --- a/nengo_gui/static/image.js +++ b/nengo_gui/static/image.js @@ -60,10 +60,13 @@ Nengo.Image.prototype.constructor = Nengo.Image; * Receive new line data from the server */ Nengo.Image.prototype.on_message = function(event) { - var self = this; var data = new Uint8Array(event.data); - self.data_store.push(data); - self.schedule_update(); + var time_data = new Float32Array(event.data.slice(0,4)); + data = Array.prototype.slice.call(data); + data = data.slice(3); + data[0] = time_data[0]; + this.data_store.push(data); + this.schedule_update(); } /** From 635cc674502911e07ed089555997017d3ad4b54a Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Fri, 7 Aug 2015 23:22:27 -0400 Subject: [PATCH 11/14] slight efficiency increase in parsing sparkle data --- nengo_gui/static/image.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nengo_gui/static/image.js b/nengo_gui/static/image.js index 0debbc90..a759ec59 100644 --- a/nengo_gui/static/image.js +++ b/nengo_gui/static/image.js @@ -60,10 +60,9 @@ Nengo.Image.prototype.constructor = Nengo.Image; * Receive new line data from the server */ Nengo.Image.prototype.on_message = function(event) { - var data = new Uint8Array(event.data); + var data = new Uint8Array(event.data.slice(3)); var time_data = new Float32Array(event.data.slice(0,4)); data = Array.prototype.slice.call(data); - data = data.slice(3); data[0] = time_data[0]; this.data_store.push(data); this.schedule_update(); From 8f450937bdc95a03e1247870fb1aaf03af2641f1 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Mon, 31 Aug 2015 17:54:00 -0400 Subject: [PATCH 12/14] Moved image.js into components directory --- nengo_gui/static/{ => components}/image.js | 0 nengo_gui/templates/page.html | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename nengo_gui/static/{ => components}/image.js (100%) diff --git a/nengo_gui/static/image.js b/nengo_gui/static/components/image.js similarity index 100% rename from nengo_gui/static/image.js rename to nengo_gui/static/components/image.js diff --git a/nengo_gui/templates/page.html b/nengo_gui/templates/page.html index 1f7b95db..c75a40d0 100644 --- a/nengo_gui/templates/page.html +++ b/nengo_gui/templates/page.html @@ -129,7 +129,7 @@ - + From 9ac1b758548018611c502b5b005e2117308311d8 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Mon, 31 Aug 2015 18:15:24 -0400 Subject: [PATCH 13/14] Fixed bug where display lags behind simulation --- nengo_gui/components/spike_grid.py | 8 +++++--- nengo_gui/static/components/image.js | 14 +++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 3f96cdcb..490ca705 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -49,10 +49,12 @@ def gather_data(self, t, x): self.data.append(data) def update_client(self, client): - while len(self.data) > 0: - data = self.data.pop(0) + length = len(self.data) + if length > 0: + item = bytes().join(self.data[:length]) + del self.data[:length] try: - client.write(data, binary=True) + client.write(item, binary=True) except: # if there is a communication problem, just drop the frame # (this usually happens when there is too much data to send) diff --git a/nengo_gui/static/components/image.js b/nengo_gui/static/components/image.js index a759ec59..deaf80a2 100644 --- a/nengo_gui/static/components/image.js +++ b/nengo_gui/static/components/image.js @@ -60,11 +60,15 @@ Nengo.Image.prototype.constructor = Nengo.Image; * Receive new line data from the server */ Nengo.Image.prototype.on_message = function(event) { - var data = new Uint8Array(event.data.slice(3)); - var time_data = new Float32Array(event.data.slice(0,4)); - data = Array.prototype.slice.call(data); - data[0] = time_data[0]; - this.data_store.push(data); + var data = new Uint8Array(event.data); + var msg_size = this.n_pixels + 4; + + for (var i = 0; i < data.length; i += msg_size) { + var time_data = new Float32Array(event.data.slice(i, i + 4)); + data = Array.prototype.slice.call(data, i + 3, i + msg_size); + data[0] = time_data[0]; + this.data_store.push(data); + } this.schedule_update(); } From 451dd20d6bfc2d871d4473edf32dc961960a3a28 Mon Sep 17 00:00:00 2001 From: Terry Stewart Date: Mon, 31 Aug 2015 22:05:41 -0400 Subject: [PATCH 14/14] Cleaned up comments --- nengo_gui/components/spike_grid.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 490ca705..f5bc1e8f 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -36,10 +36,6 @@ def remove_nengo_objects(self, page): def gather_data(self, t, x): self.max_value = max(self.max_value, np.max(x)) - - # TODO: pass only spiking neurons, using subclass of Nengo.Image? - # Considerations include how to filter if we're only passing spike - # times, i.e. need to write a new DataStore. if len(x) > self.n_neurons: x = x[:self.n_neurons] y = np.zeros(self.n_pixels, dtype=np.uint8) @@ -56,7 +52,7 @@ def update_client(self, client): try: client.write(item, binary=True) except: - # if there is a communication problem, just drop the frame + # if there is a communication problem, just drop the frames # (this usually happens when there is too much data to send) pass