D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jwilber
Full window
Github gist
apply pack layout to existing nodes
Built with
blockbuilder.org
<!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; } </style> </head> <svg style="width:600px;height:600px;" ></svg> <body> <script> const width = 500; const height = 400; const svgD3 = d3.select('svg') let sampleData = d3.range(250).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(7, 2.5)().toFixed(1): d3.randomNormal(4.5, .75)().toFixed(1), permDsn: d3.randomNormal(0, 1)().toFixed(1) })); const x = d3.scaleLinear() .domain(d3.extent(sampleData.filter(d => d.nodeGroup === 'dsn'), d => +d.permDsn)) .rangeRound([width/4, width/1.5]); // hist width(left, right) const nbins = 18; function update(){ let data = sampleData //histogram binning const histogram = d3.histogram() .domain(x.domain()) .thresholds(x.ticks(nbins)) .value(d => d.permDsn); //binning data and filtering out empty bins const bins = histogram(data); //g container for each bin let binContainer = svgD3.append('g') .attr('transform', `translate({x(d.x0)}, ${-height/8})`) .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(".preHistPosit") .data((d,i) => d.map((p, j) => { return {idx: j, dataIndex: i, value: p.Value, radius: (x(d.x1)-x(d.x0))/2 } })) .enter() .append("circle") .attr('class', 'histCirc') .attr('testStatValue', d => d.permDsn) .attr('', function(d,i) { if (i < 1 && d.dataIndex == 20) { d3.select(this).classed('response1', true) } else if (i < 1 && d.dataIndex == 9) { d3.select(this).classed('response2', true) } else if (i < 1 && d.dataIndex == 5) { d3.select(this).classed('response3', true) } else if (i < 1 && d.dataIndex == 11) { d3.select(this).classed('response4', true) } else if (i < 1 && d.dataIndex == 7) { d3.select(this).classed('response5', true) } else if (i < 1 && d.dataIndex == 6) { d3.select(this).classed('response6', true) } else if (i < 1 && d.dataIndex == 13) { d3.select(this).classed('response7', true) } else if (i < 1 && d.dataIndex == 8) { d3.select(this).classed('response8', true) } else if (i < 1 && d.dataIndex == 2) { d3.select(this).classed('response9', true) } else { d3.select(this).classed('histogramNode', true) } }) .attr('', function(d) { if (d.dataIndex > 19) { // determine which test-stat nodes to highlight d3.select(this).classed('extreme', true) } else { d3.select(this).classed('notExtreme', true) } }) .transition() .attr("cx", 0) //g element already at correct x pos .attr("cy", d => - d.idx * 2 * d.radius - d.radius - (height/8)) // control height here .attr("r", 10) .transition() .duration(800) .attr('r', 8) .transition() .attr('stroke-width', .3) .attr('stroke', 'black') 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, value: p.Value, radius: (x(d.x1)-x(d.x0))/2 } })) //UPDATE old elements present in new data. //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", 10) .merge(dots) .transition() .duration(500) .attr("r", function(d) { return (d.length==0) ? 10 : d.radius; }) };//update update(); </script> </body>
https://d3js.org/d3.v4.min.js