Data Visualization with D3 by Michael Menz

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
MICHAEL: Hello, my name is Michael. And welcome to Data Visualization in D3. Let's get started. So what is the D3? D3 stands for data-driven documents, and it's essentially a JavaScript library-- a collection of JavaScript functions, that's going to make it easy to visualize and interact with data in web pages. So there are a few prominent examples of media companies that use D3. One is The New York Times. Let me pull up a quick example of that. So this is a New York Times D3 visualization of Obama's 2013 budget proposal. So you can see it is interactive. You can see how people spend different ways. They have different arrangements of the data in different sorts of charts. And it all moves pretty seamlessly, and D3 allows us to do that. The other prominent example, which I had included, but then took out because I didn't really want to look at it, was the 538 projections for the presidential election and for the Senate races. But that was also built in D3 along with a few other JavaScript libraries. So what can we expect to achieve during the next 40 minutes or so of this seminar? So we're going to build a visualization. We're going to look at shots in the NBA, and we're going to build some sort of visualization that's going to help us analyze that. But the goal of this lecture is not so much to provide a few functions in D3 or look at a few components and just give a basic knowledge of those. Rather, we want to provide some sort of literacy in D3. And by this I mean that, in D3 there is a lot of creativity. We have several different ways that we can analyze and express data to express different things. So we have to be creative, and we have to be very versatile in how we use it. And the way that versatility is built up is by looking at examples of what other people have done and being able to read that code and understand how it translates to the visual you see on the screen. After a certain amount of time doing this, you're going to be able to start thinking about the visuals you want to make and the code that you're going to have to write to make those visuals in parallel. And that's really the goal of this lecture, is to get you started on that path. , Well let's take a step back for a moment and review a little basic HTML and JavaScript. So remember that HTML sort of follows this domain object model, which is something of a tree structure. So here we have some very simple HTML and next to it we have the DOM tree. So this is just a document with the HTML tag. Within that HTML, there's a head and a body. The head contains the title, and within the title and the body, there is some text. And it's going to all be represented as a tree. And any of the JavaScript libraries that we use to interact with HTML are going to be about grabbing notes from this tree and doing something with them in some manner. And JavaScript, remember, can interact with and change these DOM elements, so change the nodes of this tree on the client side of the operation. So let's take a look at that quickly. So here is my Flask application, which I have put together just so we can look at these D3 examples. And you can see it's very simple. All it does is when we go to the site, it serves up the file we want. And this is just reinforcing the fact that JavaScript is all being done on the client side. The server really does nothing here. And here's the HTML I have. So I can actually even take out these scripts for now. We'll use them later. And so we just have a basic page. It's titled hello, world. And we have three paragraphs-- hello, world, hi, world, hey, world-- with three different IDs. We reload the page. That's what we have. So this is that page where we went to javascript.html. And we have a console, a JavaScript console. So we can type a little bit of JavaScript directly. So if we do document.getElementbyId("greeting") and I make sure to close my quotes, then you can see we get that paragraph with the ID greeting. And we can edit that paragraph so we can change the text to say hi, world. So in this manner, JavaScript allows us to edit the text. And you can imagine that if instead of selecting the greeting, we selected the whole body and rather than selecting text content, we did affected the whole HTML, we could actually add different tags to our body. We could expand our HTML in a lot of different ways. And JavaScript allows us to do that. But it's kind of slow. We have to type a lot of code. We have to go through things one by one. So just doing it in pure JavaScript to make these sorts of visualizations is not really feasible. So another thing that you guys can briefly introduce to another library is jQuery. In jQuery, you can see from its description is a JavaScript library that handles document traversal and manipulation, event handling animation, and Ajax. And it's a very broad library. It's actually much broader than D3. Often jQuery is going to be used in parallel with D3. So it's going to cover some things that it's good at, and D3 is going to cover it's much narrower focus, which is really visualizations. And I think in that area, it's going to be a lot more effective than jQuery. So let's talk about D3, and let's get into what D3 is. So the main interface in D3 for traversing documents and really for doing anything is called a selection, which is essentially a group of HTML elements, a group of those nodes from our DOM tree. And selections are created using this d3.select or d3.selectAll. So remember, in jQuery we have this dollar sign which starts all of our sort of jQuery functions, our jQuery calls. In D3, it's all started with just lowercase d3. And we can select in a very similar manner that we do in jQuery. So if we do d3.select with a tag name like body, that's going to be the same as doing dollar body in jQuery to select all of the body tags or to select the one body tag. And select all is going to select, in this case, all of the block classes. So remember in CSS, we have that dot represents a class. So the d3.selectAll("block") selects all the nodes which have the class block. And this is, again, the same syntax that we would see in jQuery. We can also select on ID using a hashtag. And this could be done the same way in jQuery. It's also the same as we do in pure HTML when we do document.getElementById. And we'll come back to this filter in a moment. But let's look at this in action. So now I'm going to add back in this script. And this script is going to include the D3 library. So you can see it's hosted on de.js.org and we're getting this JavaScript file which contains the source for D3. Now if we reload this, we can do d3.selectAll, and if we select all the paragraphs-- so all of the nodes with the tag paragraph, we're going to get this sort of object back. And it's sort of a weird look at an object, a selection, but if we look inside this group's element, you can see it has this node list, which is each of the paragraphs. So the question is how do we interact with these selections? And there's a lot of different ways. So once we make a selection, so once we do de.selectAll or d3.select, there are several functions which can be used to manipulate that selection and to manipulate the nodes within that selection. So a couple of examples of these are .attr, which stands for attribute. So that's going to be changing attributes of the HTML documents, of the HTML nodes. .style, which is going to change the CSS for those nodes. And .append, which is actually going to add HTML elements between the tags of those nodes. So let's do one example, one which I didn't actually show here, which is .text, which changes the text inside the node. So if we do d3.selectAll("p"), and then we do .text, this will change the text of the nodes. So if we changed them all to yo, world. You can see we've selected all the paragraphs, and we've changed the text inside them to yo, world. So you can see that D3 allows us to act on all the nodes at the same time, all of the nodes in our selection. We could have also selected just one of them using d3.select on the ID. So if we just did d3.select("#greeting"), then this is going to select the node with the ID greeting. And if we do .text("hello,world") here, then you can see it changes that one node back to hello, world. So why would we use select rather than select all? There's no really specific reason why. I mean it's going to be better style in some ways, because it's going to make it clear that we're selecting only one element rather than selecting many. If we had done d3.selectAll("#greeting"), of course, we're only going to get one element back, because elements have to have unique IDs. OK, so this is all well and good, right? But the question is why would we ever want to change all the attributes of a bunch of nodes to the same thing. And maybe there's a couple instances where we would do that, but usually what would be useful is if we could change nodes in different ways, but in one, sort of a short period of code. And for that we're going to have to have some reason to treat the nodes differently. And that comes back to what D3 is really for, and D3 is for data. And how do we associate the nodes we want to change with the data that we have. And that's done with this idiom basically, which is going to be d3.select.d3.selectA ll(...).data(...).enter(). So there's a bunch of functions that we string together here. And let's explain what each of those do in an example. So here I have a simple JS script, which has that idiom that we talked about. And let's just explain what each of the line does. So we first do d3.select("body"). So this is selecting that first body tag. And now we're going to select all the paragraphs inside the body. So you can see we can string together selections, where we call a select on something and that's going to select whatever we've decided to select. Here, it's the body tag. And then if we string together a select all or a select on that, it's going to call select All on all the nodes below that element in the DOM tree. So here it would select all three of these paragraphs because they're within the body tag. But suppose I comment those out. Then the selection is going to be empty. So it's a little weird that we've done that, but let's go a bit further. Next we're going to specify some data. So .data is a function which is going to take in an array. And that array should represent the data that we want to visualize. Here it's just an array of greetings-- hello, hi, yo, hey, and so on. And .enter, the next function, binds the data we've input to our selection. So every element in our array is going to be bound to one node in our selection. But wait a second, our selection's empty. There's nothing to bind to. In that case, if we just add a .append below this, it's going to try to fill out our selection so that it can bind each data point to one element of the selection. So here by doing ,append("p"), it's going to append one paragraph per element of our array. So in this case we have seven elements of our array, so it's going to append seven paragraphs. So we have one last thing which we're doing here, which is this .text. So once it's appended all of these paragraphs, right, we now have a selection of seven paragraphs and we're going to call .text on those paragraphs. Now remember, here we could have put something like .text hi world or whatnot. So we could have just typed hi world and then we would have ended up and deleted this function here. And if we did that, then we'd end up with seven paragraphs that say, hi, world. So let's look at that real quickly. So if we uncomment out this script here, so we have some script which is executed within the body. And that script is this example. And then go over and run it, we can see that we end up with seven paragraphs called hi, world. But we can actually use the data to make these distinct. So if we go back and put back in this function. So it's a nameless function, but it takes one argument d. And d is going to be the data associated with that node. So remember, each of these elements of the array are associated with one node in our selection. So it's a simple function. It takes in the data d, and it returns d plus comma world. So we're going to end up with hello, world, hi, world, yo, world, and hey, world. And let's see if we do that, and that's indeed what we end up with. So we can see how we've bound data to each of these nodes. And then using that, we've been able to treat the node differently, but still with only sort of one writing this function once. This is beginning to show the power of D3- not it's a pretty simple dataset, just a list of strings. We're going to be working with a little bit more complicated dataset today, but I think it's a fun one, which is all the shots taken by the New York Knicks in the 2013-2014 season. So let's take a quick look at what that looks like. And this is a little hard to see. But basically we have games, all the game in the 2013 season specified by game ID. The period in which they occurred, so the quarter, the score at that time, the remaining time, the team, which is always New York Knicks, the player who took the shot, whether the shot was made or missed, the x and y-coordinates of the shot, the distance it was taken from, and who, if anybody, got the assist. So we have a bunch of data here. The main data we're going to be working with today is just these four columns, which are the player who took the shot, the result, and where the shot came from. And we're going try to visualize that in some sense. So the question is how do we actually read in data like this? So in this case all the data is stored in a CSV format, and D3 provides some excellent interfaces for reading in CSV data. And that's going to be done with this function d3.csv. The first argument to d3.csv is just going to be the file name, as to be expected. And the second argument is a nameless function, which takes one argument data. And what's going to be passed to this function, what's going to be executed is the data which is contained in filename.csv. And by that I mean it's going to be an array of JavaScript objects, where each JavaScript object has the keys that are the column names. So these are going to be the keys, and values, which are the values within the row. So these are going to be the values. So let's take a look at that real quickly. So as you guys can see, I'm not quite as confident in my ability to type code live as David. So I've typed a lot of this code beforehand. And we'll go through and comment it out line by line. But for the start, all we really have here is we read in the shots.csv file. And we're going to log what the data looks like. And we should also look at what the actual HTML looks like here. So at shots.html, we can ignore this SVG for now. That's not going to be important yet. And we can ignore this selector for now. But we're just running the scripts shots.js. So if we go to shots.html, take a look at that. Here's what our data looks like. And as you can see, it's what we said. It's an array where each element of the array is a JavaScript object, which are those keys are the column names and the values are the values within the rows. OK. So the question is, how are we actually going to visualize this? And there are maybe some limitations with just using pure HTML elements. Like we're probably not just going to want to put a bunch of paragraphs saying, Carmelo Anthony made this shot here, or a div that has maybe, we fill in blue, you know, if someone made a shot. Green, if someone made a shot, red if someone didn't. We want to have a little bit more freedom to draw things than that. And that's going to be allowed by this-- I really shouldn't say beyond the DOM because it still is the DOM, but it's beyond the basic HTML elements. We're going to be dealing with this image format called SVG. And SVG stands for scalable vector graphics. And in SVGs, we're going to be able to draw lines, shapes, and text. So what do I mean by SVG follows the DOM? So let's take a look here. We have this basic HTML file called svg.html. And you can see it looks, it is HTML. We open up an SVG with the attributes width 600 and height 200. Within the SVG I have three tags, each called circle, each a circle tag. And I've specified the center-- x the center, y, and the radius. So that's going to be the x and y-coordinates of the center of the circle and the radius of the circle. And for the last one also specified that it should be a fill of blue. So it's going to be colored blue. So if I go to svg.html, you can see I get this image here, which is these three circles that I've specified. So we can see that SVGs follow the same DOM tree that we work with HTML. So we're going to be able to interact with them using D3 in pretty much the same way we interact with HTML. And that's going to allow us to create a lot of these drawings. And this is the manner in which The New York Times created a drawing like this, by appending circles to an SVG, and doing a lot of other stuff, but that's the starting point. So a couple important tips for using SVGs in these visualizations. So it's going to be tempting at first to just append a bunch of circles and specify their center x and center y since that's what we've just seen. But this can be a little bit annoying down the road. So take for example, if we wanted to draw a smiley face, for instance, on an SVG. Then we might have one circle for the head, two circles for the eyes, and an arc for the mouth. And no matter where we put the smiley face on the SVG, the relative positions of all of those elements are going to each other are going to be the same. However, if we want to move that smiley face around, then we need to change the absolute location of each of those elements independently, right? So they each need to specify-- if we move it 500 down, 500 left, then we need to move each element 500 down, 500 to the left. And this can get a little bit annoying if for each one we're specifying a center. So to deal with that, we can use this g tag, and g stands for group. And the idea is we can specify a g tag and put all the elements that we want to group together inside of these two tags. The g tag has this attribute transform. And transform is going to be some transformation which we apply to all the elements of the group. So this first one we have a translation, 100 down and 50 to the left. So if we have the smiley face within this group, then it would move all of the elements 100 down and 50 the left. And this is clearly a lot easier than moving them individually. We can apply other sorts of transformations. So in the second one, you have a rotation by 20 degrees and then a translation 100 to the right. One thing to keep in mind, 100 to the right. One thing to keep in mind here is that the transformations are going to occur right to left. So the rotation here is applied before the translation. You can imagine using a rotation if you wanted some sort of circular layout of your data. So if you wanted to draw a bunch of circles or rectangles or text in a circle around some center, then you might use the rotation transform for a group. So let's see this in action. And let's get started putting together the shots visualization. So back in shots.html, let's go back to the SVG which we have here. So I have an SVG with the ID canvas, a height of 600 pixels and a width of 1,200 pixels. And over in shots.js, we've read in our data. So let's start putting a little bit of-- let's start doing some work with this data. So first I'm going to select the SVG. And let's ignore that I've set it equal to shots for now. We can even delete that for now and just select the SVG and start working with that. And then I'm going to use the same idiom which we had before, where we select all the groups. And we're going to bind the data, so each of these shots to one group. So remember it's going to append one group per shot in our dataset, per row in our dataset. I'm going to give each of these groups a class. This is a very good practice in D3 when we append these general objects, with each general objects like groups or circles. You're just going to use groups and possibly a lot of contexts. And you're going to be able to want to select all the groups in a certain context. And the way the best way to do that is to say, well, if we want to say, draw all the shots and we want to draw all the rebounds, then we might have one, which is this class shot and one is the class rebound. And then we can just select all the ones with class shot rather than having to select all the groups and then do some filtering in order to get only the shots. So this makes it a little bit easier in the long run. And then we're going to have our transform. So here I've done a little work already. But sort of the first thing that makes sense is to do just the x and y-coordinates. So we're going to translate it the x-coordinates to the left and the y-coordinates down. So we have some group here. Now what you can see here is that at the end of this we have a selection, which is all the groups, one group per data point. So if I go back and I put in what I had before, where I say shots equals the selection, what I now have is shots is a selection of all the groups, it's going to be selection where each node in the selection represents one shot. So this makes a lot of sense now. And to each group I'm going to append a circle of radius 5. So for each shot, we're going to have one circle. And let's take a look at what we end up with. OK, so now that I've reloaded the page, it's a little bit cramped right. So it turns out that our x and y-coordinates are perhaps not perfectly spaced for a visualization like this. So let's expand those out a little bit. So let's multiply the x-coordinate by 10 and the y-coordinate by 10. And we can see that now it spaces it out a bit nicer. Still though, we can't see the lower half of the court because our SVG is not big enough. And typically, when we're looking at basketball courts, we want them to turned to the side here. So we can do that as well by flipping the y and x-coordinates. And now when we run it, it's going to look about how we expect. And yeah, it looks pretty much like what we might expect from a shot chart, where we have some clustering around the three point line and a lot of shots near the basket. OK, so let's start doing some work with this data in a more interesting way. So what data do we have? We have whether the shot was made or missed. So how about we make the two circles green if it was a make and red if it was a miss. So remember we have this attribute fill for the circles. So we can edit that attribute. And we're going to have a function here, which is again going to be a nameless function that's going to take that data bound to that node as the input. And it's going to output the value we want for fill. So if we uncomment each of these lines, we have this function. And it says, if d.result equals made. So remember, the node, the data represents is a JavaScript object, which has the keys, which are the rows, which are the column names in our CSV file. So here we have a column name called result, which is either made or missed. So if we do it with d.result, it equals made, then we're going to turn green. And otherwise, we're going to turn red. So we're going to have a green circle if it's a make, and a red circle if it's a miss. If we look at this again, then that's what we end up with. And we can begin to see some more things so we can see that out in this area, people are making a lot of shots. So these sort of end of the half, half court shots are not very effective, especially since this is the Knicks and not the Warriors. So we've began to look at our data and really be able to pull maybe not the most interesting thing out, but beginning to pull something out from this data. The question is, how can we add more and can we make this visualization interactive? So the main interface for adding visualizations is this .on function, which again is called on selections. And the first argument to .on is going to be a string representing an event. And this string can be click. It could be move if you move the mouse over the selection. It can be key down if you press a key. We're going to use mouse over and mouse out. So mouse over is going to be an event that triggers when you move the mouse over a node in selection. And mouse out is going to be an event that triggers when you move the mouse away from the selection. The second argument for on is the function that's called when that event is triggered. And again, the function is going to take a single argument. And that argument is going to be the data associated with the node which triggered the event. So let's look at that. So if we do .on mouseover, we are going to have a few lines here, which we can explain. So we have first this idiom de.selectthis. So d3.selectthis-- this represents the actual node. So remember the argument here is not the node itself, but the data associated with the node. But often, when an event's triggered on the node, we want to actually change just that node. And the way to get just that node, is to call this de.selectthis. And it's going to return a selection which contains just that node which triggered the event. I'm going to call the dot raise, to raise that note above the other ones. And let's take that off for now and see what happens if we don't do that. But that's going to essentially move that HTML element to the end of the SVG so it's placed above everything else. But let's see what happens if we don't have that first. To that node, we're going to append some text. We're going to give it a class called player name. And again, good practice whenever we append something to give it some sort of class. We probably should have given these circles a class if we want to draw other circles. We're actually going to not draw the circles, so I'm not going to bother with it now. But it is a good practice to have that class attribute. And we're going to add this text to this text SVG tag, which is going to be the player name, so d.player, so we're using that argument. So now, if we run this, and we move our mouse over some nodes, we can see that we indeed end up with the player's name. And we have a little bit of a problem, because when we move the mouse off the node, it doesn't delete the player's name. So now let's go back, and we add this mouseout function. So here we have on mouseout we're going to trigger another function. This function is just going to select all the text which has the class player name, and it's going to remove that. So here we wouldn't even need text. We can just do All everything with the class player name. And we could actually even do everything with just the tag text. However, probably the best practice is be as specific as possible, because we may want to add in later other sorts of text onto our visualization that we don't want to delete every time we move off a node. So now that we've added this, let's go back and reload our visualization, and see what happens as we move around. And now, we can indeed see that once we move off a node, the text goes away. Maybe we can make our nodes a little larger if we want it to be a little easier get over them. One of the things that I love about this dataset is that we can see J.R. Smith likes to take a lot of shots from way out. That's an interesting point. But one thing we can see is that once we get into here, the text is going to be added behind a bunch of other nodes. And the reason this is occurring is because we're adding it to the group, which has already been placed. So if that group was placed before another group, even when we add the text, it's going to be behind all the circles in the group's place after it. That's why we had this .raise here, so this selection is going to be that one group. And .raise is going to raise that group, so it's the last group in the SVG, so it's going to be on top. And now if we look at it again with that .raise, we can see that now the names come up above all of the other circles. So often we're not going to have data in necessarily the best form for the visualizations we want to make. In this case, we have rows of data. And we basically want one row for shot. So this works out pretty well. But often we are going to want to restructure data in some manner. And there are a bunch of functions that D3 provides in order to do that. We're going to work with d3.nest a little bit to do some stuff with the shots data. But I'm going to talk a little bit about d3.stratify and d3.hierarchy first, which deal with hierarchical data. So the classic example for hierarchical data is a family tree. So suppose we have some data, which is again represented as a table in some sort of CSV or whatnot, where we have the name of a person and then the name of their parent. So this could clearly be represented with a tree structure. And a lot of D3 visualizations are going to be trees or something that represents sort of a tree structure or a hierarchy. So we can use stratify in order to convert this sort of CSV format into something which is easier to work with when making trees. Where we actually want to end up with something like this, where we have the JavaScript object with three keys-- the ID, so the person's name, the parent ID, so who their parent is, and their children, which is a list of all of the nodes which have the parent of Eve. And this is going to be sort of recursive, right? So each of these children is going to have the same format. So it'll have their ID, their parent ID, and then their children, which is again going to be another array of a similar format. So if we write something like strat equals de.stratify, so creating some stratifier. In ID and parent ID, we're going to specify a function which is going to act on the data in that row. And it's going to return the ID we want to use and the parent ID we want to use. So here the ID is going to be the name of the person. And here the parent ID is going to be the parent. So you can see that d3.stratify was sort of designed with family trees in mind. And then if we call strat on whatever our data is, the data we write in maybe with d3.csv, then we'll end up with a JavaScript object that looks something like this. And there's going to be a lot of visualizations in D3 that are built with formats something like this. So I just wanted to touch on that briefly. But now let's return to what we're going to actually work with, with just this d3.nest. And this is used to group together data. And in our case, we're going to group together data by player. So we're going to take all the shots taken by certain players. D3.nest has three methods which we're going to use. The first is .entries, and the argument to entries is just going to be the data we want to group. So in this case, we're going to do d3.nest, entries(data). The second method we're going to use is this key. So key is going to specify what we want to group on. So here we're going to have a function. The function is going to take in a row of our data. And it's going to return what the key should be for that route. So in this case, it's going to turn the player name. So let's take a look at that. So if we do players d3.nest, the key is going to be a player. We're going to come back to rollup, and the entry is just going to be our data. And let's log what that looks like once we do this grouping. So we reload. We can see that we have an array with 17 objects where the keys are the players' names, and the values are each of the shots taken by that player. So if we open up one of these, we can see that this is a shot indeed taken by Carmelo Anthony assisted by Tyson Chandler. OK. So we now have this object, which has the shots grouped by player. The last method, which we're going to use from d3.nest is this .rollup. So .rollup allows us, once we've done this grouping, to do some aggregation on the rows that have been grouped together. So rollup takes a function, which rather than acting on the rows individually, is going to act on the whole array of rows. So in our case, we're going to do the simplest thing possible, which is we're just going to return the length of that array. So the length of the array representing the number of shots taken by the player. So here we do .rollup. Here I do V, maybe V stands for vector or whatnot. We can change it to A to stand for array. So it's just going to be this function A, which takes in the array of shots for that player and returns the length of that array. So now if we run this again. And log what we get, we can indeed see that we get this object where we have each object has two keys-- key-- Carmelo Anthony, value-- number of shots taken by Carmela Anthony, 1,643. So nest has allowed us to sort of pull some other things out from our data and group it in some manner that we can then use. So let's use this a little bit. So we haven't actually added it toward visualization. We've done some sort of computations here. But let's actually add it to our visualization and do something with it. So back in the shots.html, you saw that I had this selector with the ID selector. And we're going to want to be able to just look at the shots taken by a specific player. So now we can go back and start thinking about using D3 with the HTML rather than in the SVG context. So I'm just going to select the selector. I'm going to select-- I'm going to use this idiom again. .data, .selectAll, .data, .enter, .append. So I'm going to add one option for each element of this player's array that I've just created. So one option per player where the text of that option is going to be the key, so the player name and a colon and then the number of shots taken by the player. And the value-- so this attribute value is just going to be the key of that player. So if I do that, and I look at what I end up with, you can see now I have a selector where I have the player names and the shots taken. And I can go through and click on that selector. And you can see the selector isn't so pretty, but you can imagine we could also combine this with Bootstrap, and we could have a very nice looking selector. So we can start to use a lot of these different CSS and JS libraries together to make a more beautiful application. So the selector doesn't do anything right now, but we can combine some of the things we've learned in terms of interaction and selections in order to make it only show the shots for that player. So we're going to, rather than using on click here, we're going to use on change. So that when they-- rather than just when they click on the same thing, we don't want it to change anything, so only when they change the value selector. We're going to select all-- well, let's leave that for now. We're going to get the value of the selector. So what's interesting about these .attribute and here we're using .property, and .style, is that they can be used as accessors as well as setters, so getters as well as setters. So if we don't provide this second argument here to set it, then it's going to return the current value. So here we're just getting the current value of the selector. So whatever we set here is the value. And once we get the value, we're going to select all the shots. We're going to apply this filter function which is going to restrict our selection. So .filter, which I mentioned way back in terms of selections, and said I would come back to, well, this is the time. So once I've created a selection I may not want all of the nodes in that selection. And I may want to be able to pick out the nodes in a more specific sense than just class, ID, and tag. And I can do that by using this .filter function. So the argument to filter is just going to be a function, which takes in the data bound to that node, and if it returns true, then we keep the node in selection, And if returns false, we don't keep the node. So here my function takes the data, and it returns d.player not equal to value. So it returns true if the player for that row is not equal to the player I've selected. So it's going to select all the shots not taken by the player. And it's going to set their opacity to 0.1. And so it's going to make them transparent. Then let's see that in action. So now if I reload and click, you can see that it only shows me the shots for Beno Udrih. Problem is, if I select another player, then they're all going to be transparent. Because I'm only making more nodes transparent, I'm never resetting them. So in order to change that, I go back to the start of my function. I select all the shots. And I change their opacity to 1 before I go and change the opacity of the shots not taken by that player. So if I do that, and reload, and now I select Raymond Felton. And see he's spread it out, spreads out his shots pretty well. If I go and look at Tyson Chandler, a little bit tighter to the hoop. Metta World Peace, maybe not taking that many shots. Amare Stoudemire, another guy who plays tight to the hoop, and of course, Carmelo Anthony, all over the floor. So again, we can begin to pull more things out of our data. Now the one thing which I don't like about this is it starts out with Carmelo Anthony, right? But it's not just Carmelo Anthony's shots here. Like nothing gets faded until we change the selector. So to remedy that-- I'm just going to add-- remember players is just an array-- so I can just add one JavaScript object at the start of players, one associative array at the start of players. I'm going to have my key be all, and I'm going to have my value be this d3.sum. And we're not going to go into too much detail in d3.sum. That's something that can be looked at, and it's not too hard to understand given the rest of this lecture. But it's just going to sum up the values of the elements and players. So it's going to be the total number of shots taken. And I'm only going to fade shots if the value is not equal to all. So now we have this selector, where we can select through different players. And if we go back to all, then all the shots are shown. So now this works exactly as we would want it to. And we have all the lines of code uncommented, so we're done with what I had planned. So we've created this visualization. And of course, there are a lot of ways that I'm sure you are beginning to think about, how we can iterate on this, how we can improve on this, even based on just the few functions that we've seen. We can think about looking at how assists play into this. We can look at maybe coloring the notes differently based on shot distance or shot difficulty and whether they made or missed. And those are some great things to think about going forward. However, as I said, really the way to work with D3 is to look at other examples to begin to formulate your own ideas about what visualizations you want to create and what different kinds of code, how D3 is being used in versatile ways to create those visualizations. So I'm providing a couple of resources here that you can look at. So we have d3js.org, which are going to have a wide gallery of sort of complete D3 applications as well as the code for them and a ton of great documentation. There's also this site Blocks by this guy Mike Bostock, which has a lot of simpler examples which sort of illustrate single aspects of D3. So here he has this circle dragging example, which just demonstrates basically a good way to implement circles that you can drag around. So this is a pretty simple example. It's not really a full visualization. But if you're looking for a more specific thing you want to implement in D3, then this blocks is a good place to look if someone has already done it. And the last thing I'm linking is a library with 538 put together called D3-pre. As you saw, at some points our application was a little laggy in terms of loading. It took a little while for it to render. D3-pre allows us to pre-render a lot of our visualizations. So if we want to have a lot of stuff going on in a visualization, we can use this D3-pre so it renders more quickly when we want to actually show it to users. So that should complete what I wanted to talk about D3. I hope that you guys are inspired to look at some examples and go forward, and feel that you were literate with the language. Thank you.
Info
Channel: CS50
Views: 34,134
Rating: undefined out of 5
Keywords: cs50, harvard, computer, science, david, j., malan
Id: 219xXJRh4Lw
Channel Id: undefined
Length: 45min 17sec (2717 seconds)
Published: Thu Nov 10 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.