Skip to content

Instantly share code, notes, and snippets.

@mdrohmann
Last active August 29, 2015 14:14
Show Gist options
  • Save mdrohmann/d1f068cfff753d25c45c to your computer and use it in GitHub Desktop.
Save mdrohmann/d1f068cfff753d25c45c to your computer and use it in GitHub Desktop.
Interactive demo of d3-mvc

This is an interactive demonstration of d3-mvc. It is a small library on top of d3, that allows you to quickly create a 2D chart with a legend and some interactive controls for your data.

Consider to add the following new plots to the text field above (do not forget to separate plots with commas):

  • cosinus curve

      {
      "name": "cos curve",
      "data": [[ 0        ,  0.31578947,  0.63157895,  0.94736842,  1.26315789,
          1.57894737,  1.89473684,  2.21052632,  2.52631579,  2.84210526,
          3.15789474,  3.47368421,  3.78947368,  4.10526316,  4.42105263,
          4.73684211,  5.05263158,  5.36842105,  5.68421053,  6        ],
          [ 1        ,  0.95055149,  0.80709627,  0.58382164,  0.30280879,
         -0.00815095, -0.31830459, -0.59697884, -0.81661368, -0.95548785,
         -0.99986712, -0.94536252, -0.79736438, -0.57050928, -0.28723252,
          0.02445069,  0.33371579,  0.6099774 ,  0.82591406,  0.96017029]
          ]
      }
    
  • a plot with a second y axis

      {
          "name": "two points 1",
          "ydesc": "completely different y values",
          "data": [[0, 5], [-100, 100]]
      }
    
  • a plot with a second x axis

      {
          "name": "two points 2",
          "xdesc": "completely different x values",
          "ydesc": "completely different y values",
          "data": [[-200, 200], [-100, 100]]
      }
    
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.d3mvc=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (global){
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
var String = require('./utils/string_extension.js');
function Axis2d(view, configuration) {
this.view = view;
this.container = view.container;
for (var i=0; i<configuration.length; ++i) {
this.extra_margin = configuration[i].extra_margin || undefined;
}
this.compute_axes();
}
Axis2d.prototype = {};
Axis2d.prototype.height = function() {
var margin = this.margin();
return Math.max(this.view.height() - margin.top - margin.bottom, 1);
};
Axis2d.prototype.width = function() {
var margin = this.margin();
return Math.max(this.view.width() - margin.left - margin.right, 1);
};
/* This method needs to be executed, when
* - the model changes
* - the scaling of any axis changes.
*
* Note: Changing the range of an axis scale does not require this function
* to be run.
*/
Axis2d.prototype.compute_axes = function() {
var margin = {
top: 10, bottom: 50, left: 60, right: 10
};
model = this.view.model;
if (model.length === 0) {
throw {
name: 'ModelFormatError',
message: 'Model needs to have at least one element.'
};
}
var xdescs = {},
ydescs = {};
for (var mi=0; mi < model.length; ++mi) {
var xdesc = this.view.adapter().xdesc(mi);
var ydesc = this.view.adapter().ydesc(mi);
xdomain_tmp = this.view.adapter().xdomain(mi);
ydomain_tmp = this.view.adapter().ydomain(mi);
if (xdesc in xdescs) {
xdescs[xdesc].indices.push(mi);
xdescs[xdesc].domain = d3.extent(
xdomain_tmp.concat(xdescs[xdesc].domain));
} else {
xdescs[xdesc] = {};
xdescs[xdesc].indices = [mi];
xdescs[xdesc].domain = xdomain_tmp;
}
if (ydesc in ydescs) {
ydescs[ydesc].indices.push(mi);
ydescs[ydesc].domain = d3.extent(
ydomain_tmp.concat(ydescs[ydesc].domain));
} else {
ydescs[ydesc] = {};
ydescs[ydesc].indices = [mi];
ydescs[ydesc].domain = ydomain_tmp;
}
}
var xlabels = Object.keys(xdescs);
var ylabels = Object.keys(ydescs);
if (xlabels.length > 2) {
throw {
name: 'ModelFormatError',
message: 'too many different x values'
};
}
if (ylabels.length > 2) {
throw {
name: 'ModelFormatError',
message: 'too many different y values'
};
}
/* TODO: add possibility to use logarithmic scales (from model?) */
var xscales = [d3.scale.linear()];
var yscales = [d3.scale.linear()];
if (xlabels.length === 2) {
margin.bottom = 100;
xscales.push(d3.scale.linear());
}
if (ylabels.length === 2) {
margin.right = 60;
yscales.push(d3.scale.linear());
}
this.margin(margin);
var xAxis = [],
yAxis = [];
var th = this;
xlabels.map(function (xl, i) {
var xdesc = xdescs[xl];
xscales[i]
.domain(xdesc.domain)
.range([0, th.width()]);
xdesc.indices.map(function (index) {
th.view.adapter().xscale(index, xscales[i]);
});
xAxis.push(d3.svg.axis().scale(xscales[i]));
});
ylabels.map(function (yl, i) {
var ydesc = ydescs[yl];
yscales[i]
.domain(ydesc.domain)
.range([th.height(), 0]);
ydesc.indices.map(function (index) {
th.view.adapter().yscale(index, yscales[i]);
});
yAxis.push(d3.svg.axis().scale(yscales[i]));
});
var xlabel_config = [{
label: xlabels[0],
transformation: 'translate(0, ' + this.height() + ')',
labelpos: {
x: 0.5 * this.width(), y: 35,
dx: 0, dy: 0,
transformation: null,
anchor: 'middle'
},
axis: xAxis[0].orient('bottom')
}];
var ylabel_config = [{
label: ylabels[0],
transformation: null,
labelpos: {
x: 0.5 * this.height(), y: 35,
dx: 0, dy: '.71em',
transformation: 'rotate(90)',
anchor: 'middle'
},
axis: yAxis[0].orient('left')
}];
if (xlabels.length === 2) {
xlabel_config.push({
label: xlabels[1],
transformation: 'translate(0, ' + (this.height() + 40) + ')',
labelpos: {
x: 0.5 * this.width(), y: 25,
dx: 0, dy: '.71em',
transformation: null,
anchor: 'middle'
},
axis: xAxis[1].orient('bottom')
});
xlabel_config[0].labelpos.y = 25;
}
if (ylabels.length === 2) {
ylabel_config.push({
label: ylabels[1],
transformation: 'translate(' + this.width() + ', 0)',
labelpos: {
x: 0.5 * this.height(), y: -35,
dx: 0, dy: '-.71em',
transformation: 'rotate(90)',
anchor: 'middle'
},
axis: yAxis[1].orient('right')
});
}
this.xlabel_config = xlabel_config;
this.ylabel_config = ylabel_config;
};
Axis2d.prototype.margin = function(margin) {
if (!arguments.length) {
var em;
if (this.extra_margin !== undefined) {
em = this.extra_margin;
} else {
em = {top: 0, left: 0, right: 0, bottom: 0};
}
var m = this.margin_;
var mm = {
top: m.top + em.top, left: m.left + em.left,
right: m.right + em.right, bottom: m.bottom + em.bottom
};
return mm;
}
this.margin_ = margin;
return this;
};
Axis2d.prototype.draw_axis_label = function(classnames, config) {
var axis = this.draw_area;
var axisC = axis.selectAll('.' + classnames.join('.'))
.data(config);
var axis_enter = axisC.enter()
.append("g")
.attr("class", function (_, i) { return classnames.concat(['ax' + i]).join(' '); })
.append("text") // axis label
.attr("class", "label");
axisC.attr("transform", function (d) {return d.transformation; })
.each(function (_, i) {
d3.select(this).call(config[i].axis);
})
.select("text")
.attr("transform", function(d) { return d.labelpos.transformation; })
.attr("x", function(d) { return d.labelpos.x; })
.attr("y", function(d) { return d.labelpos.y; })
.attr("dy", function(d) { return d.labelpos.dy; })
.attr("dx", function(d) { return d.labelpos.dx; })
.style("text-anchor", function (d) { return d.labelpos.anchor; });
axisC.select(".label")
.text(function (d) { return d.label; });
axisC.exit()
.remove();
};
Axis2d.prototype.update = function() {
this.compute_axes();
this.display();
};
Axis2d.prototype.display = function() {
this.svg = this.container.selectAll('svg')
.data([this]);
this.svg.enter()
.append('svg')
.attr('width', function(d) { return d.view.width(); })
.attr('height', function(d) { return d.view.height(); });
this.draw_area = this.svg.selectAll(".drawing_area")
.data([this]);
var margin = this.margin();
var draw_area_enter = this.draw_area.enter()
.append('g')
.attr('class', 'drawing_area')
.attr('transform', function (d) {
return 'translate({left},{top})'.format(d.margin());
});
this.draw_axis_label(['x', 'axis'], this.xlabel_config);
this.draw_axis_label(['y', 'axis'], this.ylabel_config);
};
module.exports = Axis2d;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./utils/string_extension.js":8}],2:[function(require,module,exports){
// This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/).
var colorbrewer = {YlGn: {
3: ["#f7fcb9","#addd8e","#31a354"],
4: ["#ffffcc","#c2e699","#78c679","#238443"],
5: ["#ffffcc","#c2e699","#78c679","#31a354","#006837"],
6: ["#ffffcc","#d9f0a3","#addd8e","#78c679","#31a354","#006837"],
7: ["#ffffcc","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#005a32"],
8: ["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#005a32"],
9: ["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"]
},YlGnBu: {
3: ["#edf8b1","#7fcdbb","#2c7fb8"],
4: ["#ffffcc","#a1dab4","#41b6c4","#225ea8"],
5: ["#ffffcc","#a1dab4","#41b6c4","#2c7fb8","#253494"],
6: ["#ffffcc","#c7e9b4","#7fcdbb","#41b6c4","#2c7fb8","#253494"],
7: ["#ffffcc","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#0c2c84"],
8: ["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#0c2c84"],
9: ["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"]
},GnBu: {
3: ["#e0f3db","#a8ddb5","#43a2ca"],
4: ["#f0f9e8","#bae4bc","#7bccc4","#2b8cbe"],
5: ["#f0f9e8","#bae4bc","#7bccc4","#43a2ca","#0868ac"],
6: ["#f0f9e8","#ccebc5","#a8ddb5","#7bccc4","#43a2ca","#0868ac"],
7: ["#f0f9e8","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#08589e"],
8: ["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#08589e"],
9: ["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"]
},BuGn: {
3: ["#e5f5f9","#99d8c9","#2ca25f"],
4: ["#edf8fb","#b2e2e2","#66c2a4","#238b45"],
5: ["#edf8fb","#b2e2e2","#66c2a4","#2ca25f","#006d2c"],
6: ["#edf8fb","#ccece6","#99d8c9","#66c2a4","#2ca25f","#006d2c"],
7: ["#edf8fb","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#005824"],
8: ["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#005824"],
9: ["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"]
},PuBuGn: {
3: ["#ece2f0","#a6bddb","#1c9099"],
4: ["#f6eff7","#bdc9e1","#67a9cf","#02818a"],
5: ["#f6eff7","#bdc9e1","#67a9cf","#1c9099","#016c59"],
6: ["#f6eff7","#d0d1e6","#a6bddb","#67a9cf","#1c9099","#016c59"],
7: ["#f6eff7","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016450"],
8: ["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016450"],
9: ["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"]
},PuBu: {
3: ["#ece7f2","#a6bddb","#2b8cbe"],
4: ["#f1eef6","#bdc9e1","#74a9cf","#0570b0"],
5: ["#f1eef6","#bdc9e1","#74a9cf","#2b8cbe","#045a8d"],
6: ["#f1eef6","#d0d1e6","#a6bddb","#74a9cf","#2b8cbe","#045a8d"],
7: ["#f1eef6","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#034e7b"],
8: ["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#034e7b"],
9: ["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"]
},BuPu: {
3: ["#e0ecf4","#9ebcda","#8856a7"],
4: ["#edf8fb","#b3cde3","#8c96c6","#88419d"],
5: ["#edf8fb","#b3cde3","#8c96c6","#8856a7","#810f7c"],
6: ["#edf8fb","#bfd3e6","#9ebcda","#8c96c6","#8856a7","#810f7c"],
7: ["#edf8fb","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#6e016b"],
8: ["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#6e016b"],
9: ["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"]
},RdPu: {
3: ["#fde0dd","#fa9fb5","#c51b8a"],
4: ["#feebe2","#fbb4b9","#f768a1","#ae017e"],
5: ["#feebe2","#fbb4b9","#f768a1","#c51b8a","#7a0177"],
6: ["#feebe2","#fcc5c0","#fa9fb5","#f768a1","#c51b8a","#7a0177"],
7: ["#feebe2","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177"],
8: ["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177"],
9: ["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"]
},PuRd: {
3: ["#e7e1ef","#c994c7","#dd1c77"],
4: ["#f1eef6","#d7b5d8","#df65b0","#ce1256"],
5: ["#f1eef6","#d7b5d8","#df65b0","#dd1c77","#980043"],
6: ["#f1eef6","#d4b9da","#c994c7","#df65b0","#dd1c77","#980043"],
7: ["#f1eef6","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#91003f"],
8: ["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#91003f"],
9: ["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"]
},OrRd: {
3: ["#fee8c8","#fdbb84","#e34a33"],
4: ["#fef0d9","#fdcc8a","#fc8d59","#d7301f"],
5: ["#fef0d9","#fdcc8a","#fc8d59","#e34a33","#b30000"],
6: ["#fef0d9","#fdd49e","#fdbb84","#fc8d59","#e34a33","#b30000"],
7: ["#fef0d9","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#990000"],
8: ["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#990000"],
9: ["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"]
},YlOrRd: {
3: ["#ffeda0","#feb24c","#f03b20"],
4: ["#ffffb2","#fecc5c","#fd8d3c","#e31a1c"],
5: ["#ffffb2","#fecc5c","#fd8d3c","#f03b20","#bd0026"],
6: ["#ffffb2","#fed976","#feb24c","#fd8d3c","#f03b20","#bd0026"],
7: ["#ffffb2","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#b10026"],
8: ["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#b10026"],
9: ["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"]
},YlOrBr: {
3: ["#fff7bc","#fec44f","#d95f0e"],
4: ["#ffffd4","#fed98e","#fe9929","#cc4c02"],
5: ["#ffffd4","#fed98e","#fe9929","#d95f0e","#993404"],
6: ["#ffffd4","#fee391","#fec44f","#fe9929","#d95f0e","#993404"],
7: ["#ffffd4","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#8c2d04"],
8: ["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#8c2d04"],
9: ["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"]
},Purples: {
3: ["#efedf5","#bcbddc","#756bb1"],
4: ["#f2f0f7","#cbc9e2","#9e9ac8","#6a51a3"],
5: ["#f2f0f7","#cbc9e2","#9e9ac8","#756bb1","#54278f"],
6: ["#f2f0f7","#dadaeb","#bcbddc","#9e9ac8","#756bb1","#54278f"],
7: ["#f2f0f7","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#4a1486"],
8: ["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#4a1486"],
9: ["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"]
},Blues: {
3: ["#deebf7","#9ecae1","#3182bd"],
4: ["#eff3ff","#bdd7e7","#6baed6","#2171b5"],
5: ["#eff3ff","#bdd7e7","#6baed6","#3182bd","#08519c"],
6: ["#eff3ff","#c6dbef","#9ecae1","#6baed6","#3182bd","#08519c"],
7: ["#eff3ff","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#084594"],
8: ["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#084594"],
9: ["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"]
},Greens: {
3: ["#e5f5e0","#a1d99b","#31a354"],
4: ["#edf8e9","#bae4b3","#74c476","#238b45"],
5: ["#edf8e9","#bae4b3","#74c476","#31a354","#006d2c"],
6: ["#edf8e9","#c7e9c0","#a1d99b","#74c476","#31a354","#006d2c"],
7: ["#edf8e9","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#005a32"],
8: ["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#005a32"],
9: ["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"]
},Oranges: {
3: ["#fee6ce","#fdae6b","#e6550d"],
4: ["#feedde","#fdbe85","#fd8d3c","#d94701"],
5: ["#feedde","#fdbe85","#fd8d3c","#e6550d","#a63603"],
6: ["#feedde","#fdd0a2","#fdae6b","#fd8d3c","#e6550d","#a63603"],
7: ["#feedde","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#8c2d04"],
8: ["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#8c2d04"],
9: ["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"]
},Reds: {
3: ["#fee0d2","#fc9272","#de2d26"],
4: ["#fee5d9","#fcae91","#fb6a4a","#cb181d"],
5: ["#fee5d9","#fcae91","#fb6a4a","#de2d26","#a50f15"],
6: ["#fee5d9","#fcbba1","#fc9272","#fb6a4a","#de2d26","#a50f15"],
7: ["#fee5d9","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#99000d"],
8: ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#99000d"],
9: ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"]
},Greys: {
3: ["#f0f0f0","#bdbdbd","#636363"],
4: ["#f7f7f7","#cccccc","#969696","#525252"],
5: ["#f7f7f7","#cccccc","#969696","#636363","#252525"],
6: ["#f7f7f7","#d9d9d9","#bdbdbd","#969696","#636363","#252525"],
7: ["#f7f7f7","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525"],
8: ["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525"],
9: ["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"]
},PuOr: {
3: ["#f1a340","#f7f7f7","#998ec3"],
4: ["#e66101","#fdb863","#b2abd2","#5e3c99"],
5: ["#e66101","#fdb863","#f7f7f7","#b2abd2","#5e3c99"],
6: ["#b35806","#f1a340","#fee0b6","#d8daeb","#998ec3","#542788"],
7: ["#b35806","#f1a340","#fee0b6","#f7f7f7","#d8daeb","#998ec3","#542788"],
8: ["#b35806","#e08214","#fdb863","#fee0b6","#d8daeb","#b2abd2","#8073ac","#542788"],
9: ["#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788"],
10: ["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],
11: ["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"]
},BrBG: {
3: ["#d8b365","#f5f5f5","#5ab4ac"],
4: ["#a6611a","#dfc27d","#80cdc1","#018571"],
5: ["#a6611a","#dfc27d","#f5f5f5","#80cdc1","#018571"],
6: ["#8c510a","#d8b365","#f6e8c3","#c7eae5","#5ab4ac","#01665e"],
7: ["#8c510a","#d8b365","#f6e8c3","#f5f5f5","#c7eae5","#5ab4ac","#01665e"],
8: ["#8c510a","#bf812d","#dfc27d","#f6e8c3","#c7eae5","#80cdc1","#35978f","#01665e"],
9: ["#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e"],
10: ["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],
11: ["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"]
},PRGn: {
3: ["#af8dc3","#f7f7f7","#7fbf7b"],
4: ["#7b3294","#c2a5cf","#a6dba0","#008837"],
5: ["#7b3294","#c2a5cf","#f7f7f7","#a6dba0","#008837"],
6: ["#762a83","#af8dc3","#e7d4e8","#d9f0d3","#7fbf7b","#1b7837"],
7: ["#762a83","#af8dc3","#e7d4e8","#f7f7f7","#d9f0d3","#7fbf7b","#1b7837"],
8: ["#762a83","#9970ab","#c2a5cf","#e7d4e8","#d9f0d3","#a6dba0","#5aae61","#1b7837"],
9: ["#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837"],
10: ["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],
11: ["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"]
},PiYG: {
3: ["#e9a3c9","#f7f7f7","#a1d76a"],
4: ["#d01c8b","#f1b6da","#b8e186","#4dac26"],
5: ["#d01c8b","#f1b6da","#f7f7f7","#b8e186","#4dac26"],
6: ["#c51b7d","#e9a3c9","#fde0ef","#e6f5d0","#a1d76a","#4d9221"],
7: ["#c51b7d","#e9a3c9","#fde0ef","#f7f7f7","#e6f5d0","#a1d76a","#4d9221"],
8: ["#c51b7d","#de77ae","#f1b6da","#fde0ef","#e6f5d0","#b8e186","#7fbc41","#4d9221"],
9: ["#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221"],
10: ["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],
11: ["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"]
},RdBu: {
3: ["#ef8a62","#f7f7f7","#67a9cf"],
4: ["#ca0020","#f4a582","#92c5de","#0571b0"],
5: ["#ca0020","#f4a582","#f7f7f7","#92c5de","#0571b0"],
6: ["#b2182b","#ef8a62","#fddbc7","#d1e5f0","#67a9cf","#2166ac"],
7: ["#b2182b","#ef8a62","#fddbc7","#f7f7f7","#d1e5f0","#67a9cf","#2166ac"],
8: ["#b2182b","#d6604d","#f4a582","#fddbc7","#d1e5f0","#92c5de","#4393c3","#2166ac"],
9: ["#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac"],
10: ["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],
11: ["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"]
},RdGy: {
3: ["#ef8a62","#ffffff","#999999"],
4: ["#ca0020","#f4a582","#bababa","#404040"],
5: ["#ca0020","#f4a582","#ffffff","#bababa","#404040"],
6: ["#b2182b","#ef8a62","#fddbc7","#e0e0e0","#999999","#4d4d4d"],
7: ["#b2182b","#ef8a62","#fddbc7","#ffffff","#e0e0e0","#999999","#4d4d4d"],
8: ["#b2182b","#d6604d","#f4a582","#fddbc7","#e0e0e0","#bababa","#878787","#4d4d4d"],
9: ["#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d"],
10: ["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],
11: ["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"]
},RdYlBu: {
3: ["#fc8d59","#ffffbf","#91bfdb"],
4: ["#d7191c","#fdae61","#abd9e9","#2c7bb6"],
5: ["#d7191c","#fdae61","#ffffbf","#abd9e9","#2c7bb6"],
6: ["#d73027","#fc8d59","#fee090","#e0f3f8","#91bfdb","#4575b4"],
7: ["#d73027","#fc8d59","#fee090","#ffffbf","#e0f3f8","#91bfdb","#4575b4"],
8: ["#d73027","#f46d43","#fdae61","#fee090","#e0f3f8","#abd9e9","#74add1","#4575b4"],
9: ["#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4"],
10: ["#a50026","#d73027","#f46d43","#fdae61","#fee090","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],
11: ["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"]
},Spectral: {
3: ["#fc8d59","#ffffbf","#99d594"],
4: ["#d7191c","#fdae61","#abdda4","#2b83ba"],
5: ["#d7191c","#fdae61","#ffffbf","#abdda4","#2b83ba"],
6: ["#d53e4f","#fc8d59","#fee08b","#e6f598","#99d594","#3288bd"],
7: ["#d53e4f","#fc8d59","#fee08b","#ffffbf","#e6f598","#99d594","#3288bd"],
8: ["#d53e4f","#f46d43","#fdae61","#fee08b","#e6f598","#abdda4","#66c2a5","#3288bd"],
9: ["#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd"],
10: ["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],
11: ["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"]
},RdYlGn: {
3: ["#fc8d59","#ffffbf","#91cf60"],
4: ["#d7191c","#fdae61","#a6d96a","#1a9641"],
5: ["#d7191c","#fdae61","#ffffbf","#a6d96a","#1a9641"],
6: ["#d73027","#fc8d59","#fee08b","#d9ef8b","#91cf60","#1a9850"],
7: ["#d73027","#fc8d59","#fee08b","#ffffbf","#d9ef8b","#91cf60","#1a9850"],
8: ["#d73027","#f46d43","#fdae61","#fee08b","#d9ef8b","#a6d96a","#66bd63","#1a9850"],
9: ["#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850"],
10: ["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],
11: ["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"]
},Accent: {
3: ["#7fc97f","#beaed4","#fdc086"],
4: ["#7fc97f","#beaed4","#fdc086","#ffff99"],
5: ["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0"],
6: ["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f"],
7: ["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17"],
8: ["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"]
},Dark2: {
3: ["#1b9e77","#d95f02","#7570b3"],
4: ["#1b9e77","#d95f02","#7570b3","#e7298a"],
5: ["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e"],
6: ["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02"],
7: ["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d"],
8: ["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"]
},Paired: {
3: ["#a6cee3","#1f78b4","#b2df8a"],
4: ["#a6cee3","#1f78b4","#b2df8a","#33a02c"],
5: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99"],
6: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c"],
7: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f"],
8: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00"],
9: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6"],
10: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a"],
11: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99"],
12: ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"]
},Pastel1: {
3: ["#fbb4ae","#b3cde3","#ccebc5"],
4: ["#fbb4ae","#b3cde3","#ccebc5","#decbe4"],
5: ["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6"],
6: ["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc"],
7: ["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd"],
8: ["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec"],
9: ["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]
},Pastel2: {
3: ["#b3e2cd","#fdcdac","#cbd5e8"],
4: ["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4"],
5: ["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9"],
6: ["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae"],
7: ["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc"],
8: ["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"]
},Set1: {
3: ["#e41a1c","#377eb8","#4daf4a"],
4: ["#e41a1c","#377eb8","#4daf4a","#984ea3"],
5: ["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00"],
6: ["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33"],
7: ["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628"],
8: ["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf"],
9: ["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"]
},Set2: {
3: ["#66c2a5","#fc8d62","#8da0cb"],
4: ["#66c2a5","#fc8d62","#8da0cb","#e78ac3"],
5: ["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854"],
6: ["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f"],
7: ["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494"],
8: ["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"]
},Set3: {
3: ["#8dd3c7","#ffffb3","#bebada"],
4: ["#8dd3c7","#ffffb3","#bebada","#fb8072"],
5: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3"],
6: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462"],
7: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69"],
8: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5"],
9: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9"],
10: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd"],
11: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5"],
12: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"]
}};
module.exports = colorbrewer;
},{}],3:[function(require,module,exports){
(function (global){
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
var d3mvc_View = require('./view.js');
var d3mvc_ModelAdapter = require('./modeladapter.js');
var d3mvc = {
version: '0.2.0'
};
function make_view(model, container_id) {
var container = d3.select(container_id);
if (container.size() !== 1) {
throw {
"name": "ValueError",
"message": "The selector " + container_id + " does not exist in the DOM"
};
}
var view = new d3mvc_View(model, container);
return view;
}
d3mvc.make_view = make_view;
d3mvc.View = d3mvc_View;
d3mvc.ModelAdapter2d = d3mvc_ModelAdapter;
module.exports = d3mvc;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./modeladapter.js":6,"./view.js":10}],4:[function(require,module,exports){
(function (global){
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
function Legend2dView(view, configuration) {
this.view = view;
this.xshift = 0;
this.yshift = 0;
this.outer_margin = {top: 0, left: 0, right: 0, bottom: 0};
this.entry_height = 15;
this.legend_margin = 5;
this.configuration = configuration;
this.configure(configuration);
}
Legend2dView.prototype = {};
Legend2dView.prototype.configure = function(configuration) {
if (configuration.hasOwnProperty('pos')) {
this.pos = configuration.pos;
} else {
this.pos = 'outer right';
}
this.configure_position();
};
Legend2dView.prototype.configure_position = function() {
if (this.pos === 'outer right' || this.pos === 'default') {
this.outer_margin.right = 110;
this.xshift = this.view.width() - (this.outer_margin.right + 5);
this.yshift = 0;
} else {
throw {
name: 'ValueError',
message: 'Invalid legend position: ' + this.pos
};
}
};
Legend2dView.prototype.axis_margin = function() {
return this.outer_margin;
};
Legend2dView.prototype.legend_icon = function (unused1, unused2) {
return undefined;
};
Legend2dView.prototype.display = function () {
var svg = this.view.axis.svg;
var view = this.view;
var adapter = view.adapter();
var legend_box = svg.selectAll('.legend')
.data([1]);
var mouseover_func = function (d) {
d3.selectAll('.drawing_area .' + d.key)
.classed('highlight', true);
d3.select(this)
.classed('highlight', true);
};
var mouseleave_func = function (d) {
d3.selectAll('.drawing_area .' + d.key)
.classed('highlight', false);
d3.select(this)
.classed('highlight', false);
};
var eh = this.entry_height,
lm = this.legend_margin;
legend_box.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', "translate(" + this.xshift + "," + this.yshift + ")")
.append('text')
.attr('class', 'title')
.attr('dy', '.71em')
.attr('transform', 'translate(18, ' + lm + ')')
.style('font-weight', 'bold')
.text('Legend');
var entries = svg.select('.legend').selectAll('.entry')
.data(adapter.data(), function (d) { return d.key; });
var entries_enter = entries.enter()
.append('g')
.attr('class', 'entry')
.attr('transform',
function (d, i) {
return "translate(0, " + (eh * (i+1) + lm) + ")";
})
.on('mouseover', mouseover_func)
.on('mouseleave', mouseleave_func);
entries_enter
.append('text')
.attr('x', 18)
.attr('dy', '.71em');
entries_enter
.append('g')
.attr('class', 'icon');
entries.select('.icon')
.each(function (d, i) {
view.legend_icon(i, d3.select(this));
});
entries.select('text')
.text(function (d) { return d.name; });
entries.exit()
.remove();
try {
var rect = svg.select('.legend').node().getBBox();
var offset = 2;
var pathinfo = [
{x: rect.x-offset, y: rect.y },
{x: rect.x+offset + rect.width, y: rect.y},
{x: rect.x+offset + rect.width, y: rect.y + rect.height },
{x: rect.x-offset, y: rect.y + rect.height},
{x: rect.x-offset, y: rect.y },
];
var d3line = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
var legend_rect = legend_box.selectAll('.legend-box')
.data([pathinfo]);
legend_rect.enter()
.append('path')
.attr('class', 'legend-box')
.style('stroke', 'black')
.style('stroke-width', '1')
.style('fill', 'none');
legend_rect
.attr('d', function (d) { return d3line(d); });
legend_rect.exit().remove();
} catch (ignore) {}
};
Legend2dView.prototype.update = function() {
this.configure(this.configuration);
this.display();
};
module.exports = Legend2dView;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],5:[function(require,module,exports){
(function (global){
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
var Axis2d = require('./axis2d.js');
function Lines2dView(view, configuration) {
this.view = view;
this.configuration = configuration;
this.configure(configuration);
}
Lines2dView.prototype = {};
Lines2dView.prototype.configure = function(configuration) {
this.interpolation = configuration.interpolation || 'linear';
this.color = configuration.color || this.view.color_scale();
};
Lines2dView.prototype.legend_icon = function(index, selection) {
var color = this.color;
color.domain(this.view.get_names());
var name = this.view.adapter().name(index);
var c = color(name);
selection.append('path')
.attr('class', 'line ' + name)
.style('stroke', c)
.attr('d', 'M0,3L14,3');
};
Lines2dView.prototype.display = function () {
this.view.axis.update();
var svg = this.view.axis.draw_area;
var adapter = this.view.adapter();
var color = this.color;
color.domain(this.view.get_names());
var data = adapter.data();
var line = d3.svg.line()
.interpolate(this.interpolation)
.x(function (d) { return d[0]; })
.y(function (d) { return d[1]; });
var lines = svg.selectAll('.line')
.data(data, function(d) { return d.key; });
/* one graph for each model */
// enter
lines.enter()
.append('path');
// enter and update
lines.attr('class', function(d) { return 'line ' + d.key; })
.transition()
.duration(300)
.style('stroke', function(d) { return color(d.name); })
.attr('d', function(d) {
var ds = d3.transpose([d.x.map(d.xscale), d.y.map(d.yscale)]);
return line(ds);
});
// exit
lines.exit()
.remove();
};
Lines2dView.prototype.update = function() {
this.configure(this.configuration);
this.display();
};
module.exports = Lines2dView;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./axis2d.js":1}],6:[function(require,module,exports){
(function (global){
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
var utils = require('./utils/utils.js');
function ModelAdapter2d(model) {
this.model = model;
this.xscales_ = [];
this.yscales_ = [];
this.properties_ = [];
}
ModelAdapter2d.prototype = {};
ModelAdapter2d.prototype.add_property = function(properties) {
if (properties !== undefined) {
var default_error = function(p) {
var error = function(d, i) {
throw {
name: 'RuntimeError',
message: 'Model data is missing the property ' + p
};
};
return error;
};
for (var i = 0; i < properties.length; ++i) {
var property;
if (typeof(properties[i]) === 'string') {
property = {
'key': properties[i],
'default': default_error(properties[i])
};
} else {
property = properties[i];
}
this.properties_.push(property);
}
}
};
ModelAdapter2d.prototype.name = function(i) {
return this.model[i].name || 'plot' + i;
};
ModelAdapter2d.prototype.x = function(i) {
try {
return this.model[i].data[0];
} catch(_) {
return [];
}
};
ModelAdapter2d.prototype.y = function(i) {
try {
return this.model[i].data[1];
} catch(_) {
return [];
}
};
ModelAdapter2d.prototype.xscale = function(i, scale) {
if (arguments.length === 1) {
xscale = this.xscales_[i];
if (xscale === undefined) {
return function(d) { return []; };
}
else {
return xscale;
}
}
this.xscales_[i] = scale;
};
ModelAdapter2d.prototype.yscale = function(i, scale) {
if (arguments.length == 1) {
yscale = this.yscales_[i];
if (yscale === undefined) {
return function(d) { return []; };
}
else {
return yscale;
}
}
this.yscales_[i] = scale;
};
ModelAdapter2d.prototype.xdesc = function(i) {
var alternative_xdesc = this.model[0].xdesc || 'x';
return this.model[i].xdesc || alternative_xdesc;
};
ModelAdapter2d.prototype.ydesc = function(i) {
var alternative_ydesc = this.model[0].ydesc || 'y';
return this.model[i].ydesc || alternative_ydesc;
};
ModelAdapter2d.prototype.xdomain = function(i) {
return this.model[i].xdomain || d3.extent(this.x(i));
};
ModelAdapter2d.prototype.ydomain = function(i) {
return this.model[i].ydomain || d3.extent(this.y(i));
};
ModelAdapter2d.prototype.data = function() {
// TODO: cache data
var data = [];
for (var i=0; i < this.model.length; ++i) {
var elem = {
xdesc: this.xdesc(i), ydesc: this.ydesc(i),
name: this.name(i),
key: utils.string_to_slug(this.name(i)),
x: this.x(i), y: this.y(i),
xscale: this.xscale(i), yscale: this.yscale(i)
};
for (var j=0; j < this.properties_.length; ++j) {
elem[this.properties_[j].key] = this.model[i][this.properties_[j].key] ||
this.properties_[j].default(this.model[i], i);
}
data.push(elem);
}
return data;
};
module.exports = ModelAdapter2d;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./utils/utils.js":9}],7:[function(require,module,exports){
(function (global){
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
function Scatter2dView(view, configuration) {
this.view = view;
this.configuration = configuration;
this.configure(configuration);
}
Scatter2dView.prototype = {};
Scatter2dView.prototype.configure = function(configuration) {
this.color = configuration.color || this.view.color_scale();
};
Scatter2dView.prototype.legend_icon = function(index, selection) {
var color = this.color;
color.domain(this.view.get_names());
var name = this.view.adapter().name(index);
var c = color(name);
selection.append('circle')
.attr('class', 'circle ' + name)
.style('fill', c)
.attr('r', 3)
.attr('cx', 8)
.attr('cy', 3);
};
Scatter2dView.prototype.display = function () {
this.view.axis.update();
var svg = this.view.axis.draw_area;
var adapter = this.view.adapter();
var color = this.color;
color.domain(this.view.get_names());
var data = adapter.data();
var lines = svg.selectAll('.circle_container')
.data(data, function(d) { return d.key; });
/* one graph for each model */
// enter
lines.enter()
.append('g');
lines.attr('class', function(d) { return 'circle_container ' + d.key; })
.style('fill', function (d) { return color(d.name); });
// update not necessary
// exit
lines.exit()
.remove();
/* plot the graphs */
var scatters = lines.selectAll('.circle')
.data(function (d) { return d3.transpose([d.x.map(d.xscale), d.y.map(d.yscale)]); });
// enter
scatters.enter()
.append('circle')
.attr('class', 'circle');
// update and enter
scatters
.transition()
.duration(300)
.attr('r', 3)
.attr('cx', function(d) { return d[0]; })
.attr('cy', function(d) { return d[1]; });
// exit
scatters.exit()
.remove();
};
Scatter2dView.prototype.update = function() {
this.configure(this.configuration);
this.display();
};
module.exports = Scatter2dView;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],8:[function(require,module,exports){
if (!String.prototype.format) {
String.prototype.format = function() {
var str = this.toString();
if (!arguments.length)
return str;
var args = typeof arguments[0];
args = (("string" == args || "number" == args) ? arguments : arguments[0]);
for (var arg in args)
str = str.replace(RegExp("\\{" + arg + "\\}", "gi"), args[arg]);
return str;
};
}
module.exports = String;
},{}],9:[function(require,module,exports){
module.exports = {};
module.exports.get_unique = function(arr) {
var u = {}, a = [];
var l = arr.length;
var i = 0;
for(i = 0; i < l; ++i) {
if(u.hasOwnProperty(arr[i])) {
continue;
}
a.push(arr[i]);
u[arr[i]] = 1;
}
return a;
};
module.exports.string_to_slug = function(str) {
// Separate camel-cased words with a space for later processing.
str = str.replace(/[A-Z]/g, function(s){
return " " + s;
});
str = str.toLowerCase();
// remove accents, swap ñ for n, etc
var from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;",
to = "aaaaeeeeiiiioooouuuunc------";
for (var i=0, l=from.length ; i<l ; i++) {
str = str.replace(from[i], to[i]);
}
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
.replace(/\s+/g, '-') // collapse whitespace and replace by -
.replace(/-+/g, '-'); // collapse dashes
// Trim leading and trailing whitespace and dashes.
str = str.replace(/^[\s|-]+|[\s|-]+$/g, '');
return str;
};
/* vim: set sw=4: */
},{}],10:[function(require,module,exports){
(function (global){
var String = require('./utils/string_extension.js');
var colorbrewer = require('./colorbrewer.js');
var utils = require('./utils/utils.js');
var Lines2dView = require('./lines2d.js');
var Scatter2dView = require('./scatter2d.js');
var LegendView = require('./legend.js');
var Axis2d = require('./axis2d.js');
var ModelAdapter2d = require('./modeladapter.js');
var d3 = (typeof window !== "undefined" ? window.d3 : typeof global !== "undefined" ? global.d3 : null);
function View(model, container, controllers) {
this.container = container;
this.model = model;
this.controllers = controllers;
this.axis = undefined;
this.axis_type = undefined;
this.adapter_type = undefined;
this.adapter_ = undefined;
this.axis_options = [];
this.config_chain = [];
this.config_ = [];
this.displayed_ = false;
this.configure();
}
View.prototype = {};
View.prototype.configure = function() {
if (this.model.length < 12) {
this.color = d3.scale.ordinal().range(colorbrewer.Paired[Math.max(3, this.model.length)]);
} else {
this.color = d3.scale.category20();
}
};
View.prototype.adapter = function() {
if (!this.is_configured()) { // || this.adapter_.model !== this.model) {
throw {
name: 'RuntimeError',
message: 'Model adapter was not configured yet...'
// message: 'model wrapped in adapter changed! That should not happen!'
};
}
return this.adapter_;
};
View.prototype.configure_view = function(configuration) {
this.color = configuration.color || this.color;
};
View.prototype.addConfiguration = function(configuration) {
this.config_.push(configuration);
var type = configuration.type;
var operation;
var adapter_type;
var adapter_options;
var axis_type;
var axis_options;
if (type === 'view') {
this.configure_view(configuration);
return;
}
if (type === 'lines') {
operation = new Lines2dView(this, configuration);
axis_type = Axis2d;
adapter_type = ModelAdapter2d;
}
else if(type === 'scatter') {
operation = new Scatter2dView(this, configuration);
axis_type = Axis2d;
adapter_type = ModelAdapter2d;
}
else if(type === 'legend') {
operation = new LegendView(this, configuration);
axis_type = this.axis_type;
axis_options = {extra_margin: operation.axis_margin()};
adapter_type = ModelAdapter2d;
}
else {
throw {
name: "ValueError",
message: "The given view operation " + type + " is invalid."
};
}
if (this.axis_type === undefined) {
this.axis_type = axis_type;
} else if(this.axis_type !== axis_type) {
throw {
name: "ValueError",
message: "You cannot combine incompatible view operations.\n" +
configuration + " is incompatible with other settings."
};
}
// initialize model adapter
if (this.adapter_type === undefined) {
this.adapter_type = adapter_type;
this.adapter_ = new adapter_type(this.model);
} else if(this.adapter_type !== adapter_type) {
throw {
name: "ValueError",
message: "You cannot combine incompatible view operations.\n" +
configuration + " is incompatible with other settings."
};
}
this.adapter_.add_property(adapter_options);
if (axis_options !== undefined) {
this.axis_options.push(axis_options);
}
this.config_chain.push(operation);
return this;
};
View.prototype.color_scale = function() {
return this.color;
};
View.prototype.is_configured = function() {
return this.config_chain.length > 0;
};
View.prototype.is_displayed = function() {
return this.displayed_;
};
View.prototype.config = function(c) {
if (!arguments.length) {
return this.config_;
}
this.config_ = [];
this.config_chain = [];
var ii = 0;
for (; ii < c.length; ii++) {
this.addConfiguration(c[ii]);
}
return this;
};
View.prototype.get_names = function() {
if (! this.is_configured()) {
throw {
'name': 'RuntimeError',
'message': 'requested names of uninitialized view'
};
}
var name_list = this.adapter().data().map(
function (d) { return d.name; });
return utils.get_unique(name_list);
};
View.prototype.display = function() {
if (! this.is_configured()) {
throw {
'name': 'RuntimeError',
'message': 'requested display of uninitialized view'
};
}
this.displayed_ = true;
this.axis = new this.axis_type(this, this.axis_options);
this.axis.display();
this.config_chain.map(function(op) { op.display(); });
return this;
};
View.prototype.update = function(model) {
if (arguments.length === 1) {
this.model = model;
this.adapter_ = new this.adapter_type(model);
}
this.configure();
this.axis.update();
this.config_chain.map(function(op) { op.update(); });
return this;
};
View.prototype.hide = function(do_hide) {
if (!arguments.length || do_hide) {
this.container.style('display', 'none');
}
else {
this.container.style('display', 'block');
}
return this;
};
View.prototype.width = function() {
return Math.max(parseInt(this.container.style('width'), 10) || 100, 100);
};
View.prototype.height = function() {
var w = Math.min(100, this.width());
return Math.max(parseInt(this.container.style('height'), 10) || 100, w);
};
View.prototype.highlight_data_block = function(index) {
throw { name: "NotImplementedError" };
};
View.prototype.legend_icon = function(index, selection) {
this.config_chain.map(function(op) { op.legend_icon(index, selection); });
};
module.exports = View;
/* vim: set sw=4: */
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./axis2d.js":1,"./colorbrewer.js":2,"./legend.js":4,"./lines2d.js":5,"./modeladapter.js":6,"./scatter2d.js":7,"./utils/string_extension.js":8,"./utils/utils.js":9}]},{},[3])(3)
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.axis path, .axis line {
fill: none;
shape-rendering: crispedges;
stroke: black;
stroke-linecap: round;
stroke-width: 2px;
}
.axis .tick line {
stroke-width: 1px;
}
path.line.highlight {
stroke-width: 4px;
}
path.line {
fill: none;
stroke-width: 2px;
}
.circle_container.highlight circle {
fill: inherit;
stroke-width: 2px;
stroke: orange;
}
svg circle {
fill: inherit;
stroke: none;
}
#plot {
width: 500px;
height: 400px;
float: left;
}
#json_errors {
color: red;
background-color: lightgrey;
}
#controls {
margin-left: 500px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="./d3mvc.js"></script>
</head>
<body>
<div id="plot"></div>
<div id="controls">
<div id="json_errors"></div>
<form>
<textarea id="model_data" rows="20" cols="50" autofocus>
[{
"name": "sin curve",
"xdesc": "X values",
"ydesc": "Y values",
"data": [[ 0 , 0.31578947, 0.63157895, 0.94736842, 1.26315789,
1.57894737, 1.89473684, 2.21052632, 2.52631579, 2.84210526,
3.15789474, 3.47368421, 3.78947368, 4.10526316, 4.42105263,
4.73684211, 5.05263158, 5.36842105, 5.68421053, 6 ],
[ 0 , 0.310567 , 0.59041986, 0.81188195, 0.95305133,
0.99996678, 0.9479885 , 0.80225698, 0.57718464, 0.29503045,
-0.01630136, -0.32602102, -0.60349817, -0.82129115, -0.95786089,
-0.99970104, -0.94267373, -0.79241881, -0.56379603, -0.2794155 ]
]
}
]
</textarea>
<br />
<input type="button" id="update_button" value="Update" />
</form>
</div>
<div id="errors">
</div>
<script>
$("#plot").children(0).remove();
var model = JSON.parse(d3.select("#model_data").html());
var view = d3mvc.make_view(model, "#plot")
.addConfiguration({type: 'lines'})
.addConfiguration({type: 'scatter'})
.addConfiguration({type: 'legend'})
.display();
$("#update_button").click(function () {
$("#json_errors, #errors").text("");
try {
var model = JSON.parse(d3.select("#model_data").property('value'));
view.update(model);
} catch (e) {
if (e instanceof SyntaxError) {
$("#json_errors").text(e.message);
} else {
$("#errors").text(e.message);
}
}
});
</script>
</body>
</html>
<!-- vim: set sw=4: -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment