2 //Code adapted from Jason Davies' "Parallel Coordinates"
3 // http://bl.ocks.org/jasondavies/1341281
5 nv.models.parallelCoordinates = function() {
7 //============================================================
8 // Public Variables with Default Settings
9 //------------------------------------------------------------
12 var margin = {top: 30, right: 10, bottom: 10, left: 10}
15 , x = d3.scale.ordinal()
18 , color = nv.utils.getColor(d3.scale.category20c().range())
19 , axisLabel = function(d) { return d; }
22 , dispatch = d3.dispatch('brush')
25 //============================================================
28 //============================================================
30 //------------------------------------------------------------
33 //============================================================
36 function chart(selection) {
37 selection.each(function(data) {
38 var availableWidth = width - margin.left - margin.right,
39 availableHeight = height - margin.top - margin.bottom,
40 container = d3.select(this);
42 active = data; //set all active before first brush call
44 chart.update = function() { }; //This is a placeholder until this chart is made resizeable
46 //------------------------------------------------------------
50 .rangePoints([0, availableWidth], 1)
53 // Extract the list of dimensions and create a scale for each.
54 dimensions.forEach(function(d) {
55 y[d] = d3.scale.linear()
56 .domain(d3.extent(data, function(p) { return +p[d]; }))
57 .range([availableHeight, 0]);
59 y[d].brush = d3.svg.brush().y(y[d]).on('brush', brush);
65 //------------------------------------------------------------
68 //------------------------------------------------------------
69 // Setup containers and skeleton of chart
71 var wrap = container.selectAll('g.nv-wrap.nv-parallelCoordinates').data([data]);
72 var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-parallelCoordinates');
73 var gEnter = wrapEnter.append('g');
74 var g = wrap.select('g')
76 gEnter.append('g').attr('class', 'nv-parallelCoordinatesWrap');
78 wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
80 //------------------------------------------------------------
83 var line = d3.svg.line(),
84 axis = d3.svg.axis().orient('left'),
89 // Add grey background lines for context.
90 background = gEnter.append('g')
91 .attr('class', 'background')
94 .enter().append('path')
98 // Add blue foreground lines for focus.
99 foreground = gEnter.append('g')
100 .attr('class', 'foreground')
103 .enter().append('path')
107 // Add a group element for each dimension.
108 var dimension = g.selectAll('.dimension')
111 .attr('class', 'dimension')
112 .attr('transform', function(d) { return 'translate(' + x(d) + ',0)'; });
114 // Add an axis and title.
115 dimension.append('g')
116 .attr('class', 'axis')
117 .each(function(d) { d3.select(this).call(axis.scale(y[d])); })
119 .attr('text-anchor', 'middle')
123 // Add and store a brush for each axis.
124 dimension.append('g')
125 .attr('class', 'brush')
126 .each(function(d) { d3.select(this).call(y[d].brush); })
132 // Returns the path for a given data point.
134 return line(dimensions.map(function(p) { return [x(p), y[p](d[p])]; }));
137 // Handles a brush event, toggling the display of foreground lines.
139 var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
140 extents = actives.map(function(p) { return y[p].brush.extent(); });
142 filters = []; //erase current filters
143 actives.forEach(function(d,i) {
150 active = []; //erase current active list
151 foreground.style('display', function(d) {
152 var isActive = actives.every(function(p, i) {
153 return extents[i][0] <= d[p] && d[p] <= extents[i][1];
155 if (isActive) active.push(d);
156 return isActive ? null : 'none';
174 //============================================================
175 // Expose Public Variables
176 //------------------------------------------------------------
179 chart.dispatch = dispatch;
180 chart.options = nv.utils.optionsFunc.bind(chart);
182 chart.margin = function(_) {
183 if (!arguments.length) return margin;
184 margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
185 margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
186 margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
187 margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
191 chart.width = function(_) {
192 if (!arguments.length) return width;
197 chart.height = function(_) {
198 if (!arguments.length) return height;
203 chart.color = function(_) {
204 if (!arguments.length) return color;
205 color = nv.utils.getColor(_)
209 chart.xScale = function(_) {
210 if (!arguments.length) return x;
215 chart.yScale = function(_) {
216 if (!arguments.length) return y;
221 chart.dimensions = function(_) {
222 if (!arguments.length) return dimensions;
227 chart.filters = function() {
231 chart.active = function() {
235 //============================================================