testing a simple swarm chart with force to see how much accuracy is lost with increase of nodes
Last active
May 22, 2017 19:43
-
-
Save eesur/b8a5d5c6ccd92bfc4f113ae1137c50ad to your computer and use it in GitHub Desktop.
d3 | swarm with force
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
function render(nodes) { | |
var svg = d3.select('svg') | |
var width = +svg.attr('width') | |
var height = +svg.attr('height') | |
var vis = svg.select('g.vis') | |
var axis = svg.select('g.axis') | |
var f = d3.format('.2f') | |
var xScale = d3.scaleLinear() | |
.domain([0, 100]) | |
.range([0, 900]) | |
var simulation = d3.forceSimulation(nodes) | |
.force('x', d3.forceX().x(function (d) { return xScale(d.value); }).strength(1)) | |
.force('y', d3.forceY().y(function (d) { return height/2; }).strength(1)) | |
.force('collision', d3.forceCollide(7))//.radius(d => d.radius + 1)) | |
simulation.stop() | |
for (var i = 0; i < nodes.length; ++i){ | |
simulation.tick() | |
} | |
//append circles | |
var u = vis.selectAll('circle') | |
.data(nodes) | |
u.enter() | |
.append('circle') | |
// .attr('r', d => d.radius + 1)) | |
.attr('r', 5) | |
.style('fill', function (d) { return d.color; }) | |
.merge(u) | |
.attr('cx', function (d) { return d.x; }) | |
.attr('cy', function (d) { return d.y; }) | |
.on('mouseover', function(d) { | |
d3.select('#js-info').text(("size: " + (f(d.radius)) + " | x: \n " + (f(d.value)))) | |
}) | |
u.exit().remove() | |
// render an axis | |
var xAxis = d3.axisBottom().scale(xScale) | |
axis.call(xAxis) | |
} | |
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> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<link href="https://unpkg.com/[email protected]/css/basscss.min.css" rel="stylesheet"> | |
<style> | |
body{ | |
font-family: Consolas, monaco, monospace; | |
position: relative; | |
padding: 20px; | |
color: #FDBB30; | |
background: #130C0E; | |
} | |
circle { | |
fill: #ec008c; | |
opacity: 0.6; | |
} | |
circle:hover { | |
opacity: 1; | |
} | |
.axis path, .axis line { | |
stroke: #FDBB30; | |
} | |
.axis text { | |
fill: #FDBB30; | |
font-family: Consolas, monaco, monospace; | |
} | |
input[type="range"] { | |
-webkit-appearance:none; | |
width: 100%; | |
height:2px; | |
background: #FDBB30; | |
background-position:center; | |
background-repeat:no-repeat; | |
margin: auto; | |
} | |
input[type="range"]::-webkit-slider-thumb { | |
-webkit-appearance:none; | |
width: 20px; | |
height: 20px; | |
border-radius: 100%; | |
background: #130C0E; | |
position:relative; | |
border: 3px solid #FDBB30; | |
z-index: 2; | |
cursor: pointer; | |
} | |
input:focus { | |
outline: none; | |
} | |
span { | |
letter-spacing: 3px; | |
color: #FDBB30; | |
} | |
</style> | |
</head> | |
<body> | |
<header class="fixed top-0 left-0 ml2 mt1"> | |
<p class="caps">Number of points: <span id="slider-amount">34</span></p> | |
<input type="range" id="point-amount" value="34"> | |
</header> | |
<svg width="960" height="400"> | |
<g class="vis" transform="translate(15, 10)"></g> | |
<g class="axis" transform="translate(15, 260)"></g> | |
</svg> | |
<footer> | |
<span id="js-info"></span> | |
</footer> | |
<script src="//d3js.org/d3.v4.min.js" charset="utf-8"></script> | |
<!-- d3 code --> | |
<script src=".script-compiled.js" charset="utf-8"></script> | |
<script> | |
// render some dummy data | |
var nodes = function(value) { | |
return d3.range(value).map((d) => { | |
return { | |
radius: Math.sqrt(d3.randomUniform(10, 100)()), | |
value: d3.randomUniform(10, 100)() | |
} | |
}) | |
} | |
// render swarm | |
render(nodes(34)) | |
// set a min and max to to the range slider | |
document.getElementById('point-amount').max = '300'; | |
document.getElementById('point-amount').min = '5'; | |
// when the input range changes re-render | |
d3.select('#point-amount').on('input', function() { | |
var value = +this.value | |
d3.select('#slider-amount').text(value) | |
render(nodes(value)); | |
}) | |
</script> | |
</body> | |
</html> | |
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
function render(nodes) { | |
const svg = d3.select('svg') | |
const width = +svg.attr('width') | |
const height = +svg.attr('height') | |
const vis = svg.select('g.vis') | |
const axis = svg.select('g.axis') | |
const f = d3.format('.2f') | |
const xScale = d3.scaleLinear() | |
.domain([0, 100]) | |
.range([0, 900]) | |
let simulation = d3.forceSimulation(nodes) | |
.force('x', d3.forceX().x(d => xScale(d.value)).strength(1)) | |
.force('y', d3.forceY().y(d => height/2).strength(1)) | |
.force('collision', d3.forceCollide(7))//.radius(d => d.radius + 1)) | |
simulation.stop() | |
for (let i = 0; i < nodes.length; ++i){ | |
simulation.tick() | |
} | |
//append circles | |
const u = vis.selectAll('circle') | |
.data(nodes) | |
u.enter() | |
.append('circle') | |
// .attr('r', d => d.radius + 1)) | |
.attr('r', 5) | |
.style('fill', d => d.color) | |
.merge(u) | |
.attr('cx', d => d.x) | |
.attr('cy', d => d.y) | |
.on('mouseover', function(d) { | |
d3.select('#js-info').text(`size: ${f(d.radius)} | x: | |
${f(d.value)}`) | |
}) | |
u.exit().remove() | |
// render an axis | |
const xAxis = d3.axisBottom().scale(xScale) | |
axis.call(xAxis) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment