Skip to content

Instantly share code, notes, and snippets.

@chloerulesok
Last active November 5, 2017 21:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chloerulesok/e45c8bb1241c4f6051ef30623e6fe552 to your computer and use it in GitHub Desktop.
Save chloerulesok/e45c8bb1241c4f6051ef30623e6fe552 to your computer and use it in GitHub Desktop.
Scatterplot/Beeswarm/forceSimulation/forceCollide
license: mit
<!DOCTYPE html>
<meta charset="utf-8">
<p id="g1"></p>
<head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 14px;
}
div.tooltip {
position: absolute;
text-align: center;
/*width: 150px;*/
height: 28px;
padding: 2px 5px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<script src="//d3js.org/d3.v4.min.js"></script>
</head>
<body ng-app="app" ng-controller="ctrl">
<!--
Regexable filter: (e.g. "aa" or (aa|bb))
<input type="text" ng-model="filteringSelection" ng-change="updateFilter()">
-->
<div id="chart"></div>
</body>
<script>
var items = ['aaa', 'bbb', 'ccc'];
// *** Create data
function randomData(samples) {
var data = [];
var random = d3.randomNormal();
for (i = 0; i < samples; i++) {
var date = new Date(+(new Date()) - Math.floor(Math.random()*1000000000));
data.push({
datetime: date,
pivot: items[Math.floor(Math.random()*items.length)]
});
}
return data;
}
// *** Create random data set using above function
var fullData = randomData(300);
// *** Set up svg
var margin = { top: 20, right: 20, bottom: 60, left: 60 };
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var tooltip = d3.select("#chart").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var x = d3.scaleTime().range([0, width-margin.left]).nice();
var y = d3.scaleBand().rangeRound([0, height]);
// *** Parse the date / time
var parseDate = d3.timeParse("%e/%m/%Y");
var formatDateTime = d3.timeFormat("%e/%m/%Y" );
var parseTime = d3.timeParse("%H:%M:%S");
var formatDateTime = d3.timeFormat("%e/%m/%Y %H:%M:%S");
// *** Scale the range of the data
var earliestDate = d3.min(fullData, function(d) { return d.datetime; });
var latestDate = d3.max(fullData, function(d) { return d.datetime; });
x.domain([earliestDate, latestDate]);
y.domain(d3.map(fullData, function(d){return d.pivot;}).keys().sort());
var xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat("%Y-%m-%d"));
var yAxis = d3.axisLeft(y);
fullData.forEach(function(d) {
d.idealy = y(d.pivot)+((height/items.length)/2);
});
var svg = d3.select("#chart").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 clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width )
.attr("height", height )
.attr("x", 0)
.attr("y", 0);
var scatter = svg.append("g")
.attr("id", "scatterplot")
.attr("clip-path", "url(#clip)");
var colour = d3.scaleOrdinal()
.domain(d3.map(fullData, function(d){return d.pivot;}).keys())
.range(d3.schemeCategory10);
// x axis
svg.append("g")
.attr("class", "x axis")
.attr('id', "axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
svg.append("text")
.style("text-anchor", "end")
.attr("x", width)
.attr("y", height - 8)
.text("Date");
// y axis
svg.append("g")
.attr("class", "y axis")
.attr('id', "axis--y")
.call(yAxis);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "1em")
.style("text-anchor", "end")
.text("Time");
var simulation = d3.forceSimulation(fullData)
.force("x", d3.forceX(function(d) { return x(d.datetime); }))
.force("y", d3.forceY(function(d) { return d.idealy; }))
.force("collide", d3.forceCollide(4)
.strength(1)
.iterations(2))
.stop();
console.log(fullData[0]);
for (var i = 0; i < 120; ++i) simulation.tick();
scatter.selectAll(".dot")
.data(fullData)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 4)
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) { return d.y; })
.attr("opacity", 0.7)
.style("fill", function(d) { return colour(d.pivot); })
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(formatDateTime(d.datetime) + "<br/>" + d.pivot)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment