Skip to content
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

Added ability to change color palettes #574

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1d87572
Added basic labels to value plot
Seanny123 Oct 1, 2015
8c99b64
added modal to edit labels
Seanny123 Oct 4, 2015
5825cd2
Create plots for the input and the output of the SPA Basal Ganglia
Seanny123 Oct 4, 2015
f328e9b
Added ability to choose different color palette
Seanny123 Oct 14, 2015
4921aa9
added color palette to config
Seanny123 Oct 14, 2015
91c57da
fixed legend setting behaviour
Seanny123 Oct 14, 2015
b83d12d
expanded palette switching to spa_similarity and bg_plot
Seanny123 Oct 16, 2015
74aa0f5
removed left-over ipdb
Seanny123 Oct 16, 2015
ded744a
Fixed id and empty labels error for spasimilarity
Seanny123 Oct 16, 2015
ed4f79e
Removed redundant variable from bg_plot
Seanny123 Oct 20, 2015
a91e6dc
Added basic labels to value plot
Seanny123 Oct 1, 2015
fe5caae
added modal to edit labels
Seanny123 Oct 4, 2015
a57699d
Create plots for the input and the output of the SPA Basal Ganglia
Seanny123 Oct 4, 2015
f64d726
Added ability to choose different color palette
Seanny123 Oct 14, 2015
8c06f90
added color palette to config
Seanny123 Oct 14, 2015
a7b5978
fixed legend setting behaviour
Seanny123 Oct 14, 2015
8683a1e
expanded palette switching to spa_similarity and bg_plot
Seanny123 Oct 16, 2015
0e7cef0
removed left-over ipdb
Seanny123 Oct 16, 2015
30b4e02
Fixed id and empty labels error for spasimilarity
Seanny123 Oct 16, 2015
91e0a31
Removed redundant variable from bg_plot
Seanny123 Oct 20, 2015
a913d86
fixed formatting stuff
Seanny123 Oct 28, 2015
9137f2a
fix bg plot disapearing problem
Seanny123 Oct 30, 2015
7acea6d
Merge branch 'more-colors' of github.com:nengo/nengo_gui into more-co…
Seanny123 Oct 30, 2015
89092b0
delete useless fil
Seanny123 Nov 16, 2015
3daa7ca
Merge remote-tracking branch 'origin/master' into more-colors
Seanny123 Nov 17, 2015
b319286
fixup
Seanny123 Nov 17, 2015
59272f3
fixup config
Seanny123 Nov 17, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nengo_gui/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .spa_similarity import SpaSimilarity
from .htmlview import HTMLView
from .spike_grid import SpikeGrid
from .bg_plot import BGPlot

# 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
52 changes: 52 additions & 0 deletions nengo_gui/components/bg_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import struct

import nengo
import numpy as np

from nengo_gui.components.value import Value


class BGPlot(Value):
"""The server-side system for the SPA Basal Ganglia plot."""

# the parameters to be stored in the .cfg file
config_defaults = Value.config_defaults
config_defaults["palette_index"] = 1
config_defaults["show_legend"] = True

def __init__(self, obj, **kwargs):
args = kwargs["args"]
super(BGPlot, self).__init__(obj, args["n_lines"])

# default legends to show
self.def_legend_labels = args["legend_labels"]

# the item to connect to
self.probe_target = args["probe_target"]

self.label = "bg " + self.probe_target

def attach(self, page, config, uid):
super(Value, self).attach(page, config, uid)

def add_nengo_objects(self, page):
# create a Node and a Connection so the Node will be given the
# data we want to show while the model is running.
with page.model:
self.node = nengo.Node(self.gather_data,
size_in=self.n_lines)
if self.probe_target == "input":
self.conn = nengo.Connection(self.obj.input, self.node, synapse=0.01)
else:
self.conn = nengo.Connection(self.obj.output, self.node, synapse=0.01)

def javascript(self):
# generate the javascript that will create the client-side object
info = dict(uid=id(self), label=self.label,
n_lines=self.n_lines, synapse=0)

if getattr(self.config, "legend_labels") == []:
json = self.javascript_config(info, override={"legend_labels":self.def_legend_labels})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???? Why not just do

info = dict(uid=id(self), label=self.label, 
                   n_lines=self.n_lines, synapse=0,
                   legend_labels=self.def_legend_labels)

and get rid of this whole override thing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the behaviour of javascript_config is to override everything with the defaults. It doesn't look to see if the defaults have been set to anything else. Is that it's intended behaviour or should the code be changed?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I understand... all javascript_config does is go through the config entry for the item and just into a json output:

        for attr in self.config._clsparams.params:
            cfg[attr] = getattr(self.config, attr)
        return json.dumps(cfg)

what do you mean by overriding everything with the defaults?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll break it down why it over-writes by going through the above code with the example of legend_labels being set in dict argument to ["A", "B", "C"].

cfg is the dict I've passed in as an argument. The for-loop takes values from the default config, which is self.config._clsparams and adds it to cfg. The default config contains legend_labels = [], so when the for-loop runs, regardless of what the value that cfg has for legend_labels, it will be over-written by the default config. That is why ["A","B","C"] will be over-written to []. Does that make sense now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's basically equivalent to running this code:

cfg = dict(label="pants", n_lines=4, legend_labels=["A", "B", "C"])

default_conf = dict(min=-1, max=1, legend_labels=[])

for attr in default_conf.keys():
    cfg[attr] = default_conf[attr]
print(cfg)

else:
json = self.javascript_config(info)
return 'new Nengo.Value(main, sim, %s);' % json
7 changes: 5 additions & 2 deletions nengo_gui/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,16 @@ def remove_nengo_objects(self, page):
"""
pass

def javascript_config(self, cfg):
def javascript_config(self, cfg, override = {}):
"""Convert the nengo.Config information into javascript.

This is needed so we can send that config information to the client.
"""
for attr in self.config._clsparams.params:
cfg[attr] = getattr(self.config, attr)
if attr not in override:
cfg[attr] = getattr(self.config, attr)
else:
cfg[attr] = override[attr]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment in bgplot.py; I'm pretty sure that this override thing isn't needed at all, since you can just directly put that stuff in the dictionary you're creating and passing in here.

return json.dumps(cfg)

def code_python(self, uids):
Expand Down
10 changes: 10 additions & 0 deletions nengo_gui/components/netgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import threading

import nengo
from nengo import spa
import json

from nengo_gui.components.component import Component
Expand Down Expand Up @@ -469,6 +470,15 @@ def get_extra_info(self, obj):
elif isinstance(obj, nengo.Ensemble):
info['dimensions'] = int(obj.size_out)
info['n_neurons'] = int(obj.n_neurons)
# TODO: Add the same functionality for the BasalGanglia non-spa net
elif isinstance(obj, spa.BasalGanglia):
info['bg_inputs'] = obj.input.size_in
info['input_labels'] = []
for ac in obj.actions.actions:
if ac.name == None:
info['input_labels'].append(ac.condition.expression.__str__())
else:
info['input_labels'].append(ac.name)
info['sp_targets'] = (
nengo_gui.components.pointer.Pointer.applicable_targets(obj))
return info
Expand Down
8 changes: 3 additions & 5 deletions nengo_gui/components/spa_similarity.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

class SpaSimilarity(SpaPlot):

config_defaults = dict(max_value=1,
min_value=-1,
show_pairs=False,
config_defaults = dict(max_value=1.5, min_value=-1.5,
palette_index=1, show_pairs=False,
**Component.config_defaults)

def __init__(self, obj, **kwargs):
Expand Down Expand Up @@ -80,8 +79,7 @@ def update_legend(self, vocab):
def javascript(self):
"""Generate the javascript that will create the client-side object"""
info = dict(uid=id(self), label=self.label, n_lines=len(self.labels),
synapse=0, min_value=-1.5, max_value=1.5,
pointer_labels=self.labels)
synapse=0, pointer_labels=self.labels)
json = self.javascript_config(info)
return 'new Nengo.SpaSimilarity(main, sim, %s);' % json

Expand Down
17 changes: 11 additions & 6 deletions nengo_gui/components/value.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ class Value(Component):
"""The server-side system for a Value plot."""

# the parameters to be stored in the .cfg file
config_defaults = dict(max_value=1,
min_value=-1,
config_defaults = dict(max_value=1, min_value=-1,
show_legend=False, legend_labels=[], palette_index=0,
**Component.config_defaults)

def __init__(self, obj):
def __init__(self, obj, n_lines=0):
super(Value, self).__init__()
# the object whose decoded value should be displayed
self.obj = obj
Expand All @@ -23,7 +23,11 @@ def __init__(self, obj):
self.data = []

# the number of data values to send
self.n_lines = int(obj.size_out)
self.n_lines = 0
if n_lines == 0:
self.n_lines = int(obj.size_out)
else:
self.n_lines = n_lines

# the binary data format to sent in. In this case, it is a list of
# floats, with the first float being the time stamp and the rest
Expand All @@ -40,7 +44,7 @@ def add_nengo_objects(self, page):
# data we want to show while the model is running.
with page.model:
self.node = nengo.Node(self.gather_data,
size_in=self.obj.size_out)
size_in=self.n_lines)
self.conn = nengo.Connection(self.obj, self.node, synapse=0.01)

def remove_nengo_objects(self, page):
Expand Down Expand Up @@ -68,7 +72,8 @@ def update_client(self, client):
def javascript(self):
# generate the javascript that will create the client-side object
info = dict(uid=id(self), label=self.label,
n_lines=self.n_lines, synapse=0)
n_lines=self.n_lines, synapse=0)

json = self.javascript_config(info)
return 'new Nengo.Value(main, sim, %s);' % json

Expand Down
3 changes: 2 additions & 1 deletion nengo_gui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def dumps(self, uids):
lines.append('%s = %s' % (uid, obj.code_python(uids)))
for k in obj.config_defaults.keys():
v = getattr(self[obj], k)
if isinstance(v, bool):
if(isinstance(v, bool) or isinstance(v, list)
or isinstance(v, dict)):
val = '%s' % v
else:
val = '%g' % v
Expand Down
45 changes: 45 additions & 0 deletions nengo_gui/static/color.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Generate a color sequence of a given length.
*/

/**
* Generate a color sequence of a given length.
*
* Colors are defined using a color blind-friendly palette.
*/
Nengo.make_colors = function(N) {
// Color blind palette with blue, green, red, magenta, yellow, cyan
var palette = ["#1c73b3", "#039f74", "#d65e00", "#cd79a7", "#f0e542", "#56b4ea"];
var c = [];

for (var i = 0; i < N; i++) {
c.push(palette[i % palette.length]);
}
return c;
}

/**
* Color blind-friendly palette.
*/
Nengo.default_colors = function() {
// Color blind palette with blue, green, red, magenta, yellow, cyan
var palette = ["#1c73b3", "#039f74", "#d65e00", "#cd79a7", "#f0e542", "#56b4ea"];
return function(i){ return palette[i%palette.length] };
}

/**
* Color palette use by Google for graphics, trends, etc...
*/
Nengo.google_colors = function() {
var palette = ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499", "#22aa99", "#aaaa11", "#6633cc", "#e67300", "#8b0707", "#651067", "#329262", "#5574a6", "#3b3eac"];
return function(i){ return palette[i%palette.length] };
}

/** list of valid color choices */
Nengo.color_choices = [
["Nengo Color-Blind Friendly (6 colors)", {"func":Nengo.default_colors(), "mod":6}],
["Google (20 colors)", {"func":Nengo.google_colors(), "mod":20}],
["D3.js A (20 colors)", {"func":d3.scale.category20(), "mod":20}],
["D3.js B (20 colors)", {"func":d3.scale.category20b(), "mod":20}],
["D3.js C (20 colors)", {"func":d3.scale.category20c(), "mod":20}]
];
23 changes: 22 additions & 1 deletion nengo_gui/static/components/netgraph_item.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) {
this.size = info.size;
this.type = info.type;
this.uid = info.uid;
this.sp_targets = info.sp_targets;
this.passthrough = info.passthrough;
this.fixed_width = null;
this.fixed_height = null;
Expand All @@ -34,6 +33,12 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) {
this.g_items = ng.g_items_mini;
}

// SPA network specific parameter
this.sp_targets = info.sp_targets;
// Basal Ganglia network specific parameters
this.bg_inputs = info.bg_inputs;
this.input_labels = info.input_labels;

/** if this is a network, the children list is the set of NetGraphItems
* and NetGraphConnections that are inside this network */
this.children = [];
Expand Down Expand Up @@ -362,6 +367,22 @@ Nengo.NetGraphItem.prototype.generate_menu = function () {
items.push(['Semantic pointer plot',
function() {self.create_graph('SpaSimilarity', self.sp_targets[0]);}])
}
if (this.bg_inputs) {
items.push(['Input Plot',
function () {
self.create_graph('BGPlot',
{"n_lines":self.bg_inputs, "legend_labels":self.input_labels, "probe_target":"input"}
);
}
]);
items.push(['Output Plot',
function () {
self.create_graph('BGPlot',
{"n_lines":self.bg_inputs, "legend_labels":self.input_labels, "probe_target":"output"}
);
}
]);
}
items.push(['Details ...', function() {self.create_modal();}]);
return items;
};
Expand Down
Loading