Created
June 20, 2023 23:42
-
-
Save johnbaums/b0cf365c978d144afb6a77a9ba80b288 to your computer and use it in GitHub Desktop.
R2D3 implementation of https://d3-graph-gallery.com/graph/bubble_template.html
This file contains 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
.bubbles { | |
stroke-width: 1px; | |
stroke: black; | |
opacity: .8 | |
} | |
.bubbles:hover { | |
stroke: black; | |
} | |
* { | |
font-family: sans-serif; | |
} | |
.tooltip { | |
position: absolute; | |
} | |
.tooltip:hover, text { | |
cursor: default; | |
} |
This file contains 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
// https://d3-graph-gallery.com/graph/bubble_template.html | |
// !preview r2d3 data=readr::read_csv("testd3.csv"), d3_version="6", container="div" | |
// | |
// r2d3: https://rstudio.github.io/r2d3 | |
// | |
// set the dimensions and margins of the graph | |
var margin = {top: 40, right: window.innerWidth * 0.3, bottom: 60, left: 30}, | |
width = width - margin.left - margin.right, | |
height = height - margin.top - margin.bottom; | |
// append the svg object to the body of the page | |
var svg = div | |
.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 + ")"); | |
//Read the data | |
r2d3.onRender(function(data, s, w, h, options) { | |
// ---------------------------// | |
// AXIS AND SCALE // | |
// ---------------------------// | |
// Add X axis | |
var x = d3.scaleLinear() | |
.domain([0, 50000]) | |
.range([ 0, width ]); | |
svg.append("g") | |
.attr("transform", "translate(0," + height + ")") | |
.call(d3.axisBottom(x).ticks(4)); | |
// Add X axis label: | |
svg.append("text") | |
.attr("text-anchor", "end") | |
.attr("x", width) | |
.attr("y", height+50 ) | |
.text("GDP per Capita"); | |
// Add Y axis | |
var y = d3.scaleLinear() | |
.domain([35, 90]) | |
.range([ height, 0]); | |
svg.append("g") | |
.call(d3.axisLeft(y)); | |
// Add Y axis label: | |
svg.append("text") | |
.attr("text-anchor", "end") | |
.attr("x", 0) | |
.attr("y", -20 ) | |
.text("Life expectancy") | |
.attr("text-anchor", "start") | |
// Add a scale for bubble size | |
var z = d3.scaleSqrt() | |
.domain([200000, 1310000000]) | |
.range([ 2, 30]); | |
// Add a scale for bubble color | |
var myColor = d3.scaleOrdinal() | |
.domain(["Asia", "Europe", "Americas", "Africa", "Oceania"]) | |
.range(d3.schemeSet1); | |
// ---------------------------// | |
// TOOLTIP // | |
// ---------------------------// | |
// -1- Create a tooltip div that is hidden by default: | |
var tooltip = div | |
.append("div") | |
.style("opacity", 0) | |
.attr("class", "tooltip") | |
.style("background-color", "black") | |
.style("border-radius", "5px") | |
.style("border-style", "solid") | |
.style("border-width", "2px") | |
.style("padding", "10px") | |
.style("color", "white") | |
// -2- Create 3 functions to show / update (when mouse move but stay on same circle) / hide the tooltip | |
var showTooltip = function(event, d) { | |
//console.log(+new Date) | |
tooltip | |
.style("opacity", 1) | |
.style("border-color", myColor(d.continent)) | |
.html(d.country) | |
.style("left", (event.pageX - margin.left) + "px") | |
.style("top", (event.pageY - margin.bottom) + "px") | |
} | |
var moveTooltip = function(event, d) { | |
tooltip | |
.style("left", (event.pageX - margin.left) + "px") | |
.style("top", (event.pageY - margin.bottom) + "px") | |
} | |
var hideTooltip = function(event, d) { | |
tooltip | |
.style("opacity", 0) | |
} | |
// ---------------------------// | |
// HIGHLIGHT GROUP // | |
// ---------------------------// | |
// What to do when one group is hovered | |
var highlight = function(event, d){ | |
// reduce opacity of all groups | |
d3.selectAll(".bubbles").style("opacity", .05) | |
// expect the one that is hovered | |
d3.selectAll("."+d).style("opacity", 1) | |
} | |
// And when it is not hovered anymore | |
var noHighlight = function(event, d){ | |
d3.selectAll(".bubbles").style("opacity", 1) | |
} | |
// ---------------------------// | |
// CIRCLES // | |
// ---------------------------// | |
// Add dots | |
svg.append('g') | |
.selectAll("dot") | |
.data(data) | |
.enter() | |
.append("circle") | |
.attr("class", function(d) { return "bubbles " + d.continent }) | |
.attr("cx", function (d) { return x(d.gdpPercap); } ) | |
.attr("cy", function (d) { return y(d.lifeExp); } ) | |
.attr("r", function (d) { return z(d.pop); } ) | |
.attr("fill", function(d) { return myColor(d.continent); } ) | |
//.style("fill", function (d) { return myColor(d.continent); } ) | |
// -3- Trigger the functions for hover | |
.on("mouseover", showTooltip) | |
.on("mousemove", moveTooltip) | |
.on("mouseout", hideTooltip) | |
// ---------------------------// | |
// LEGEND // | |
// ---------------------------// | |
// Add legend: circles | |
var valuesToShow = [10000000, 100000000, 1000000000] | |
var xCircle = window.innerWidth * 0.75 | |
var xLabel = window.innerWidth * 0.75 + 50 | |
svg | |
.selectAll("legend") | |
.data(valuesToShow) | |
.enter() | |
.append("circle") | |
.attr("cx", xCircle) | |
.attr("cy", function(d){ return height - 100 - z(d) } ) | |
.attr("r", function(d){ return z(d) }) | |
.attr("fill", "none") | |
//.style("fill", "none") | |
.attr("stroke", "black") | |
// Add legend: segments | |
svg | |
.selectAll("legend") | |
.data(valuesToShow) | |
.enter() | |
.append("line") | |
.attr('x1', function(d){ return xCircle + z(d) } ) | |
.attr('x2', xLabel) | |
.attr('y1', function(d){ return height - 100 - z(d) } ) | |
.attr('y2', function(d){ return height - 100 - z(d) } ) | |
.attr('stroke', 'black') | |
.style('stroke-dasharray', ('2,2')) | |
// Add legend: labels | |
svg | |
.selectAll("legend") | |
.data(valuesToShow) | |
.enter() | |
.append("text") | |
.attr('x', xLabel) | |
.attr('y', function(d){ return height - 100 - z(d) } ) | |
.text( function(d){ return d/1000000 } ) | |
.style("font-size", 10) | |
.attr('alignment-baseline', 'middle') | |
// Legend title | |
svg.append("text") | |
.attr('x', xCircle) | |
.attr("y", height - 100 +30) | |
.text("Population (M)") | |
.attr("text-anchor", "middle") | |
// Add one dot in the legend for each name. | |
var size = 20 | |
var allgroups = ["Asia", "Europe", "Americas", "Africa", "Oceania"] | |
svg.selectAll("myrect") | |
.data(allgroups) | |
.enter() | |
.append("circle") | |
.attr("cx", window.innerWidth*0.75) | |
.attr("cy", function(d,i){ return 10 + i*(size+5)}) // 100 is where the first dot appears. 25 is the distance between dots | |
.attr("r", 8) | |
.attr("fill", function(d){ return myColor(d)}) | |
//.style("fill", function(d){ return myColor(d)}) | |
.on("mouseover", highlight) | |
.on("mouseleave", noHighlight) | |
// Add labels beside legend dots | |
svg.selectAll("mylabels") | |
.data(allgroups) | |
.enter() | |
.append("text") | |
.attr("x", window.innerWidth*0.75 + size*.6) | |
.attr("y", function(d,i){ return i * (size + 5) + (size*0.6)}) // 100 is where the first dot appears. 25 is the distance between dots | |
.attr("fill", function(d){ return myColor(d)}) | |
//.style("fill", function(d){ return myColor(d)}) | |
.text(function(d){ return d}) | |
.attr("text-anchor", "left") | |
.style("alignment-baseline", "middle") | |
.on("mouseover", highlight) | |
.on("mouseleave", noHighlight) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment