-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updated firing pattern plot #522
Merged
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
34c5b93
WIP: Basic sparkle plot, a bit slow
hunse a91e0e6
Use pixelated sparkle plot where available.
jgosmann 676c21a
Use relative units for sparkle plot margins.
jgosmann 6c8be48
Fix initial size.
jgosmann ab54282
Improved communication
tcstewar dbe43fd
Changed name of graph to 'Firing pattern'
tcstewar 247bd20
Updated to refactored Components
tcstewar 3205f5a
Don't crash on increasing n_neurons
tcstewar f98e24e
Handled changing number of neurons
tcstewar a198165
Fixed sparkle plot looking backwards in time
tcstewar 635cc67
slight efficiency increase in parsing sparkle data
tcstewar 8f45093
Moved image.js into components directory
tcstewar 9ac1b75
Fixed bug where display lags behind simulation
tcstewar 451dd20
Cleaned up comments
tcstewar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
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)) | ||
|
||
# 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) | ||
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 frame | ||
# (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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What Nengo.Image are you talking about? Dammit. Just figured it out by reading more. Maybe note that you're talking about Nengo.js?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that comment's a bit outdated anyway, as we don't want to just send spike data when we're doing the synapse filter in Nengo. I removed it.