Skip to content

Instantly share code, notes, and snippets.

@mjcoyle
Created August 15, 2018 18:09
Show Gist options
  • Save mjcoyle/a5c56d3b682afe106495529a641af352 to your computer and use it in GitHub Desktop.
Save mjcoyle/a5c56d3b682afe106495529a641af352 to your computer and use it in GitHub Desktop.
X and Y force splits
license: mit
[
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Muscular"
Service: "ServiceA"
Count: 1
TotalBytes: 1293823
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Echo"
Service: "Alert"
Count: 1
TotalBytes: 488996
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Delta"
Service: "ServiceB"
Count: 1
TotalBytes: 5510368
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Delta"
Service: "ServiceC"
Count: 1
TotalBytes: 4723001
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Cobalt"
Service: "ServiceD"
Count: 1
TotalBytes: 9251331
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Beta"
Service: "ServiceE"
Count: 1
TotalBytes: 21017388
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Beta"
Service: "ServiceF"
Count: 1
TotalBytes: 669657
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Echo"
Service: "Echo"
Count: 1
TotalBytes: 479949
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Beta"
Service: "ServiceG"
Count: 1
TotalBytes: 715733
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Beta"
Service: "ServiceH"
Count: 1
TotalBytes: 8693115
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Designer"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 8697
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Delta"
Service: "ServiceB"
Count: 1
TotalBytes: 12559664
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Delta"
Service: "ServiceC"
Count: 1
TotalBytes: 10005943
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Muscular"
Service: "ServiceA"
Count: 1
TotalBytes: 2530702
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Cobalt"
Service: "ServiceD"
Count: 1
TotalBytes: 24436925
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Delta"
Service: "ServiceJ"
Count: 1
TotalBytes: 44491
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Echo"
Service: "Alert"
Count: 1
TotalBytes: 753592
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Beta"
Service: "ServiceE"
Count: 1
TotalBytes: 13215785
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Beta"
Service: "ServiceF"
Count: 1
TotalBytes: 1338112
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Beta"
Service: "ServiceK"
Count: 1
TotalBytes: 102697
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Beta"
Service: "ServiceG"
Count: 1
TotalBytes: 1299100
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Beta"
Service: "ServiceH"
Count: 1
TotalBytes: 6037661
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Echo"
Service: "Echo"
Count: 1
TotalBytes: 654725
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Cobalt"
Service: "ServiceD"
Count: 1
TotalBytes: 1350606
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Echo"
Service: "Alert"
Count: 1
TotalBytes: 614452
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Muscular"
Service: "ServiceA"
Count: 1
TotalBytes: 1899648
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Muscular"
Service: "ServiceA"
Count: 1
TotalBytes: 2905325
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Beta"
Service: "ServiceG"
Count: 1
TotalBytes: 568408
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Delta"
Service: "ServiceC"
Count: 1
TotalBytes: 1647166
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Echo"
Service: "Echo"
Count: 1
TotalBytes: 638715
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Delta"
Service: "ServiceC"
Count: 1
TotalBytes: 9298148
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Beta"
Service: "ServiceH"
Count: 1
TotalBytes: 4136793
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Echo"
Service: "Echo"
Count: 1
TotalBytes: 572316
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Beta"
Service: "ServiceG"
Count: 1
TotalBytes: 896970
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Echo"
Service: "Alert"
Count: 1
TotalBytes: 549582
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Delta"
Service: "ServiceJ"
Count: 1
TotalBytes: 42675
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Cobalt"
Service: "ServiceD"
Count: 1
TotalBytes: 2222615
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Beta"
Service: "ServiceK"
Count: 1
TotalBytes: 24328
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 24103
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Delta"
Service: "ServiceJ"
Count: 1
TotalBytes: 20740
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Alpha"
Service: "ServiceL"
Count: 1
TotalBytes: 87925
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Beta"
Service: "ServiceK"
Count: 1
TotalBytes: 55537
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Alpha"
Service: "ServiceL"
Count: 1
TotalBytes: 111273
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 17433
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Cobalt"
Service: "Status"
Count: 1
TotalBytes: 11028
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Beta"
Service: "ServiceH"
Count: 1
TotalBytes: 1954930
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Analyst"
System: "Cobalt"
Service: "Status"
Count: 1
TotalBytes: 3676
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Designer"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 27263
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Delivery"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 27263
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Alpha"
Service: "ServiceL"
Count: 1
TotalBytes: 29501
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Analyst"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 27263
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Echo"
Service: "Alert"
Count: 1
TotalBytes: 1023211
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Echo"
Service: "Echo"
Count: 1
TotalBytes: 1168347
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Beta"
Service: "ServiceG"
Count: 1
TotalBytes: 1885594
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Cobalt"
Service: "ServiceD"
Count: 967
TotalBytes: 6268505
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Cobalt"
Service: "Status"
Count: 1
TotalBytes: 12866
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Delta"
Service: "ServiceC"
Count: 1
TotalBytes: 12438299
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Beta"
Service: "ServiceG"
Count: 1
TotalBytes: 1485710
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Echo"
Service: "Alert"
Count: 1
TotalBytes: 990838
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Delta"
Service: "ServiceC"
Count: 1
TotalBytes: 1968416
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Echo"
Service: "Echo"
Count: 1
TotalBytes: 1134382
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Cobalt"
Service: "ServiceD"
Count: 1
TotalBytes: 3760258
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Cobalt"
Service: "Status"
Count: 1
TotalBytes: 12866
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Beta"
Service: "ServiceH"
Count: 1
TotalBytes: 7533712
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 35112
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Beta"
Service: "ServiceH"
Count: 1
TotalBytes: 6628991
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 31745
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Research"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 27263
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Delta"
Service: "ServiceJ"
Count: 1
TotalBytes: 46020
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Cobalt"
Service: "Status"
Count: 1
TotalBytes: 11028
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Beta"
Service: "Status"
Count: 1
TotalBytes: 82018
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Alpha"
Service: "ServiceL"
Count: 1
TotalBytes: 237375
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Delta"
Service: "ServiceI"
Count: 1
TotalBytes: 20035
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Beta"
Service: "ServiceK"
Count: 1
TotalBytes: 211387
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Analyst"
System: "Beta"
Service: "ServiceK"
Count: 1
TotalBytes: 211387
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Beta"
Service: "ServiceK"
Count: 1
TotalBytes: 9783
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad B"
Node: "Engineer"
System: "Beta"
Service: "Status"
Count: 1
TotalBytes: 82018
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Alpha"
Service: "ServiceL"
Count: 1
TotalBytes: 237375
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad C"
Node: "Designer"
System: "Beta"
Service: "Status"
Count: 1
TotalBytes: 82018
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad D"
Node: "Designer"
System: "Beta"
Service: "Status"
Count: 1
TotalBytes: 82018
Time: "2018-08-08T21:19:48.024Z"
},
{
Domain: "OPS"
Location: "Squad A"
Node: "Engineer"
System: "Cobalt"
Service: "Status"
Count: 1
TotalBytes: 1838
Time: "2018-08-08T21:19:48.024Z"
}
]
<!DOCTYPE html>
<body>
<style>
html {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}
.button {
position: absolute;
bottom: 10px;
padding: 10px 20px;
font-size: 2em;
text-align: center;
background: #FFF;
border-radius: 5px;
border: 1px solid #DDD;
}
.button:hover {
background: #CCC;
cursor: pointer;
}
#locations {
right: 10px;
}
#systems {
right: 10px;
bottom: 75px;
}
/* svg { border: solid purple; }
g { border: solid blue; } */
</style>
<button id="locations" class="button">Territory</button>
<button id="systems" class="button">Teams</button>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
d3.json('data.json')
.then(function(data) {
console.log(data)
data = data.filter(d => d.System != "");
var locations = [...new Set(data.map(d => d.Location))];
var nodes = [...new Set(data.map(d => d.Node))];
var systems = [...new Set(data.map(d => d.System))]
console.log('systems', systems)
var margin = {left: 20, top: 20, right: 20, bottom: 20},
width = 950 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select('body').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 locScale = d3.scalePoint()
.range([margin.left,width-margin.right*6])
.domain(locations)
.padding(0.5);
var sysScale = d3.scalePoint()
.range([height-margin.bottom,margin.top*4])
.domain(systems)
.padding(0.5);
var countScale = d3.scaleLinear()
.range([5,20])
.domain(d3.extent(data, d => d.Count));
var nodeScale = d3.scaleOrdinal(d3.schemeSet1)
.domain([...new Set(data.map(d => d.Node))]);
nodeLeg();
//countLeg();
var locationsLables = svg.selectAll('text.locLables')
.data(locScale.domain())
.enter().append('text')
.attr('class', 'locLables')
.text(d => d)
.attr('x', width/2)
.attr('y', margin.top*3)
.attr('text-anchor', 'middle')
.attr('fill', '#fff');
var sysLables = svg.selectAll('text.sysLables')
.data(sysScale.domain())
.enter().append('text')
.attr('class', 'sysLables')
.text(d => d)
.attr('x', margin.left*2)
.attr('y', height - height/2)
.attr('text-anchor', 'middle')
.attr('fill', '#fff')
var xLocForce = d3.forceX(d => locScale(d.Location));
var ySysForce = d3.forceY(d => sysScale(d.System));
var locactionSplit = false;
var systemSplit = false;
document.getElementById('locations').onclick = function() {
if (!locactionSplit) {
simulation.force('x', xLocForce);
locationsLables.transition()
.attr('x', d => locScale(d))
.attr('fill', '#777')
} else {
simulation.force('x', centerXForce);
locationsLables.transition()
.attr('x', width/2)
.attr('fill', '#fff')
}
locactionSplit = !locactionSplit;
simulation.alpha(1).restart();
}
document.getElementById('systems').onclick = function() {
if (!systemSplit) {
simulation.force('y', ySysForce);
sysLables.transition()
.attr('y', d => sysScale(d))
.attr('fill', '#777')
} else {
simulation.force('y', centerYForce);
sysLables.transition()
.attr('y', height - height/2)
.attr('fill', '#fff')
}
systemSplit = !systemSplit;
simulation.alpha(1).restart();
}
var chargeForce = d3.forceManyBody().strength(-5)
var centerXForce = d3.forceX(width/2);
var centerYForce = d3.forceY(height/2);
var forceCollide = d3.forceCollide()
.strength(1)
.radius(d => countScale(d.Count) + 1)
.iterations(2);
var simulation = d3.forceSimulation()
.force('charge', chargeForce)
.force('collide', forceCollide)
.force('x', centerXForce)
.force('y', centerYForce)
var node = svg.selectAll('circle')
.data(data)
.enter().append('circle')
.attr('r', d => countScale(d.Count))
.attr('fill', d => nodeScale(d.Node));
simulation.nodes(data)
.on('tick', () => {
node.attr('cx', d => d.x)
.attr('cy', d => d.y);
});
function nodeLeg () {
var nodeLegend = svg.append('g')
.attr('transform', 'translate(' + (width - margin.right*5) + ',' + height/2 + ')')
.selectAll('g')
.data(nodeScale.domain())
.enter().append('g')
.attr('transform', (d,i) => 'translate(' + [0, i*20] + ')')
nodeLegend.append('text')
.text(d => d)
nodeLegend.append('circle')
.attr('fill', d => nodeScale(d))
.attr('cx', -10)
.attr('cy', -5)
.attr('r', 7)
}
function countLeg () {
var countLegend = svg.append('g')
.attr('transform', 'translate(' + (width - margin.right*5) + ',' + height*(3/4) + ')')
.selectAll('g')
.data(countScale.domain())
.enter().append('g')
countLegend.append('circle')
.attr('cx', 0)
.attr('cy', d => -countScale(d)/2)
.attr('r', d => countScale(d))
.attr('fill', 'none')
.attr('stroke', 'black')
.attr('stroke-width', 2)
}
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment