d3.js mouse-over effects for your scatter plot

KJ Schmidt
4 min readMar 12, 2019

--

This tutorial uses d3.js version 4.6.0 and builds off of a scatter plot I made a tutorial for previously. You can see the scatter plot with hover effects on my data visualization project or check it out in the gif below.

Hover effects — Where do they go?

Let’s start by identifying where this code needs to be. We need to find the code that draws our data points. That way, the effect can take place when the user hovers over any data point. Drawing our data points is happening here in our path variable, so that’s where we’ll be adding our hover effects.

var path = svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function (d) {
return x(d.date);
})
.attr("cy", function (d) {
return y(d.wage);
})
.attr("stroke", "#32CD32")
.attr("stroke-width", 1.5)
.attr("fill", "#FFFFFF");

Adding effects

To add hover effects, we’ll need to use the .on method with mouseover and mouseout. I wanted my data points to get bigger when the user hovered over them. To do this, I’m using .attr to change the radius of the points. .duration allows me to control the speed of the data point growing on mouseover and shrinking back to original size on mouseout.

.on('mouseover', function (d, i) {
d3.select(this).transition()
.duration('100')
.attr("r", 7);
})
.on('mouseout', function (d, i) {
d3.select(this).transition()
.duration('200')
.attr("r", 5);
});

Now our graph looks like this:

Showing value on hover

Showing the data point’s value on hover requires a little more code. First, we need to add a div to hold the value we want to show. The div should be set at 0 opacity so it’s initially hidden. I added a class on mine so I can style it with CSS.

var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);

Speaking of CSS, this is the CSS I’m using to style it:

div.tooltip {
position: absolute;
text-align: center;
padding: .2rem;
background: #313639;
color: #f9f9f9;
border: 0px;
border-radius: 8px;
pointer-events: none;
font-size: .7rem;
}

Now we need to make our div appear and disappear on hover. We’ll do this in the mouseover and mouseout sections we wrote earlier:

.on('mouseover', function (d, i) {
d3.select(this).transition()
.duration('100')
.attr("r", 7);
//Makes div appear
div.transition()
.duration(100)
.style("opacity", 1);
})
.on('mouseout', function (d, i) {
d3.select(this).transition()
.duration('200')
.attr("r", 5);
//makes div disappear
div.transition()
.duration('200')
.style("opacity", 0);
});

Great! We’ve got a styled div that appears on hover and disappears when we mouseout. Now all we need to do is insert the data point’s value and place it near the mouse. This will happen in the mouseover function.

To insert the value, we’ll just be feeding our data into div.html(). For the placement, we’ll be using d3.event.pageX and d3.event.pageY. Make sure to adjust the +/- values to numbers that make sense for your graph.

div.html(d.wage)
.style("left", (d3.event.pageX + 10) + "px")
.style("top", (d3.event.pageY - 15) + "px");

Because my data is currency, I have some extra formatting. First I’m adding a dollar sign to the beginning, then I'm using d3.format() to format the numbers to two decimal places.

div.html("$" + d3.format(".2f")(d.wage))
.style("left", (d3.event.pageX + 10) + "px")
.style("top", (d3.event.pageY - 15) + "px");

Our finished div and path javascript looks like this:

var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var path = svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function (d) {
return x(d.date);
})
.attr("cy", function (d) {
return y(d.wage);
})
.attr("stroke", "#32CD32")
.attr("stroke-width", 1.5)
.attr("fill", "#FFFFFF");
.on('mouseover', function (d, i) {
d3.select(this).transition()
.duration('100')
.attr("r", 7);
div.transition()
.duration(100)
.style("opacity", 1);
div.html("$" + d3.format(".2f")(d.wage))
.style("left", (d3.event.pageX + 10) + "px")
.style("top", (d3.event.pageY - 15) + "px");
})
.on('mouseout', function (d, i) {
d3.select(this).transition()
.duration('200')
.attr("r", 5);
div.transition()
.duration('200')
.style("opacity", 0);
});

You did it!

You’ve built a scatter plot, added effects, and are showing values on hover. Amazing!

If you’re having any issues, check out the full code on github. Make this graph responsive with my other tutorial.

--

--

KJ Schmidt

ML Scientist at UChicago + Argonne National Lab. Talking too much to my dog. Being a “cool” aunt. I like knowing things. She/Her