Built with blockbuilder.org
Last active
November 3, 2024 16:01
-
-
Save dianaow/6a50292357511ceac3b78fc0fab4a2b5 to your computer and use it in GitHub Desktop.
D3 V4: Radial Point Chart
This file contains hidden or 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 hidden or 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"> | |
<meta name="viewport" content="width=device-width"> | |
<script src="http://d3js.org/d3.v4.min.js"></script> | |
<link href="https://fonts.googleapis.com/css?family=Karla" rel="stylesheet"> | |
</head> | |
<style> | |
text { | |
font-family: 'Karla', sans-serif; | |
} | |
#panel { | |
text-align: center; | |
} | |
.btn { | |
color: darkgray; | |
background: transparent; | |
border: 2px solid darkgray; | |
border-radius: 6px; | |
padding: 8px 16px; | |
text-align: center; | |
display: inline-block; | |
font-size: 0.8em; | |
margin: 4px 2px; | |
-webkit-transition-duration: 0.4s; /* Safari */ | |
transition-duration: 0.4s; | |
cursor: pointer; | |
text-decoration: none; | |
text-transform: uppercase; | |
} | |
.btn:hover { | |
background-color: darkgray; | |
color: white; | |
} | |
.btn:focus { | |
background-color: darkgray; | |
color: white; | |
} | |
</style> | |
<body> | |
<div id="chart"> | |
<div id='panel'> | |
<input name="type" | |
type="button" | |
class="btn" | |
id="update" | |
value="Update"/> | |
</div> | |
</div> | |
</div> | |
<script> | |
var radialChart = function () { | |
/////////////////////////////////////////////////////////////////////////// | |
///////////////////////////////// Globals ///////////////////////////////// | |
/////////////////////////////////////////////////////////////////////////// | |
var fociRadius, radial | |
var canvasDim = { width: screen.width, height: screen.height} | |
var margin = {top: screen.height/3, right: 20, bottom: 20, left: screen.width/2} | |
var width = canvasDim.width - margin.left - margin.right; | |
var height = canvasDim.height - margin.top - margin.bottom; | |
var modal = d3.select("#chart") | |
var t = d3.transition() | |
.duration(2000) | |
.ease(d3.easeQuadOut) | |
/////////////////////////////////////////////////////////////////////////// | |
///////////////////////////// Create scales /////////////////////////////// | |
/////////////////////////////////////////////////////////////////////////// | |
var scoreScale = d3.scaleLinear() | |
.domain([0, 1]) | |
var rScale = d3.scaleLinear() | |
.range([0, 2 * Math.PI]) | |
var fociRadius = d3.scaleLinear() | |
.range([150, 300]) | |
.domain([0, 1]) | |
var subgraphColor = d3.scaleLinear() | |
.range(['powderblue', 'darkorange', 'red']) | |
/////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////// CORE ////////////////////////////////// | |
/////////////////////////////////////////////////////////////////////////// | |
return { | |
clear : function () { | |
modal.select("svg").remove() | |
}, | |
run : function () { | |
//////////////////// Set up and initiate containers /////////////////////// | |
var svg = modal.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
g = svg.append("g") | |
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') | |
radialG = g.append("g") | |
.attr("class", "radialG") | |
pointsG = g.append("g") | |
.attr("class", "pointsG") | |
////////////////////////// Run animation sequence ///////////////////////// | |
var data = getData() | |
radialChart(data.subgraphs, data.subgraph_nested) | |
donutChart(data.subgraph_nested) | |
d3.select('#update').on("click", function () { | |
data.subgraphs.forEach((d) => { | |
d.scores = randBetween(0.2, 1) | |
}) | |
updatePoints(data.subgraphs) | |
}) | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////// Data Processing /////////////////////////// | |
/////////////////////////////////////////////////////////////////////////// | |
function getData(){ | |
var subgraphs = [] | |
d3.range(1,100).forEach((d,i) => { | |
subgraphs.push({ | |
scores : randBetween(0.2, 1), | |
index : i, | |
subgraph : getRandomInt(0, 4).toString() | |
}) | |
}) | |
subgraphs.sort(function(x, y){ | |
return d3.ascending(x.subgraph, y.subgraph); //sort by subgraph number | |
}) | |
var subgraph_nested = d3.nest() | |
.key(function(d) { return +d.subgraph; }) | |
.rollup(function(leaves) { return leaves.length; }) | |
.entries(subgraphs) | |
console.log(subgraph_nested) | |
var subgraph_lists = subgraph_nested.map(d=>d.key) | |
subgraphColor.domain([0, subgraph_lists.length, 1]) | |
return {subgraphs: subgraphs, subgraph_nested: subgraph_nested} | |
} | |
function donutChart(subgraph_nested) { | |
var pie = d3.pie() | |
.sort(null) | |
.value(function(d) { return d.value; }); | |
var path = d3.arc() | |
.outerRadius(fociRadius.range()[0] - 15) | |
.innerRadius(fociRadius.range()[0] - 35) | |
var label = d3.arc() | |
.outerRadius(fociRadius.range()[0] - 15) | |
.innerRadius(fociRadius.range()[0] - 35) | |
var arc = radialG.selectAll(".arc") | |
.data(pie(subgraph_nested)) | |
.enter().append("g") | |
.attr("class", "arc"); | |
arc.append("path") | |
.attr("d", path) | |
.attr("fill", function(d,i) { return subgraphColor(d.data.key) }) | |
.each(function(d,i) { | |
var firstArcSection = /(^.+?)L/; | |
var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1]; | |
newArc = newArc.replace(/,/g , " "); | |
//Create a new invisible arc that the text can flow along | |
arc.append("path") | |
.attr("class", "hiddenDonutArcs") | |
.attr("id", "donutArc"+i) | |
.attr("d", newArc) | |
.style("fill", "none"); | |
}) | |
arc.append("text") | |
.attr("dy", "1em") | |
.attr('fill', 'white') | |
.append("textPath") | |
.attr("xlink:href",function(d,i){return "#donutArc"+i;}) | |
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; }) | |
.style("text-anchor","middle") | |
.attr("startOffset", "50%") | |
.text(function(d) { return d.data.key; }); | |
} | |
/////////////////////// Create radial chart for subgraph scores ////////////////// | |
function radialChart(subgraphs) { | |
var ticks = fociRadius.ticks(5).slice(1) | |
ticks.unshift(0) | |
// create concentric lines | |
radial = radialG.selectAll('g').data(ticks, d=>d) | |
var gr = radial.enter().append('g') | |
.attr('class', 'r axis') | |
gr.append('circle') | |
.attr('r', fociRadius) | |
.attr('stroke', function(d) {return 'darkgray'}) | |
.attr('fill', function(d) {return 'none'}) | |
gr.append("text") | |
.attr("y", fociRadius) | |
.attr("dy", "0.35em") | |
.attr("fill", "none") | |
.attr("stroke", "black") | |
.attr("stroke-width", 1) | |
.attr("stroke-linejoin", "round") | |
.text(function(d) { return d }) | |
// create polar scatter plot | |
scoreScale.range([fociRadius.range()[0], fociRadius.range()[1]]) | |
rScale.domain([0, subgraphs.length]) | |
subgraphs.map((d,i)=>{ | |
d.index = i | |
}) | |
updatePoints(subgraphs) | |
} | |
function updatePoints(data) { | |
var line = d3.lineRadial() | |
.radius(function(d) { return scoreScale(d.scores) }) | |
.angle(function(d,i) { return rScale(d.index) }) | |
radialPoint = pointsG.selectAll('circle').data(data, d=>d.index) | |
radialPoint.exit().remove() | |
var entered_radialPoint = radialPoint | |
.enter().append('circle') | |
.attr('class', function(d) { return 'point-' + d.index }) | |
.attr('transform', function(d) { | |
var coors = line([d]).slice(1).slice(0, -1); // removes 'M' and 'Z' from string | |
return 'translate(' + coors + ')' | |
}) | |
.attr('r', function(d) { return 4 }) | |
.attr('fill',function(d,i){ return subgraphColor(d.subgraph) }) | |
radialPoint = radialPoint.merge(entered_radialPoint) | |
radialPoint.transition().duration(2000).ease(d3.easeQuadOut) | |
.attr('transform', function(d) { | |
var coors = line([d]).slice(1).slice(0, -1); // removes 'M' and 'Z' from string | |
return 'translate(' + coors + ')' | |
}) | |
} | |
function randBetween(min, max) { | |
return min + (max - min) * Math.random(); | |
} | |
function getRandomInt(min, max) { | |
min = Math.ceil(min); | |
max = Math.floor(max); | |
return Math.floor(Math.random() * (max - min + 1)) + min; | |
} | |
}() | |
</script> | |
<script> | |
radialChart.run() | |
</script> | |
</body> | |
</html> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment