forked from zanarmstrong's block: comet chart (prototype)
forked from zanarmstrong's block: comet chart - input your own data
forked from zanarmstrong's block: comet chart (prototype)
forked from zanarmstrong's block: comet chart - input your own data
body { | |
font-family: sans-serif; | |
} | |
.segments polygon { | |
shape-rendering: geometricPrecision; | |
} | |
.axis path { | |
stroke: grey; | |
stroke-width: 1px; | |
} | |
.axis line { | |
fill: none; | |
stroke: #727272; | |
shape-rendering: crispEdges; | |
stroke-width: .2; | |
} | |
.axis text { | |
font-size: 11px; | |
fill: #727272; | |
} | |
.label { | |
fill: grey; | |
stroke: none; | |
font-size: 16px; | |
} |
// define variables | |
var margin = { | |
top: 0, | |
right: 20, | |
bottom: 50, | |
left: 70 | |
}, | |
width = 500, | |
height = 400; | |
var formatAsNumber = d3.format(",.0f") | |
var segmentName = 'birthweight'; | |
// standard insertion of svg element | |
var svg = d3.select("#chart") | |
.append('svg') | |
.attr('width', width + margin.left + margin.right) | |
.attr('height', height + margin.top + margin.bottom); | |
var segments = svg.append("g") | |
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') | |
.attr("class", "segments"); | |
// add labels | |
segments.append("text") | |
.attr("class", "x label") | |
.attr("x", width / 2) | |
.attr("y", height + 40) | |
.style("text-anchor", "middle") | |
.text(mapping.titleWeight); | |
segments.append("text") | |
.attr("transform", "rotate(-90)") | |
.attr("class", "y label") | |
.attr("x", -height / 2) | |
.attr("y", -40) | |
.style("text-anchor", "middle") | |
.text(mapping.titleValue); | |
// call and use data | |
d3.csv("data.csv", function(error, data) { | |
if (error) return console.error('error'); | |
// filter by filter category, if desired | |
data = data.filter(function(d) { | |
if (mapping.filterCat != '') { | |
return d[mapping.filterName] == mappping.filterCat; | |
} else { | |
return d; | |
} | |
}); | |
// set scales | |
scales = applyData(data); | |
// add the comets | |
drawComets(segments, data); | |
// adding x axis, and y axis | |
addAxis(segments, scales.size, 'bottom'); | |
addAxis(segments, scales.value, 'left') | |
}); |
// graph elements | |
function addAxis(element, scale, location) { | |
var axis = d3.svg.axis() | |
.scale(scale) | |
.orient(location) | |
.ticks(15, ",.1s") | |
.tickSize(3, 0); | |
element.append("g").attr("class", "axis") | |
.attr("transform", placeAxis(location)) | |
.call(axis); | |
}; | |
function placeAxis(location) { | |
if (location == 'bottom') { | |
return "translate(0," + height + ")"; | |
} else if (location == 'left') { | |
return "translate(0,0)"; | |
} | |
} | |
function applyData(data) { | |
// initialize counter variables | |
var maxValue = 0, | |
maxWeight = 0, | |
minValue = data[0].startvalue, | |
minWeight = data[0].startweight, | |
diff = 0, | |
sizeSum = [0, 0], | |
comboSum = [0, 0]; | |
// use data to define max value, weight, weight diffs, and sum size and combo | |
data.forEach(function(d) { | |
d.weightDiff = +d.endweight - +d.startweight; | |
if (Math.abs(d.weightDiff) > diff) { | |
diff = Math.abs(d.weightDiff) | |
}; | |
maxValue = Math.max(maxValue, +d.startvalue, +d.endvalue); | |
maxWeight = Math.max(maxWeight, +d.startweight, +d.endweight); | |
minValue = Math.min(minValue, +d.startvalue, +d.endvalue); | |
minWeight = Math.min(minWeight, +d.startweight, +d.endweight); | |
// calculate for aggregate | |
sizeSum = [sizeSum[0] + +d.startweight, | |
sizeSum[1] + +d.endweight | |
]; | |
comboSum = [comboSum[0] + +d.startweight * +d.startvalue, | |
comboSum[1] + +d.endweight * +d.endvalue | |
]; | |
}) | |
// calculate and append aggregate data | |
// assumes same number of segments for start & end | |
// assumes no missing values | |
var aggregate = { | |
startvalue: comboSum[0] / sizeSum[0], | |
endvalue: comboSum[1] / sizeSum[1], | |
startweight: sizeSum[0] / data.length, | |
endweight: sizeSum[1] / data.length, | |
}; | |
aggregate[mapping.segmentName] = 'aggregate'; | |
data.push(aggregate); | |
// sets x and y scale to determine size of visible boxes | |
if (scaleOptions.weightScale == 'log') { | |
var sizeScale = d3.scale.log().clamp(true) | |
.domain([minWeight * .8, maxWeight * 2]) | |
.range([0, width]); | |
} else { | |
var sizeScale = d3.scale.linear().clamp(true) | |
.domain([minWeight * .8, maxWeight * 1.1]) | |
.range([0, width]); | |
} | |
if (scaleOptions.valueScale == 'log') { | |
var valueScale = d3.scale.log().clamp(true) | |
.domain([minValue * .9, maxValue * 2]) | |
.range([height, 0]); | |
} else { | |
var valueScale = d3.scale.linear().clamp(true) | |
.domain([minValue * .9, maxValue * 1.1]) | |
.range([height, 0]); | |
} | |
// color scale, based on data diffs | |
var colorScale = d3.scale.linear() | |
.domain([-diff, 0, diff]) | |
.range(['orange', 'grey', 'blue']) | |
return { | |
size: sizeScale, | |
value: valueScale, | |
color: colorScale | |
} | |
}; | |
// data to polygons | |
function valuesToPoints(startweight, endweight, startvalue, endvalue, halfWidth) { | |
points = [ | |
[startweight, startvalue] | |
]; | |
var a = startweight - endweight; | |
var b = startvalue - endvalue; | |
var dist = Math.sqrt(a * a + b * b); | |
var newPoint1 = [halfWidth / dist * b + endweight, -halfWidth / dist * a + endvalue]; | |
var newPoint2 = [-halfWidth / dist * b + endweight, halfWidth / dist * a + endvalue]; | |
points.push(newPoint1, newPoint2); | |
return points.join(" ") | |
}; | |
// function to draw comets | |
function drawComets(element, data) { | |
element.selectAll("polygon") | |
.data(data) | |
.enter() | |
.append("polygon") | |
.attr("points", function(d) { | |
return valuesToPoints(scales.size(+d.startweight), | |
scales.size(+d.endweight), | |
scales.value(+d.startvalue), | |
scales.value(+d.endvalue), | |
3); | |
}) | |
.attr("fill", function(d) { | |
if (d[mapping.segmentName] == 'aggregate') { | |
// | |
return 'black'; | |
} else { | |
return scales.color(d.weightDiff) | |
}; | |
}) | |
.append("title") | |
.text(function(d) { | |
return d[mapping.filterName] + | |
', ' + mapping.segmentName + | |
d[mapping.segmentName] + | |
', value: ' + | |
d.startvalue + ', ' + | |
d.endvalue + | |
' weights ' + | |
d.startweight + ' ' + | |
d.endweight; | |
}); | |
}; |
state | birthweight | startvalue | endvalue | startweight | endweight | |
---|---|---|---|---|---|---|
Ohio | 2500 - 2999 grams | 5.53 | 4.88 | 101227 | 109151 | |
Ohio | 1500 - 1999 grams | 29.19 | 26.96 | 9078 | 9904 | |
Ohio | 1000 - 1499 grams | 67.39 | 59.15 | 4526 | 5038 | |
Ohio | 4000+ grams | 1.96 | 1.24 | 65199 | 46140 | |
Ohio | 500 - 999 grams | 336.39 | 287.95 | 3377 | 3445 | |
Ohio | 2000 - 2499 grams | 13.69 | 11.62 | 28782 | 30884 | |
Ohio | 3000 - 3499 grams | 3.02 | 2.45 | 219696 | 222982 | |
Ohio | 499 grams or less | 921.9 | 901.15 | 1114 | 1305 | |
Ohio | 3500 - 3999 grams | 2.09 | 1.61 | 177442 | 154742 | |
Georgia | 2500 - 2999 grams | 5.39 | 4.11 | 84094 | 117194 | |
Georgia | 1500 - 1999 grams | 31.75 | 25.06 | 7748 | 10377 | |
Georgia | 1000 - 1499 grams | 66.49 | 59.75 | 3880 | 5021 | |
Georgia | 4000+ grams | 2.03 | 1.67 | 42755 | 35975 | |
Georgia | 500 - 999 grams | 349.31 | 293.52 | 3338 | 4228 | |
Georgia | 2000 - 2499 grams | 14.22 | 10.39 | 24539 | 34175 | |
Georgia | 3000 - 3499 grams | 2.66 | 2.14 | 172853 | 227039 | |
Georgia | 499 grams or less | 904.81 | 728.06 | 956 | 1151 | |
Georgia | 3500 - 3999 grams | 2.15 | 1.63 | 126734 | 137645 | |
New Jersey | 2500 - 2999 grams | 3.93 | 2.36 | 74847 | 82086 | |
New Jersey | 1500 - 1999 grams | 20.08 | 16.37 | 7120 | 7513 | |
New Jersey | 1000 - 1499 grams | 56.28 | 35.94 | 3536 | 3645 | |
New Jersey | 4000+ grams | 1.22 | 1.09 | 48311 | 33939 | |
New Jersey | 500 - 999 grams | 297.12 | 269.42 | 2955 | 2639 | |
New Jersey | 2000 - 2499 grams | 9.97 | 6.84 | 21156 | 22957 | |
New Jersey | 3000 - 3499 grams | 1.95 | 1.5 | 165760 | 173854 | |
New Jersey | 499 grams or less | 875.33 | 870.97 | 762 | 651 | |
New Jersey | 3500 - 3999 grams | 1.23 | 0.99 | 132117 | 118722 | |
Florida | 2500 - 2999 grams | 4.55 | 3.87 | 132288 | 177337 | |
Florida | 1500 - 1999 grams | 29.05 | 25.01 | 11601 | 15155 | |
Florida | 1000 - 1499 grams | 56.2 | 53.75 | 5783 | 7275 | |
Florida | 4000+ grams | 1.81 | 1.59 | 70266 | 58431 | |
Florida | 500 - 999 grams | 319.63 | 290.92 | 4696 | 5871 | |
Florida | 2000 - 2499 grams | 12.55 | 10.32 | 37381 | 49210 | |
Florida | 3000 - 3499 grams | 2.52 | 1.92 | 288298 | 364768 | |
Florida | 499 grams or less | 911.6 | 911.06 | 1233 | 1664 | |
Florida | 3500 - 3999 grams | 1.63 | 1.32 | 214462 | 226844 | |
Michigan | 2500 - 2999 grams | 5.87 | 3.93 | 84729 | 83716 | |
Michigan | 1500 - 1999 grams | 28.38 | 31.25 | 8281 | 7776 | |
Michigan | 1000 - 1499 grams | 71.52 | 55.03 | 3929 | 3816 | |
Michigan | 4000+ grams | 2.04 | 1.67 | 59301 | 41855 | |
Michigan | 500 - 999 grams | 347.11 | 295.4 | 3218 | 3084 | |
Michigan | 2000 - 2499 grams | 13.07 | 9.61 | 25024 | 24753 | |
Michigan | 3000 - 3499 grams | 2.63 | 2.22 | 190941 | 179909 | |
Michigan | 499 grams or less | 891.05 | 870.88 | 1028 | 1092 | |
Michigan | 3500 - 3999 grams | 1.91 | 1.62 | 158394 | 132157 | |
Texas | 3000 - 3499 grams | 2.54 | 2.06 | 514828 | 653989 | |
Texas | 1000 - 1499 grams | 61.69 | 53.48 | 8753 | 12079 | |
Texas | 2500 - 2999 grams | 4.55 | 3.83 | 226968 | 320675 | |
Texas | 1500 - 1999 grams | 30.92 | 28.16 | 18695 | 26033 | |
Texas | 4500+ grams | 2.23 | 2.37 | 17513 | 12673 | |
Texas | 4000 - 4499 grams | 1.68 | 1.67 | 99225 | 86139 | |
Texas | 499 grams or less | 703.34 | 708.93 | 1409 | 2642 | |
Texas | 3500 - 3999 grams | 1.87 | 1.4 | 373838 | 392317 | |
Texas | 500 - 999 grams | 308.81 | 265.38 | 7163 | 8859 | |
Texas | 2000 - 2499 grams | 13.27 | 10.76 | 60726 | 85758 | |
New York | 2500 - 2999 grams | 4.3 | 2.78 | 176330 | 184645 | |
New York | 1500 - 1999 grams | 25.99 | 20.74 | 16082 | 16300 | |
New York | 1000 - 1499 grams | 56.79 | 46.98 | 7906 | 7918 | |
New York | 4000+ grams | 1.57 | 1.07 | 106329 | 77806 | |
New York | 500 - 999 grams | 338.98 | 273.29 | 6552 | 5840 | |
New York | 2000 - 2499 grams | 10.92 | 7.88 | 49348 | 50356 | |
New York | 3000 - 3499 grams | 2.07 | 1.45 | 389495 | 388484 | |
New York | 499 grams or less | 931.61 | 927.12 | 1506 | 1276 | |
New York | 3500 - 3999 grams | 1.43 | 1.12 | 296709 | 263005 | |
Illinois | 2500 - 2999 grams | 5.75 | 3.78 | 121146 | 125074 | |
Illinois | 1500 - 1999 grams | 31.83 | 24.81 | 11436 | 11487 | |
Illinois | 1000 - 1499 grams | 70.31 | 51.46 | 5504 | 5344 | |
Illinois | 4000+ grams | 1.77 | 1.37 | 74666 | 54564 | |
Illinois | 500 - 999 grams | 364.81 | 300.19 | 4490 | 4204 | |
Illinois | 2000 - 2499 grams | 14.06 | 10.09 | 35357 | 35871 | |
Illinois | 3000 - 3499 grams | 3.11 | 1.96 | 268166 | 268672 | |
Illinois | 499 grams or less | 901.83 | 878.87 | 1477 | 1453 | |
Illinois | 3500 - 3999 grams | 2.04 | 1.36 | 210021 | 187259 | |
Pennsylvania | 2500 - 2999 grams | 4.8 | 4.51 | 94587 | 104298 | |
Pennsylvania | 1500 - 1999 grams | 30.89 | 23.89 | 8644 | 9711 | |
Pennsylvania | 1000 - 1499 grams | 63.76 | 51.12 | 4203 | 4851 | |
Pennsylvania | 4000+ grams | 1.82 | 1.64 | 64457 | 50705 | |
Pennsylvania | 500 - 999 grams | 326.86 | 285.59 | 3298 | 3456 | |
Pennsylvania | 2000 - 2499 grams | 12.32 | 10.13 | 27202 | 30112 | |
Pennsylvania | 3000 - 3499 grams | 2.51 | 2.19 | 212567 | 222310 | |
Pennsylvania | 499 grams or less | 920.35 | 918.74 | 1130 | 1366 | |
Pennsylvania | 3500 - 3999 grams | 1.69 | 1.38 | 174075 | 162801 | |
California | 3000 - 3499 grams | 2.33 | 1.57 | 802668 | 855510 | |
California | 1000 - 1499 grams | 68.98 | 54.7 | 12351 | 13237 | |
California | 2500 - 2999 grams | 4.6 | 3.13 | 331059 | 377355 | |
California | 1500 - 1999 grams | 32.57 | 24.98 | 25636 | 28865 | |
California | 4500+ grams | 2.37 | 2.12 | 36300 | 24560 | |
California | 4000 - 4499 grams | 1.67 | 1.12 | 194276 | 153362 | |
California | 499 grams or less | 879.21 | 850.28 | 2318 | 2518 | |
California | 3500 - 3999 grams | 1.7 | 1.21 | 642323 | 597310 | |
California | 500 - 999 grams | 338.35 | 295.25 | 8967 | 9338 | |
California | 2000 - 2499 grams | 12.98 | 9.85 | 81989 | 93270 |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<title>Comet Chart</title> | |
<link rel="stylesheet" href="cometChart.css"> | |
<header> | |
</header> | |
<p>To use this chart with your own data:</p> | |
<p>(1) paste your data into the data.csv</p> | |
<p>(2) change the column names in the mappingNames.js file</p> | |
<p>(optional) set the scale for each axis to log or linear</p> | |
<div id="chart"></div> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="mappingNames.js"></script> | |
<script src="cometChartFunctions.js"></script> | |
<script src="cometChart.js"></script> |
var mapping = { | |
// columns names for "value" metrics (y-axis), and a title for the size/weight value to use on the y-axis | |
startValue: "deathRate_before", | |
endValue: "deathRate_after", | |
titleValue: "Fetal Death Rate", | |
// column names for "weight" metrics (x-axis), and a title for the size/weight variable to use on the x-axis | |
startWeight: "numBabiesBorn_before", | |
endWeight: "numBabiesBorn_after", | |
titleWeight: "Number of Babies Born", | |
// column to segment the data into subgroups | |
segmentName: "birthweight", | |
// if you want to filter by another variable, type the name of that column here - and the category you want to filter as 'filterCat', as shown in the options that are commented out | |
filterName: "", | |
filterCat: "", | |
//filterName: "state", | |
//filterCat: "Ohio" | |
} | |
var scaleOptions = { | |
// set scale (either 'linear' or 'log') | |
weightScale: "log", | |
valueScale: "log" | |
} |