Solving a problem of overlapping data points with correct positioning on the x-axis
forked from stain-win's block: Scatter plot with collision
license: mit |
Solving a problem of overlapping data points with correct positioning on the x-axis
forked from stain-win's block: Scatter plot with collision
[ | |
{ | |
"value": 46, | |
"size": 690 | |
}, | |
{ | |
"value": 10, | |
"size": 453 | |
}, | |
{ | |
"value": 19, | |
"size": 535 | |
}, | |
{ | |
"value": 35, | |
"size": 753 | |
}, | |
{ | |
"value": 14, | |
"size": 283 | |
}, | |
{ | |
"value": 14, | |
"size": 940 | |
}, | |
{ | |
"value": 13, | |
"size": 427 | |
}, | |
{ | |
"value": 34, | |
"size": 406 | |
}, | |
{ | |
"value": 49, | |
"size": 933 | |
}, | |
{ | |
"value": 46, | |
"size": 1144 | |
}, | |
{ | |
"value": 20, | |
"size": 1068 | |
}, | |
{ | |
"value": 2, | |
"size": 389 | |
}, | |
{ | |
"value": 0, | |
"size": 184 | |
}, | |
{ | |
"value": 38, | |
"size": 1695 | |
}, | |
{ | |
"value": 22, | |
"size": 1219 | |
}, | |
{ | |
"value": 18, | |
"size": 574 | |
}, | |
{ | |
"value": 45, | |
"size": 1433 | |
}, | |
{ | |
"value": 24, | |
"size": 283 | |
}, | |
{ | |
"value": 49, | |
"size": 160 | |
}, | |
{ | |
"value": 38, | |
"size": 1881 | |
}, | |
{ | |
"value": 44, | |
"size": 1440 | |
}, | |
{ | |
"value": 0, | |
"size": 73 | |
}, | |
{ | |
"value": 11, | |
"size": 297 | |
}, | |
{ | |
"value": 12, | |
"size": 1003 | |
}, | |
{ | |
"value": 2, | |
"size": 268 | |
}, | |
{ | |
"value": 35, | |
"size": 177 | |
}, | |
{ | |
"value": 35, | |
"size": 889 | |
}, | |
{ | |
"value": 42, | |
"size": 283 | |
}, | |
{ | |
"value": 15, | |
"size": 941 | |
}, | |
{ | |
"value": 20, | |
"size": 163 | |
}, | |
{ | |
"value": 37, | |
"size": 957 | |
}, | |
{ | |
"value": 49, | |
"size": 1044 | |
}, | |
{ | |
"value": 17, | |
"size": 894 | |
}, | |
{ | |
"value": 42, | |
"size": 283 | |
}, | |
{ | |
"value": 30, | |
"size": 1626 | |
}, | |
{ | |
"value": 33, | |
"size": 647 | |
}, | |
{ | |
"value": 28, | |
"size": 532 | |
}, | |
{ | |
"value": 42, | |
"size": 215 | |
}, | |
{ | |
"value": 26, | |
"size": 822 | |
}, | |
{ | |
"value": 11, | |
"size": 799 | |
}, | |
{ | |
"value": 20, | |
"size": 934 | |
}, | |
{ | |
"value": 22, | |
"size": 730 | |
}, | |
{ | |
"value": 49, | |
"size": 1158 | |
}, | |
{ | |
"value": 16, | |
"size": 79 | |
}, | |
{ | |
"value": 12, | |
"size": 671 | |
}, | |
{ | |
"value": 38, | |
"size": 1260 | |
}, | |
{ | |
"value": 34, | |
"size": 274 | |
}, | |
{ | |
"value": 22, | |
"size": 202 | |
}, | |
{ | |
"value": 36, | |
"size": 1722 | |
}, | |
{ | |
"value": 31, | |
"size": 794 | |
}, | |
{ | |
"value": 36, | |
"size": 442 | |
}, | |
{ | |
"value": 33, | |
"size": 696 | |
}, | |
{ | |
"value": 12, | |
"size": 626 | |
}, | |
{ | |
"value": 8, | |
"size": 282 | |
}, | |
{ | |
"value": 4, | |
"size": 246 | |
}, | |
{ | |
"value": 5, | |
"size": 410 | |
}, | |
{ | |
"value": 11, | |
"size": 357 | |
}, | |
{ | |
"value": 3, | |
"size": 262 | |
}, | |
{ | |
"value": 4, | |
"size": 119 | |
}, | |
{ | |
"value": 33, | |
"size": 203 | |
}, | |
{ | |
"value": 43, | |
"size": 1010 | |
}, | |
{ | |
"value": 0, | |
"size": 146 | |
}, | |
{ | |
"value": 20, | |
"size": 151 | |
}, | |
{ | |
"value": 32, | |
"size": 752 | |
}, | |
{ | |
"value": 47, | |
"size": 2716 | |
}, | |
{ | |
"value": 40, | |
"size": 1293 | |
}, | |
{ | |
"value": 34, | |
"size": 1380 | |
}, | |
{ | |
"value": 0, | |
"size": 67 | |
}, | |
{ | |
"value": 0, | |
"size": 201 | |
}, | |
{ | |
"value": 18, | |
"size": 884 | |
}, | |
{ | |
"value": 33, | |
"size": 787 | |
}, | |
{ | |
"value": 46, | |
"size": 463 | |
}, | |
{ | |
"value": 19, | |
"size": 274 | |
}, | |
{ | |
"value": 5, | |
"size": 731 | |
}, | |
{ | |
"value": 9, | |
"size": 326 | |
}, | |
{ | |
"value": 2, | |
"size": 357 | |
}, | |
{ | |
"value": 44, | |
"size": 439 | |
}, | |
{ | |
"value": 23, | |
"size": 175 | |
}, | |
{ | |
"value": 21, | |
"size": 869 | |
}, | |
{ | |
"value": 42, | |
"size": 426 | |
}, | |
{ | |
"value": 24, | |
"size": 1038 | |
}, | |
{ | |
"value": 5, | |
"size": 359 | |
}, | |
{ | |
"value": 44, | |
"size": 542 | |
}, | |
{ | |
"value": 17, | |
"size": 903 | |
}, | |
{ | |
"value": 47, | |
"size": 1841 | |
}, | |
{ | |
"value": 11, | |
"size": 73 | |
}, | |
{ | |
"value": 11, | |
"size": 388 | |
}, | |
{ | |
"value": 34, | |
"size": 445 | |
}, | |
{ | |
"value": 47, | |
"size": 530 | |
}, | |
{ | |
"value": 39, | |
"size": 818 | |
}, | |
{ | |
"value": 17, | |
"size": 860 | |
}, | |
{ | |
"value": 36, | |
"size": 137 | |
}, | |
{ | |
"value": 13, | |
"size": 266 | |
}, | |
{ | |
"value": 26, | |
"size": 594 | |
}, | |
{ | |
"value": 28, | |
"size": 242 | |
}, | |
{ | |
"value": 48, | |
"size": 1029 | |
}, | |
{ | |
"value": 28, | |
"size": 1248 | |
}, | |
{ | |
"value": 14, | |
"size": 508 | |
}, | |
{ | |
"value": 29, | |
"size": 540 | |
}, | |
{ | |
"value": 7, | |
"size": 687 | |
}, | |
{ | |
"value": 2, | |
"size": 94 | |
}, | |
{ | |
"value": 43, | |
"size": 810 | |
}, | |
{ | |
"value": 24, | |
"size": 566 | |
}, | |
{ | |
"value": 19, | |
"size": 542 | |
}, | |
{ | |
"value": 32, | |
"size": 1198 | |
}, | |
{ | |
"value": 38, | |
"size": 372 | |
}, | |
{ | |
"value": 27, | |
"size": 500 | |
}, | |
{ | |
"value": 29, | |
"size": 751 | |
}, | |
{ | |
"value": 19, | |
"size": 636 | |
}, | |
{ | |
"value": 17, | |
"size": 791 | |
}, | |
{ | |
"value": 30, | |
"size": 350 | |
}, | |
{ | |
"value": 31, | |
"size": 1205 | |
}, | |
{ | |
"value": 6, | |
"size": 856 | |
}, | |
{ | |
"value": 21, | |
"size": 939 | |
}, | |
{ | |
"value": 26, | |
"size": 1840 | |
}, | |
{ | |
"value": 45, | |
"size": 1179 | |
}, | |
{ | |
"value": 27, | |
"size": 1658 | |
}, | |
{ | |
"value": 20, | |
"size": 820 | |
}, | |
{ | |
"value": 32, | |
"size": 966 | |
}, | |
{ | |
"value": 8, | |
"size": 524 | |
}, | |
{ | |
"value": 45, | |
"size": 1435 | |
}, | |
{ | |
"value": 5, | |
"size": 241 | |
}, | |
{ | |
"value": 17, | |
"size": 1063 | |
}, | |
{ | |
"value": 3, | |
"size": 185 | |
}, | |
{ | |
"value": 2, | |
"size": 331 | |
}, | |
{ | |
"value": 9, | |
"size": 482 | |
}, | |
{ | |
"value": 32, | |
"size": 1411 | |
}, | |
{ | |
"value": 12, | |
"size": 435 | |
}, | |
{ | |
"value": 12, | |
"size": 1534 | |
}, | |
{ | |
"value": 48, | |
"size": 516 | |
}, | |
{ | |
"value": 20, | |
"size": 342 | |
}, | |
{ | |
"value": 30, | |
"size": 488 | |
}, | |
{ | |
"value": 21, | |
"size": 804 | |
}, | |
{ | |
"value": 23, | |
"size": 801 | |
}, | |
{ | |
"value": 38, | |
"size": 525 | |
}, | |
{ | |
"value": 39, | |
"size": 590 | |
}, | |
{ | |
"value": 13, | |
"size": 259 | |
}, | |
{ | |
"value": 23, | |
"size": 460 | |
}, | |
{ | |
"value": 2, | |
"size": 22 | |
}, | |
{ | |
"value": 27, | |
"size": 261 | |
}, | |
{ | |
"value": 2, | |
"size": 505 | |
}, | |
{ | |
"value": 18, | |
"size": 740 | |
}, | |
{ | |
"value": 48, | |
"size": 1853 | |
}, | |
{ | |
"value": 34, | |
"size": 681 | |
} | |
] |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
svg { | |
font: 20px sans-serif; | |
} | |
p { | |
margin: 6px 2px; | |
} | |
.axisTitle { | |
font: bold 12px sans-serif ; | |
} | |
.x.axis .domain { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.d3-tip { | |
line-height: 1; | |
font-weight: bold; | |
padding: 8px; | |
background: rgba(0, 0, 0, 0.8); | |
color: #fff; | |
border-radius: 2px; | |
font: 14px sans-serif; | |
} | |
/* Creates a small triangle extender for the tooltip */ | |
.d3-tip:after { | |
box-sizing: border-box; | |
display: inline; | |
font-size: 10px; | |
width: 100%; | |
line-height: 1; | |
color: rgba(0, 0, 0, 0.8); | |
content: "\25BC"; | |
position: absolute; | |
text-align: center; | |
} | |
/* Style northward tooltips differently */ | |
.d3-tip.n:after { | |
margin: -1px 0 0 0; | |
top: 100%; | |
left: 0; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v4.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script> | |
<script> | |
var margin = {top: 50, right: 50, bottom: 50, left: 50}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom, | |
padding = 2, | |
maxRadius = 30, | |
minRadius = 2, | |
numberOfNodes = 144; | |
var x = d3.scaleLinear() | |
.domain( [0, 50] ) | |
.range( [margin.left, width + margin.right ] ); | |
var xAxis = d3.axisBottom(x); | |
var tip = d3.tip() | |
.attr('class', 'd3-tip') | |
.offset([-6, 0]) | |
.html(function(d) { | |
return "<p><strong>Age:</strong> <span>" + d.value + "</span></p>\ | |
<p><strong>People:</strong> <span>" + d.size + "</span></p>"; | |
}); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.attr("shape-rendering", "geometric-precision"); | |
svg.call(tip); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + ( margin.top + ( height/2) ) + ")") | |
.call(xAxis); | |
var xAxisTitle = svg.append("text") | |
.attr("class", "axisTitle") | |
.text("Age in case file") | |
xAxisTitle | |
.attr("x", width - xAxisTitle.node().getBBox().width + margin.right) | |
.attr("y", margin.top + ( height/2) - xAxisTitle.node().getBBox().height); | |
svg.append("text") | |
.attr("x", 50) | |
.attr("y", 30) | |
.attr("dy", "0.71em") | |
.text("People hanging out in groups"); | |
d3.json("data.json", function(error, data) { | |
if (error) throw error; | |
var nodes = data.map(function(node, index) { | |
return { | |
index: index, | |
value: node.value, | |
size: node.size, | |
x: x(node.value), | |
fx: x(node.value), | |
}; | |
}); | |
var sizeScale = d3.scaleLinear() | |
.domain([d3.min(data, function(d){ return d.size;}), d3.max(data, function(d){ return d.size;})]) | |
.range([minRadius,maxRadius]); | |
var colorScale = d3.scaleSequential(d3.interpolateRainbow) | |
.domain( [d3.min(data, function(d){ return d.value;}), d3.max(data, function(d){ return d.value;})] ); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + ( margin.top + ( height/2) ) + ")") | |
.call(xAxis); | |
var simulation = d3.forceSimulation(nodes) | |
.force("x", d3.forceX(function(d) { return x(d.value); }).strength(1)) | |
.force("y", d3.forceY(250)) | |
.force("collide", d3.forceCollide().radius(function(d){ return sizeScale(d.size) + padding })) | |
.force("manyBody", d3.forceManyBody().strength(-10)) | |
.stop(); | |
for (var i = 0; i < 150; ++i) simulation.tick(); | |
var circle = svg.selectAll("circle") | |
.data(nodes) | |
.enter().append("circle") | |
.style("fill", function(d) { return colorScale(d.value); }) | |
.attr("cx", function(d) { return d.x} ) | |
.attr("cy", function(d) { return d.y} ) | |
.attr("r", function(d) { return sizeScale(d.size)} ) | |
.style("opacity", 0.6) | |
.on('mouseover', tip.show) | |
.on('mouseout', tip.hide) | |
}); | |
</script> |
�PNG | |