Parallel Coordinates plot for Positioning Technologies. Implementation based on http://mbostock.github.io/d3/talk/20111116/iris-parallel.html
Created
January 7, 2014 09:24
-
-
Save jensgrubert/8296876 to your computer and use it in GitHub Desktop.
Positioning Technologies Parallel Coordinates
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
technologies | Cost | Accuracy | Range | Robustness | User Number | |
---|---|---|---|---|---|---|
WLANRSSI | 1 | 1 | 1 | 1 | 4 | |
Ultrasound | 1 | 4 | 1 | 1 | 1 | |
PulseRadar | 3 | 3 | 2 | 2 | 3 | |
FMCWRadar | 3 | 3 | 3 | 3 | 3 | |
Laser | 4 | 4 | 4 | 2 | 1 | |
RFID | 1 | 1 | 0 | 2 | 3 |
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
<!DOCTYPE html> | |
<!-- based on http://mbostock.github.io/d3/talk/20111116/iris-parallel.html --> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> | |
<link type="text/css" rel="stylesheet" href="style.css"/> | |
<style type="text/css"> | |
svg { | |
font-size: 14px; | |
} | |
.foreground path { | |
fill: none; | |
stroke-opacity: .5; | |
stroke-width: 1.5px; | |
} | |
.foreground path.fade { | |
stroke: #000; | |
stroke-opacity: .05; | |
} | |
.legend { | |
font-size: 18px; | |
font-style: oblique; | |
} | |
.legend line { | |
stroke-width: 2px; | |
} | |
.WLANRSSI { | |
stroke: #800; | |
} | |
.Ultrasound { | |
stroke: #080; | |
} | |
.PulseRadar { | |
stroke: #008; | |
} | |
.FMCWRadar { | |
stroke: #808; | |
} | |
.Laser { | |
stroke: #088; | |
} | |
.RFID { | |
stroke: #000; | |
} | |
.brush .extent { | |
fill-opacity: .3; | |
stroke: #fff; | |
shape-rendering: crispEdges; | |
} | |
.axis line, .axis path { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
text-shadow: 0 1px 0 #fff; | |
cursor: move; | |
} | |
</style> | |
</head> | |
<body> | |
<h2> | |
Positioning Technology Overview<br> | |
parallel coordinates | |
</h2> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="d3.v3.min.js"></script> | |
<script type="text/javascript"> | |
var technologies = ["WLANRSSI", "Ultrasound", "PulseRadar", "FMCWRadar", "Laser", "RFID"]; | |
var characteristics = ["Cost", "Accuracy", "Range", "Robustness", "User Number"]; | |
var m = [80, 160, 100, 50], | |
w = 800 - m[1] - m[3], | |
h = 500 - m[0] - m[2]; | |
var x = d3.scale.ordinal().domain(characteristics).rangePoints([0, w]), | |
y = {}; | |
var line = d3.svg.line(), | |
axis = d3.svg.axis().orient("left"), | |
foreground; | |
var svg = d3.select("body").append("svg:svg") | |
.attr("width", w + m[1] + m[3]) | |
.attr("height", h + m[0] + m[2]) | |
.append("svg:g") | |
.attr("transform", "translate(" + m[3] + "," + m[0] + ")"); | |
d3.csv("data.csv", function(flowers) { | |
// Create a scale and brush for each characteristic. | |
characteristics.forEach(function(d) { | |
// Coerce values to numbers. | |
flowers.forEach(function(p) { p[d] = +p[d]; }); | |
y[d] = d3.scale.linear() | |
.domain(d3.extent(flowers, function(p) { return p[d]; })) | |
.range([h, 0]); | |
y[d].brush = d3.svg.brush() | |
.y(y[d]) | |
.on("brush", brush); | |
}); | |
// Add a legend. | |
var legend = svg.selectAll("g.legend") | |
.data(technologies) | |
.enter().append("svg:g") | |
.attr("class", "legend") | |
.attr("transform", function(d, i) { return "translate("+ (w + 30) +"," + (i * 20 + h/2) + ")"; }); | |
legend.append("svg:line") | |
.attr("class", String) | |
.attr("x2", 8); | |
legend.append("svg:text") | |
.attr("x", 12) | |
.attr("dy", ".31em") | |
.text(function(d) { return d; }); | |
// Add foreground lines. | |
foreground = svg.append("svg:g") | |
.attr("class", "foreground") | |
.selectAll("path") | |
.data(flowers) | |
.enter().append("svg:path") | |
.attr("d", path) | |
.attr("class", function(d) { return d.technologies; }); | |
// Add a group element for each characteristic. | |
var g = svg.selectAll(".characteristic") | |
.data(characteristics) | |
.enter().append("svg:g") | |
.attr("class", "characteristic") | |
.attr("transform", function(d) { return "translate(" + x(d) + ")"; }) | |
.call(d3.behavior.drag() | |
.origin(function(d) { return {x: x(d)}; }) | |
.on("dragstart", dragstart) | |
.on("drag", drag) | |
.on("dragend", dragend)); | |
// Add an axis and title. | |
g.append("svg:g") | |
.attr("class", "axis") | |
.each(function(d) { d3.select(this).call(axis.scale(y[d])); }) | |
.append("svg:text") | |
.attr("text-anchor", "middle") | |
.attr("y", -9) | |
.text(String); | |
// Add a brush for each axis. | |
g.append("svg:g") | |
.attr("class", "brush") | |
.each(function(d) { d3.select(this).call(y[d].brush); }) | |
.selectAll("rect") | |
.attr("x", -8) | |
.attr("width", 16); | |
function dragstart(d) { | |
i = characteristics.indexOf(d); | |
//console.log(i); | |
} | |
function drag(d) { | |
x.range()[i] = d3.event.x; | |
characteristics.sort(function(a, b) { return x(a) - x(b); }); | |
g.attr("transform", function(d) { return "translate(" + x(d) + ")"; }); | |
foreground.attr("d", path); | |
} | |
function dragend(d) { | |
x.domain(characteristics).rangePoints([0, w]); | |
var t = d3.transition().duration(500); | |
t.selectAll(".characteristic").attr("transform", function(d) { return "translate(" + x(d) + ")"; }); | |
t.selectAll(".foreground path").attr("d", path); | |
} | |
}); | |
// Returns the path for a given data point. | |
function path(d) { | |
return line(characteristics.map(function(p) { return [x(p), y[p](d[p])]; })); | |
} | |
// Handles a brush event, toggling the display of foreground lines. | |
function brush() { | |
var actives = characteristics.filter(function(p) { return !y[p].brush.empty(); }), | |
extents = actives.map(function(p) { return y[p].brush.extent(); }); | |
foreground.classed("fade", function(d) { | |
return !actives.every(function(p, i) { | |
return extents[i][0] <= d[p] && d[p] <= extents[i][1]; | |
}); | |
}); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment