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; | |
| } |