Built with blockbuilder.org
forked from avrasgoldman's block: bean explorer
license: mit |
Built with blockbuilder.org
forked from avrasgoldman's block: bean explorer
ID | food_group | beans | Calcium, Ca (mg) | Carbohydrate, by difference (g) | Total lipid (fat) (g) | Fiber, total dietary (g) | Iron, Fe (mg) | Magnesium, Mg (mg) | Protein (g) | Riboflavin (mg) | Sugars, total (g) | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Legumes | black | 27 | 23.71 | 0.54 | 8.7 | 2.1 | 0.444 | 8.86 | 0.059 | 0.32 | |
2 | Legumes | kidney | 28 | 22.8 | 0.5 | 6.4 | 2.94 | 0.477 | 8.67 | 0.058 | 0.32 | |
3 | Legumes | red kidney | 28 | 22.8 | 0.5 | 7.4 | 2.94 | 0.477 | 8.67 | 0.058 | 0.32 | |
4 | Legumes | navy | 69 | 26.05 | 0.62 | 10.5 | 2.36 | 0.527 | 8.23 | 0.066 | 0.37 | |
5 | Legumes | pink | 52 | 27.91 | 0.49 | 5.3 | 2.3 | 0.548 | 9.06 | 0.063 | 0.36 | |
6 | Legumes | pinto | 46 | 26.22 | 0.65 | 9 | 2.09 | 0.453 | 9.01 | 0.062 | 0.34 | |
7 | Legumes | white | 90 | 25.09 | 0.35 | 6.3 | 3.7 | 0.636 | 9.73 | 0.046 | 0.34 | |
8 | Legumes | yeloow | 62 | 25.28 | 1.08 | 10.4 | 2.48 | 0.455 | 9.16 | 0.103 | 0.34 | |
9 | Legumes | fava | 36 | 19.65 | 0.4 | 5.4 | 1.5 | 0.421 | 7.6 | 0.089 | 1.82 | |
10 | Legumes | garbanzo | 49 | 27.42 | 2.59 | 7.6 | 2.89 | 1.03 | 8.86 | 0.063 | 4.8 | |
11 | Legumes | blackeyed | 24 | 20.76 | 0.53 | 6.5 | 2.51 | 0.475 | 7.73 | 0.055 | 3.3 | |
12 | Legumes | lentils | 19 | 19.54 | 0.38 | 7.9 | 3.33 | 0.494 | 9.02 | 0.073 | 1.8 | |
13 | Legumes | lima | 17 | 20.88 | 0.38 | 7 | 2.39 | 0.516 | 7.8 | 0.055 | 2.9 | |
14 | Legumes | mung | 27 | 19.15 | 0.38 | 7.6 | 1.4 | 0.298 | 7.02 | 0.061 | 2 | |
15 | Legumes | peanuts | 55 | 21.26 | 22.01 | 8.8 | 1.01 | 1.023 | 13.5 | 0.063 | 2.47 | |
16 | Legumes | peas | 14 | 20.51 | 0.39 | 8.3 | 1.29 | 0.396 | 8.34 | 0.056 | 2.9 | |
17 | Legumes | soybeans | 102 | 8.36 | 8.97 | 6 | 5.14 | 0.824 | 18.21 | 0.285 | 3 |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<title>Nutrient Parallel Coordinates IV</title> | |
<body> | |
<script src="https://d3js.org/d3.v4.js"></script> | |
<script src="https://bl.ocks.org/syntagmatic/raw/3341641/render-queue.js"></script> | |
<link rel="stylesheet" href="style.css"></link> | |
<script> | |
var margin = {top: 66, right: 110, bottom: 20, left: 188}, | |
width = document.body.clientWidth - margin.left - margin.right, | |
height = 340 - margin.top - margin.bottom, | |
innerHeight = height - 2; | |
var devicePixelRatio = window.devicePixelRatio || 1; | |
var color = d3.scaleOrdinal() | |
.range(["#5DA5B3","#D58323","#DD6CA7","#54AF52","#8C92E8","#E15E5A","#725D82","#776327","#50AB84","#954D56","#AB9C27","#517C3F","#9D5130","#357468","#5E9ACF","#C47DCB","#7D9E33","#DB7F85","#BA89AD","#4C6C86","#B59248","#D8597D","#944F7E","#D67D4B","#8F86C2"]); | |
var types = { | |
"Number": { | |
key: "Number", | |
coerce: function(d) { return +d; }, | |
extent: d3.extent, | |
within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; }, | |
defaultScale: d3.scaleLinear().range([innerHeight, 0]) | |
}, | |
"String": { | |
key: "String", | |
coerce: String, | |
extent: function (data) { return data.sort(); }, | |
within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; }, | |
defaultScale: d3.scalePoint().range([0, innerHeight]) | |
}, | |
"Date": { | |
key: "Date", | |
coerce: function(d) { return new Date(d); }, | |
extent: d3.extent, | |
within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; }, | |
defaultScale: d3.scaleTime().range([0, innerHeight]) | |
} | |
}; | |
var dimensions = [ | |
{ | |
key: "beans", | |
description: "Beans", | |
type: types["String"], | |
axis: d3.axisLeft() | |
.tickFormat(function(d,i) { | |
return d; | |
}) | |
}, | |
{ | |
key: "Total lipid (fat) (g)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Sugars, total (g)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Calcium, Ca (mg)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Riboflavin (mg)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Iron, Fe (mg)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Magnesium, Mg (mg)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Protein (g)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Fiber, total dietary (g)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
}, | |
{ | |
key: "Carbohydrate, by difference (g)", | |
type: types["Number"], | |
scale: d3.scaleSqrt().range([innerHeight, 0]) | |
} | |
]; | |
var xscale = d3.scalePoint() | |
.domain(d3.range(dimensions.length)) | |
.range([0, width]); | |
var yAxis = d3.axisLeft(); | |
var container = d3.select("body").append("div") | |
.attr("class", "parcoords") | |
.style("width", width + margin.left + margin.right + "px") | |
.style("height", height + margin.top + margin.bottom + "px"); | |
var svg = container.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var canvas = container.append("canvas") | |
.attr("width", width * devicePixelRatio) | |
.attr("height", height * devicePixelRatio) | |
.style("width", width + "px") | |
.style("height", height + "px") | |
.style("margin-top", margin.top + "px") | |
.style("margin-left", margin.left + "px"); | |
var ctx = canvas.node().getContext("2d"); | |
ctx.globalCompositeOperation = 'darken'; | |
ctx.globalAlpha = 0.15; | |
ctx.lineWidth = 1.5; | |
ctx.scale(devicePixelRatio, devicePixelRatio); | |
var output = d3.select("body").append("pre"); | |
var axes = svg.selectAll(".axis") | |
.data(dimensions) | |
.enter().append("g") | |
.attr("class", function(d) { return "axis " + d.key.replace(/ /g, "_"); }) | |
.attr("transform", function(d,i) { return "translate(" + xscale(i) + ")"; }); | |
d3.csv("beans.csv", function(error, data) { | |
if (error) throw error; | |
// shuffle the data! | |
data = d3.shuffle(data); | |
data.forEach(function(d) { | |
dimensions.forEach(function(p) { | |
d[p.key] = !d[p.key] ? null : p.type.coerce(d[p.key]); | |
}); | |
// truncate long text strings to fit in data table | |
for (var key in d) { | |
if (d[key] && d[key].length > 35) d[key] = d[key].slice(0,36); | |
} | |
}); | |
// type/dimension default setting happens here | |
dimensions.forEach(function(dim) { | |
if (!("domain" in dim)) { | |
// detect domain using dimension type's extent function | |
dim.domain = d3_functor(dim.type.extent)(data.map(function(d) { return d[dim.key]; })); | |
} | |
if (!("scale" in dim)) { | |
// use type's default scale for dimension | |
dim.scale = dim.type.defaultScale.copy(); | |
} | |
dim.scale.domain(dim.domain); | |
}); | |
var render = renderQueue(draw).rate(50); | |
ctx.clearRect(0,0,width,height); | |
ctx.globalAlpha = d3.min([0.85/Math.pow(data.length,0.3),1]); | |
render(data); | |
axes.append("g") | |
.each(function(d) { | |
var renderAxis = "axis" in d | |
? d.axis.scale(d.scale) // custom axis | |
: yAxis.scale(d.scale); // default axis | |
d3.select(this).call(renderAxis); | |
}) | |
.append("text") | |
.attr("class", "title") | |
.attr("text-anchor", "start") | |
.text(function(d) { return "description" in d ? d.description : d.key; }) | |
// Add and store a brush for each axis. | |
axes.append("g") | |
.attr("class", "brush") | |
.each(function(d) { | |
d3.select(this).call(d.brush = d3.brushY() | |
.extent([[-10,0], [10,height]]) | |
.on("start", brushstart) | |
.on("brush", brush) | |
.on("end", brush) | |
) | |
}) | |
.selectAll("rect") | |
.attr("x", -8) | |
.attr("width", 16); | |
d3.selectAll(".axis.beans .tick text") | |
.style("fill", color); | |
output.text(d3.tsvFormat(data.slice(0,24))); | |
function project(d) { | |
return dimensions.map(function(p,i) { | |
// check if data element has property and contains a value | |
if ( | |
!(p.key in d) || | |
d[p.key] === null | |
) return null; | |
return [xscale(i),p.scale(d[p.key])]; | |
}); | |
}; | |
function draw(d) { | |
ctx.strokeStyle = color(d.beans); | |
ctx.beginPath(); | |
var coords = project(d); | |
coords.forEach(function(p,i) { | |
// this tricky bit avoids rendering null values as 0 | |
if (p === null) { | |
// this bit renders horizontal lines on the previous/next | |
// dimensions, so that sandwiched null values are visible | |
if (i > 0) { | |
var prev = coords[i-1]; | |
if (prev !== null) { | |
ctx.moveTo(prev[0],prev[1]); | |
ctx.lineTo(prev[0]+6,prev[1]); | |
} | |
} | |
if (i < coords.length-1) { | |
var next = coords[i+1]; | |
if (next !== null) { | |
ctx.moveTo(next[0]-6,next[1]); | |
} | |
} | |
return; | |
} | |
if (i == 0) { | |
ctx.moveTo(p[0],p[1]); | |
return; | |
} | |
ctx.lineTo(p[0],p[1]); | |
}); | |
ctx.stroke(); | |
} | |
function brushstart() { | |
d3.event.sourceEvent.stopPropagation(); | |
} | |
// Handles a brush event, toggling the display of foreground lines. | |
function brush() { | |
render.invalidate(); | |
var actives = []; | |
svg.selectAll(".axis .brush") | |
.filter(function(d) { | |
return d3.brushSelection(this); | |
}) | |
.each(function(d) { | |
actives.push({ | |
dimension: d, | |
extent: d3.brushSelection(this) | |
}); | |
}); | |
var selected = data.filter(function(d) { | |
if (actives.every(function(active) { | |
var dim = active.dimension; | |
// test if point is within extents for each active brush | |
return dim.type.within(d[dim.key], active.extent, dim); | |
})) { | |
return true; | |
} | |
}); | |
ctx.clearRect(0,0,width,height); | |
ctx.globalAlpha = d3.min([0.85/Math.pow(selected.length,0.3),1]); | |
render(selected); | |
output.text(d3.tsvFormat(selected.slice(0,24))); | |
} | |
}); | |
function d3_functor(v) { | |
return typeof v === "function" ? v : function() { return v; }; | |
}; | |
</script> |
body { | |
min-width: 760px; | |
} | |
.parcoords { | |
display: block; | |
} | |
.parcoords svg, | |
.parcoords canvas { | |
font: 10px sans-serif; | |
position: absolute; | |
} | |
.parcoords canvas { | |
opacity: 0.9; | |
pointer-events: none; | |
} | |
.axis .title { | |
font-size: 10px; | |
transform: rotate(-21deg) translate(-5px,-6px); | |
fill: #222; | |
} | |
.axis line, | |
.axis path { | |
fill: none; | |
stroke: #ccc; | |
stroke-width: 1px; | |
} | |
.axis .tick text { | |
fill: #222; | |
opacity: 0; | |
pointer-events: none; | |
} | |
.axis.manufac_name .tick text, | |
.axis.beans .tick text { | |
opacity: 1; | |
} | |
//.axis:hover line, | |
//.axis:hover path, | |
.axis.active line, | |
.axis.active path { | |
fill: none; | |
stroke: #222; | |
stroke-width: 1px; | |
} | |
.key:hover .beans { | |
font-weight: bold; | |
} | |
.axis:hover .title { | |
font-weight: bold; | |
} | |
.axis:hover .tick text { | |
opacity: 1; | |
} | |
.axis.active .title { | |
font-weight: bold; | |
} | |
.axis.active .tick text { | |
opacity: 1; | |
font-weight: bold; | |
} | |
.brush .extent { | |
fill-opacity: .3; | |
stroke: #fff; | |
stroke-width: 1px; | |
} | |
pre { | |
width: 100%; | |
height: 300px; | |
margin: 6px 12px; | |
tab-size: 40; | |
font-size: 10px; | |
overflow: auto; | |
} |