Go to Github Classroom and grab the starter code for the lab.
Once you have the repository downloaded, you will find that I have given you a start, and got you through the data download stage. This downloads the Iris data set, which is a very famous dataset for doing statistical analysis. We are just interested in it because it is fairly small and simple.
You are going to start by getting a jump on part of your homework. We are going to start by making a scatterplot that plots petal length (petal_length) on the x axis to sepal length (sepal_length) on the y axis.
Start by making two linear scales for these two variables (remember to flip the y axis range).
Then add the data items to your chart in the usual way. The difference being that this time we will create circles instead of rects. Circles in SVG have different attributes than rectangles. We have cx and cy, which are the center of the circle, and r, which is the radius. Give your new circles these three attributes. Map cx and cy to petal length and sepal length (remembering to use your scales). Just set r to 5.
Finally, create the axes in the way I showed you in class. Don't worry about the axis labels right now.
Once you are done, you should have a basic scatterplot.
Interaction on web pages is event based. There are a large number of different events that can occur, some through direct user interaction, others not. To respond to these events in JavaScript, we will register event handlers -- functions to be executed when the event occurs. Right now, we are just going to focus on two of them: mouseover (when the user hovers over an item), and mouseout (when the user moves the mouse off of an item).
Another function that we can call on D3 selections is the on() function, which allows us to register for events. The first argument is the name of the event, and the second is the function to call when the event happens. We will use this to highlight the circles as we hover over them.
First, we need to figure out how to "highlight" circles. We could just change their color, but we will be slightly more clever. We are going to use HTML classes. When a circle should be highlighted, we will give it the class highlighted. When a circle should no longer be highlighted, we can just remove the class. Then, we can use CSS to create a style for our highlighted circles.
Step one Create a highlighted style. You will see that I left an empty style tag in the head of the page. We are going to create a style that will color the circles red when they are highlighted. Add this CSS into the tag:
.highlighted{
fill: red;
}
Step two Create a variable to hold a reference to our circles selection. Go to the original chart.selectAll("circles") and add a constant declaration (i.e., const) to the start to store the selection. Call the selection circles.
Step three Make a mouseover handler. After the code that creates the circles, call circles.on(). The first argument should be the string "mouseover", and the second argument should be a function. Do not use our fat arrow shorthand (if you do, we won't have access to this, which will be important in a minute). Use function(d){}. Add a console.log() and print out d. Test this code.
Step four Change the class of the circle. In order to change the class of the circle currently under the mouse, we need a new selection that only includes this one circle. We can get this with d3.select(this). (If you are serious about learning JavaScript, sometime after lab you should read more about this). Once you have the selection, call the classed() function on it. The classed() function takes two arguments, a class name and a Boolean value. Pass in highlighted and true.
Test your code. The circles should light up as you mouse over them. Eventually they will all go red.
Step five Make the circles un-highlight when the mouse leaves. Repeat steps three and four for the mouseout event, this time setting the highlighted class to false.
You should now have circles that turn red as you mouse over them and turn black again when the mouse moves off of them.
Next, we would like to display information about each data point as we mouse over. We are going to create a block of HTML which we can update dynamically as the user explores.
Step one Add the information template to the web page. Right after the svg tag and before the script, add this block of HTML:
<div>
<p>Class: <span id="class"></span></p>
<p>
Petal length: <span id="petal_length"></span><br />
Petal width: <span id="petal_width"></span><br />
Sepal length: <span id="sepal_length"></span><br />
Sepal width: <span id="sepal_width"></span><br />
</p>
</div>
Note that the template has a collection of spans with ids. We will be using selections to change their contents on the fly.
Step two Update our template when the user mouses over an item. Obviously, we will return to the on("mouseover",..) event handler we created earlier. Recall that the d variable is a reference to the current item's data. We can use this to update the template. For example, to update the class, we would write d3.select("#class").text(d.class). Follow this pattern to fill in the rest of the template.
Once you are done, test the code. We won't worry about clearing the template back out again.
It is very useful to be able to change HTML on the fly as we interact with the visualization (this is certainly one reason to move to D3 from Altair). However, sometimes we would just like a simple tooltip. As it turns out, we can make some small adjustments to our information display to turn it into a tooltip.
Step one Restyle the template. Give the div that surrounds our information display the id "tooltip". Then add this block of CSS to the style tag.
#tooltip{
position:absolute;
width:150px;
height:auto;
padding:10px;
background-color: white;
border-radius:10px;
box-shadow: 4px 4px 10px rgba(0,0,0,0.4);
pointer-events: none;
}
#tooltip p{
margin:0;
font-family: sans-serif;
font-size:12px;
}
Step two Figure out where the mouse is. We will grab the mouse coordinates with const coordinates = [d3.event.pageX, d3.event.pageY];. Do this in the mouseover event handler.
Step three Move the tooltip. To move a div, we will change the left and top styles (not attributes). Select the tooltip and then add two styles, one for left and one for top. Use the coordinates to determine the position value. Note that we need to be passing a string that looks something like "150px", including the "px" designation. So, for example, for my left, I used (coordinates[0]+25) + "px". The tooltip should now pop around the screen as you mouse over circles.
Step four Hide the tooltip. We would rather the tooltip stayed hidden when we aren't on top of a circle. To do this, we will play the class game again. Add this style to the style tag:
#tooltip.hidden{
display:none;
}
This style says "if the item with id 'tooltip' belongs to the class 'hidden', don't show it". We would like the tooltip to be hidden initially, so add class="hidden" to the tooltip div. To have the tooltip show on demand, we will do the same thing we did for the circle highlighting. On mouseover, use classed to set the "hidden" class to false. On mouseout, use classed to set the "hidden" class to true.
Step five If you haven't already, test, test, test.
When everything is working, commit your changes and push them back to Git.