Built with blockbuilder.org
Last active
January 24, 2021 22:56
-
-
Save SpaceActuary/d6b5ca8e5fb17842d652d0de21e88a05 to your computer and use it in GitHub Desktop.
Group Clustering
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
license: mit |
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
ID | Location | Group | Class | Type | |
---|---|---|---|---|---|
1 | 1 | A | X | M | |
2 | 1 | A | Y | N | |
3 | 1 | A | Y | N | |
4 | 1 | B | Z | M | |
5 | 1 | B | Y | M | |
6 | 1 | B | X | N | |
7 | 1 | B | Z | N | |
8 | 2 | A | Z | M | |
9 | 2 | B | Z | M | |
10 | 2 | B | Y | N | |
11 | 2 | B | X | N | |
12 | 2 | B | X | M |
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> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { | |
margin:0; | |
position:fixed; | |
top:0; | |
right:0; | |
bottom:0; | |
left:0; | |
font-family: sans-serif; | |
} | |
.selected { | |
fill: none; | |
} | |
.button { | |
min-width: 130px; | |
padding: 4px 5px; | |
cursor: pointer; | |
text-align: center; | |
font-size: 13px; | |
border: 1px solid #e0e0e0; | |
text-decoration: none; | |
} | |
.button.active { | |
background: #000; | |
color: #fff; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="toolbar"> | |
<button id="all" class="button active">All</button> | |
<button id="Location" class="button">By Location</button> | |
<button id="Group" class="button">By Group</button> | |
<button id="Class" class="button">By Class</button> | |
<button id="Type" class="button">By Type</button> | |
</div> | |
<script> | |
console.clear() | |
var w = 960, h = 500; | |
var radius = 25; | |
var color = d3.scaleOrdinal(d3.schemeCategory20); | |
var centerScale = d3.scalePoint().padding(1).range([0, w]); | |
var forceStrength = 0.05; | |
var svg = d3.select("body").append("svg") | |
.attr("width", w) | |
.attr("height", h) | |
var simulation = d3.forceSimulation() | |
.force("collide",d3.forceCollide( function(d){ | |
return d.r + 8 }).iterations(16) | |
) | |
.force("charge", d3.forceManyBody()) | |
.force("y", d3.forceY().y(h / 2)) | |
.force("x", d3.forceX().x(w / 2)) | |
d3.csv("data.csv", function(data){ | |
data.forEach(function(d){ | |
d.r = radius; | |
d.x = w / 2; | |
d.y = h / 2; | |
}) | |
console.table(data); | |
var circles = svg.selectAll("circle") | |
.data(data, function(d){ return d.ID ;}); | |
var circlesEnter = circles.enter().append("circle") | |
.attr("r", function(d, i){ return d.r; }) | |
.attr("cx", function(d, i){ return 175 + 25 * i + 2 * i ** 2; }) | |
.attr("cy", function(d, i){ return 250; }) | |
.style("fill", function(d, i){ return color(d.ID); }) | |
.style("stroke", function(d, i){ return color(d.ID); }) | |
.style("stroke-width", 10) | |
.style("pointer-events", "all") | |
.call(d3.drag() | |
.on("start", dragstarted) | |
.on("drag", dragged) | |
.on("end", dragended)); | |
circles = circles.merge(circlesEnter) | |
function ticked() { | |
//console.log("tick") | |
//console.log(data.map(function(d){ return d.x; })); | |
circles | |
.attr("cx", function(d){ return d.x; }) | |
.attr("cy", function(d){ return d.y; }); | |
} | |
simulation | |
.nodes(data) | |
.on("tick", ticked); | |
function dragstarted(d,i) { | |
//console.log("dragstarted " + i) | |
if (!d3.event.active) simulation.alpha(1).restart(); | |
d.fx = d.x; | |
d.fy = d.y; | |
} | |
function dragged(d,i) { | |
//console.log("dragged " + i) | |
d.fx = d3.event.x; | |
d.fy = d3.event.y; | |
} | |
function dragended(d,i) { | |
//console.log("dragended " + i) | |
if (!d3.event.active) simulation.alphaTarget(0); | |
d.fx = null; | |
d.fy = null; | |
var me = d3.select(this) | |
console.log(me.classed("selected")) | |
me.classed("selected", !me.classed("selected")) | |
d3.selectAll("circle") | |
.style("fill", function(d, i){ return color(d.ID); }) | |
d3.selectAll("circle.selected") | |
.style("fill", "none") | |
} | |
function groupBubbles() { | |
hideTitles(); | |
// @v4 Reset the 'x' force to draw the bubbles to the center. | |
simulation.force('x', d3.forceX().strength(forceStrength).x(w / 2)); | |
// @v4 We can reset the alpha value and restart the simulation | |
simulation.alpha(1).restart(); | |
} | |
function splitBubbles(byVar) { | |
centerScale.domain(data.map(function(d){ return d[byVar]; })); | |
if(byVar == "all"){ | |
hideTitles() | |
} else { | |
showTitles(byVar, centerScale); | |
} | |
// @v4 Reset the 'x' force to draw the bubbles to their year centers | |
simulation.force('x', d3.forceX().strength(forceStrength).x(function(d){ | |
return centerScale(d[byVar]); | |
})); | |
// @v4 We can reset the alpha value and restart the simulation | |
simulation.alpha(2).restart(); | |
} | |
function hideTitles() { | |
svg.selectAll('.title').remove(); | |
} | |
function showTitles(byVar, scale) { | |
// Another way to do this would be to create | |
// the year texts once and then just hide them. | |
var titles = svg.selectAll('.title') | |
.data(scale.domain()); | |
titles.enter().append('text') | |
.attr('class', 'title') | |
.merge(titles) | |
.attr('x', function (d) { return scale(d); }) | |
.attr('y', 40) | |
.attr('text-anchor', 'middle') | |
.text(function (d) { return byVar + ' ' + d; }); | |
titles.exit().remove() | |
} | |
function setupButtons() { | |
d3.selectAll('.button') | |
.on('click', function () { | |
// Remove active class from all buttons | |
d3.selectAll('.button').classed('active', false); | |
// Find the button just clicked | |
var button = d3.select(this); | |
// Set it as the active button | |
button.classed('active', true); | |
// Get the id of the button | |
var buttonId = button.attr('id'); | |
console.log(buttonId) | |
// Toggle the bubble chart based on | |
// the currently clicked button. | |
splitBubbles(buttonId); | |
}); | |
} | |
setupButtons() | |
}) | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment