Skip to content

Commit

Permalink
Merge pull request #522 from nengo/sparkle2
Browse files Browse the repository at this point in the history
Firing pattern plot
  • Loading branch information
tcstewar committed Sep 1, 2015
2 parents 4fc9b7c + 451dd20 commit 06045c0
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 11 deletions.
1 change: 1 addition & 0 deletions nengo_gui/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions nengo_gui/components/netgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 69 additions & 0 deletions nengo_gui/components/spike_grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import nengo
import numpy as np
import struct

from nengo_gui.components.component import Component

class SpikeGrid(Component):
def __init__(self, obj, n_neurons=None):
super(SpikeGrid, self).__init__()
self.obj = obj
self.data = []
self.max_neurons = self.obj.neurons.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('<f%dB' % (self.n_pixels))
self.max_value = 1.0

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, 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))
if len(x) > self.n_neurons:
x = x[:self.n_neurons]
y = np.zeros(self.n_pixels, dtype=np.uint8)
if self.max_value > 0:
y[:x.size] = x * 255 / self.max_value
data = self.struct.pack(t, *y)
self.data.append(data)

def update_client(self, client):
length = len(self.data)
if length > 0:
item = bytes().join(self.data[:length])
del self.data[:length]
try:
client.write(item, binary=True)
except:
# if there is a communication problem, just drop the frames
# (this usually happens when there is too much data to send)
pass

def javascript(self):
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

def code_python_args(self, uids):
args = [uids[self.obj]]
if self.n_neurons != self.max_neurons:
args.append('n_neurons=%d' % self.n_neurons)
return args
123 changes: 123 additions & 0 deletions nengo_gui/static/components/image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* 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);

/** draw the plot as an SVG */
self.svg = d3.select(self.div).append('svg')
.attr('width', '100%')
.attr('height', '100%')
.attr('style', [
'padding-top:', '2em',
].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: pixelated;"
].join(""));

self.canvas = document.createElement('CANVAS');
self.canvas.width = self.pixels_x;
self.canvas.height = self.pixels_y;

self.on_resize(this.get_screen_width(), this.get_screen_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 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();
}

/**
* 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)
.attr("height", height);

self.update();

self.label.style.width = width;

self.width = width;
self.height = height;
self.div.style.width = width;
self.div.style.height = height;
};
21 changes: 10 additions & 11 deletions nengo_gui/static/components/netgraph_item.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,30 +336,31 @@ 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(['Firing pattern', 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');}])
}
}
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;
};

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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]);
Expand Down
1 change: 1 addition & 0 deletions nengo_gui/templates/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ <h4 class="modal-title"></h4>
<script src="static/components/netgraph.js"></script>
<script src="static/components/netgraph_item.js"></script>
<script src="static/components/netgraph_conn.js"></script>
<script src="static/components/image.js"></script>
<script src="static/sim_control.js"></script>
<script src="static/top_toolbar.js"></script>
<script src="static/modal.js"></script>
Expand Down

0 comments on commit 06045c0

Please sign in to comment.