Skip to content

Instantly share code, notes, and snippets.

@jwilber
Last active January 22, 2019 02:58
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 jwilber/17752024b84bdaf086cbc0aa8cb707d6 to your computer and use it in GitHub Desktop.
Save jwilber/17752024b84bdaf086cbc0aa8cb707d6 to your computer and use it in GitHub Desktop.
Dot plot histogram event-trigger
license: gpl-3.0
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<button id="clickMe" type="button"
style='font-size:30px; position: absolute;'>Add Nodes</button>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
//SVG setup
const margin = {top: 10, right: 30, bottom: 30, left: 30},
width = 550 - margin.left - margin.right,
height = 480 - margin.top - margin.bottom;
let allData = d3.range(1000).map((d,i) => ({r: 40 - i * 0.5,
Value: width/2 + d3.randomNormal(0, 1.5)() * 50,
nodeGroup: i <= 23 ? 'llama' : i <= 39 ? 'resp' : 'dsn',
dotValue: i % 2 === 0 ?
d3.randomNormal(8, 2.5)().toFixed(1):
d3.randomNormal(4.5, .75)().toFixed(1)}));
//x scales
//x scales
const x = d3.scaleLinear()
.domain(d3.extent(allData, d => +d.Value))
.rangeRound([0, width]);
//set up svg
const 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})`);
const t = d3.transition()
.duration(1000);
const dataFile = "roster.csv"
//number of bins for histogram
const nbins = 20;
//Note: data fetching is done each time the function is ran
//as d3.csv is replaced by tabletop.js request to get data each time
//from google spreadsheet
function update(num){
// Get the data
allData.forEach(function(d) {
d.Value = +d.Value;
});
//simulate new data by randomizing/slicing
let data = allData.slice(0, 0+num)
//histogram binning
const histogram = d3.histogram()
.domain(x.domain())
.thresholds(x.ticks(nbins))
.value(function(d) { return d.Value;} )
//binning data and filtering out empty bins
const bins = histogram(data).filter(d => d.length>0)
//g container for each bin
let binContainer = svg.selectAll(".gBin")
.data(bins);
binContainer.exit().remove()
let binContainerEnter = binContainer.enter()
.append("g")
.attr("class", "gBin")
.attr("transform", d => `translate(${x(d.x0)}, ${height})`)
//need to populate the bin containers with data the first time
binContainerEnter.selectAll("circle")
.data(d => d.map((p, i) => {
return {idx: i,
name: p.Name,
value: p.Value,
radius: (x(d.x1)-x(d.x0))/2
}
}))
.enter()
.append("circle")
.attr("cx", 0) //g element already at correct x pos
.attr("cy", function(d) {
return - d.idx * 2 * d.radius - d.radius; })
.attr("r", 0)
.transition()
.duration(500)
.attr("r", function(d) {
return (d.length==0) ? 0 : d.radius; })
binContainerEnter.merge(binContainer)
.attr("transform", d => `translate(${x(d.x0)}, ${height})`)
//enter/update/exit for circles, inside each container
let dots = binContainer.selectAll("circle")
.data(d => d.map((p, i) => {
return {idx: i,
name: p.Name,
value: p.Value,
radius: (x(d.x1)-x(d.x0))/2
}
}))
//UPDATE old elements present in new data.
dots.attr("class", "update");
//ENTER new elements present in new data.
dots.enter()
.append("circle")
.attr("class", "enter")
.attr("cx", 0) //g element already at correct x pos
.attr("cy", function(d) {
return - d.idx * 2 * d.radius - d.radius; })
.attr("r", 0)
.merge(dots)
.transition()
.duration(500)
.attr("r", function(d) {
return (d.length==0) ? 0 : d.radius; })
};//update
// add x axis
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
//draw everything
update(0);
let clicked = 1;
d3.select('#clickMe')
.on('click', function() {
update(clicked);
clicked == 0 || clicked == 1 ? clicked = clicked + 1 : clicked = 200;
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment