Interactive Data Visualization: Getting Started with D3.js - V5 | Bill Shander | Skillshare

Interactive Data Visualization: Getting Started with D3.js - V5

Bill Shander

Play Speed
  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x
9 Lessons (1h 54m)
    • 1. Introduction: D3.js in a Nutshell

      6:32
    • 2. Adding SVG Elements in D3

      10:22
    • 3. Getting Started Working with Data in D3

      17:54
    • 4. Making Data-Driven Graphics in D3

      9:53
    • 5. Using D3 Scales

      19:19
    • 6. Using D3 Axes

      18:59
    • 7. Animation in D3

      9:50
    • 8. Interactivity in D3

      12:29
    • 9. D3 - One More Thing

      8:46

About This Class

D3.js has become the standard for creating custom interactive data visualizations for the web. This feature-rich open source javascript library allows you to create dynamic and extremely diverse experiences that can interact with users and any other element on a web page.

For programmers familiar with Javascript, it is not hard to pick up and run with D3 very quickly. For those with limited javascript experience, it can be intimidating. This course will help anyone who has some javascript familiarity get comfortable creating rich, animated, interactive experiences with D3. If you have worked with jQuery, for instance, you can easily work with D3. 

Your instructor, Bill Shander, is a self-taught programmer with over 25 years experience doing data visualization. He remembers how confusing and intimidating it can be to learn a new technical skill. This course uses simple language, not technical lingo, and walks through everything step by step, explaining every minute detail. Even if you don't know any javascript, you should be able to follow along with the lessons, even if it might be a little confusing at times. 

All of the code used in the videos are available for download under "Class Project" to help you follow along. Please note that you will need to be running a web server for most of this course as D3 cannot load data files via local paths. I recommend using a Bitnami MAMP stack or a similar local dev server - whatever is easiest for you to setup. 

This course has been updated to work with D3 V 5.

Transcripts

1. Introduction: D3.js in a Nutshell : Welcome to D three dot Js key concepts. This course is a very solid introduction to what's become one of the most popular technologies for making interactive data visualizations for the Web. My name is Bill Sander. I've been doing information, design and data visualization for over 20 years, working on static, infographics and interactive experiences. I do design, and I'm a self taught programmer. I have vivid memories of the pains you go through learning technologies with little or no documentation or tutorials and a technical gurus rather than regular humans. And I love producing no nonsense and clear instruction that anyone can wrap their head around. D three is a JavaScript library that's surprisingly easy to use for those who have worked in JavaScript before, especially libraries like Jake Weary because it follows a lot of the norms and best practices you've seen before. D three, Also like Jake Weary allows you to manipulate and interact with any element on a Web page you could alter and read from HTML CSS and interact with other JavaScript. So anything you create is a fully compliant element of the entire experience in the browser . If you don't know any HTML CSS and JavaScript at all. You'll want to taken inter class on those technologies before you work too much with the three. However, I tend to use very simple language and try to explain things clearly, as though my audience isn't super technical. So even a somewhat technophobic person will be able to fall along with this course, even if some of the details are a bit fuzzy. Since everything in D three happens in a browser, that means we need to start by creating a basic Web page. So here I am in Sublime Text, which is a great text editor for coding because it recognizes your code and does things like cull arise it, helping you find bugs in problems and sublime text will even finish your code snippets for you as you type things. It will make suggestions about choices you can make that makes sense and allow you to do things like just type HTML. Hit the tab key, and it will set up your whole basic Web page for you, a huge time saver compared to working in no pad or texted it, for instance. So now that I have an HTML framework, I can just put in the title for this document. I'm also going to add an empty div with the I D chart, which is where all the good D three stuff is going to happen later. Next, I'm going to add some CSS to the page so I could just type, style and hit Tab, and it'll automatically add a style tag for my CSS. So first I'm going to add a background color to the body the entire Web page essentially and also set the with 2 100%. So this way it'll just stretch the entire width of the page. So if I save this, go back to my browser and refresh this page, we see that the background color of that, like gray, extends the entire with of the document. And it also is using up the height. Would just, you know, the body will sort of default 200% height. We don't need to worry about that right now. In addition, what I'm gonna do is I'm gonna open up another style element here, another CSS entry for my chart. And of course, hashtag chart means that it's going apply only to the element with the idea of chart this thing down here and I'm gonna set again the background color. In this case, I'm actually gonna match it to the body background, which I'll explain in a second. I'm gonna set a specific with just so it's a set within a set height and you'll see what that does. And I'm also going to set a, um, top and bottom margin of 50 pixels just to sort of pull it off the top edge of the browser . Animals said an automatic horizontal margin so that it's automatically centers itself. And I'm also going to give it a border. Just a solid groups. One picks black border. So again, if I go back, reload my page. You know, I just pulled it away from the edge with that 50 picks top margin, and then the auto margin puts it in the center, and I have the same background color but a little border so I can see where it actually lives. And I use that background color because later on, I can tell when I change it, which you'll see in the next video. I'll be able to see the difference to make sure the changes that makes you making her actually happening. Okay, it's time to move on to doing something on this page that actually has to do with D three. I have found the best way to learn is by working on a specific task rather than learning in theory about what code does what. So we'll be building an animated, interactive scatter plot using D three. This course is not going to attempt to cover every detail and nuance about D three, but we'll focus on several of the most important key concepts that, once you understand them, will empower you to do all kinds of really interesting things. And from there it will be easier to learn deeper level concepts in the library. It's worth noting that D three can create its objects either as SPG elements, which are vector graphics, auras, canvas elements which are part of the HTML five standard. They're pros and cons to both that I won't get into here. This course will be working on Lee an SPG. But if you prefer canvas html five, it won't be difficult at all to convert what you learn here to use that standard instead, lastly, before we can actually work with D three. We have to actually add d three, the library to the page. So I'm gonna add a script tag, and I just have to define the source. And that source is a JavaScript file in this case that lives right in the folder was going to show you here right in the folder next to my index dot html file. So I don't have to give it a path. But you could, of course, reference the library on a Cdn repository that lives out in the cloud somewhere. But I had just using a local file. Next, we'll start adding SPG elements to the page to see how the most basic D three methods work . By the way, all of the code for this course will be available via link in the course description so you can download and follow along lesson by lesson. But if you can, I would recommend you write the code yourself along the way. There's no better way to learn than by doing it yourself 2. Adding SVG Elements in D3 : So now it's time to take the file that we just sort of set up the basic framework for and start adding things to the page, Start adding the SPG elements that are gonna become are really sexy and cool Interactive graphic chart. So first thing I need to do is I'm gonna add a script tag below my div here. And the reason I put it there is that, you know, the way HTML loads is that it loads from top to bottom. So that reads it from up here all the way down to here. And I don't want tohave my JavaScript try to do anything with this div putting stuff in it until it actually exists. So that's why I put stuff below that there are ways to do it. Where you put it up here doesn't matter. It's not really detail we need to worry about today, but it's easiest just to put it down below the day that you want things to happen in. So, in this script tag, the very first thing I'm gonna do is I'm gonna create a variable called Xvg, and this variable is going to contain a D three element And so let me just create that. I'm gonna say d three dot select and I'm gonna say Select that chart, Dave that we created. And then with that, I want you to upend an SV G. And I want to give it an attribute of oops A with attributes of 1000 pixels. Copy and paste change at the height and change that to 500 pixels. And at my little semi colon. So what's happening here? I'm literally just creating a variable that essentially then will contain a d three spg of a certain width and height. That is then essentially gonna be appended to the chart. And so what I'm gonna do now is I'm just gonna save this. I'm gonna go back to my browser. I'm gonna hit, refresh, and you're not gonna see anything, because essentially, hopefully there's a SPG element in here, But we haven't given any attributes other than width and height, so I can't tell if it's there. But what I can do is open up my web inspector. So that's command option. I on the Mac and I can go look at the elements. If you're not familiar with this sort of process and how this works definitely look into it . It's a great way to debug the code. But center I can see every HTML element as it's been generated on the page so I can click into my chart, which I see has an arrow next to it, which is a good sign. There must be something inside of there. Otherwise, there wouldn't be this little hero. I click it open and sure enough, I haven't spg element. It has a width of 1000 picks and a height of 1000 pixels, which is why it is eggs feeling the full area of that same background border that I created earlier. So as you roll over, you can see it's sort of highlight in blue. So it did it. I just can't exactly see it now, So let's fix that. So what I'm gonna do is, um I'm gonna go in and I'm gonna add style to my CSS here. I'm just going to say for any SPG elements just by using the SPG tag there, I want you to set the background color. And here is where I'm gonna just said it to wait. Okay, so this is what I was talking about earlier when I created the background of this gray. And then I made my day of exactly the same gray. So it sort of blended together. That was sort of useless, except that now, when I refresh, my white will actually show up. So now I know that it exists without even having a look down here in the Inspector makes sense. The other thing I'm gonna do is I'm gonna actually add a couple of other variables. I'm gonna add a variable above everything here, and the 1st 1 is gonna be called with. I'm gonna set that to 1000 ham and create one called height that I'm gonna set to 500. And for those of you who have done some programming, you can probably predict what I'm gonna do next. I'm actually gonna set these attributes to use those variables, And so essentially, I'm starting to abstract away. Um, you know things that if I wanted to change the width and height later, I could just change him up here, and it will automatically change it here. And of course, you'll see. Probably down the road, I'll be using those variables in other ways, Which is why it's helpful to do that. Okay, so next what I want to do, I want to actually add something to my SPG. Um and I want to sort of just show you how SPG works a little bit. First I'm gonna do is I'm gonna take my SPG. So now that variable sort of is it? Like I said, a container that sort of has an entire SPG element in it so I could do something similar to what I did before, where I'm gonna penned something to it. So I'm gonna take my SPG, and I just want to upend a rectangle. And the shorthand for that in SPG language, it's sort of its own language. Let's call it. I usually just the four letters wrecked. Okay, so I'm gonna panda rectangle. I'm also going to give it a few attributes. And so I would say first, I want to set the X attributes where it's gonna be located on the page horizontally and I must say, Put it at 100 copy paste. I must set the why at 100 to I'm gonna add a with attributes. And let's give it a 10 and will make the height also 10. So what I've done here is I've added a rectangle to my SPG If I say this and I go and refresh Boom, I haven't svg rectangle that is 100 pics is over in the X direction and 100 pixels down in the Y direction Couple important points here d three spg the height The why is a little bit confusing and counterintuitive. This is 00 up here in the upper left hand corner. So any time you add a height, you're actually going down sometimes gets a little confusing when you're placing things on the screen. But just try to remember that snow. If I go into my inspector and I go into my SPG element now, it has an error next to it. I can open that one up and I can see I have a rectangle located an ex of 100. Why have 100 with of 10 pixels and I'd of 10 pixels. You notice you don't have to have the PX in here. It just automatically figures it out. So SPG allows you to create thes geometric objects like rectangles or I can do a circle and my circle, I might add, and attributes, which is called C X. And I'll explain that in a second I'm gonna push this one a little bit over to the right. So it's have 100. I'm gonna say 200. I'm going to give it a C. Why? And we might as well keep it at the same. Why position as the other one and is another attribute for circles, which is our which, if you're at all familiar with geometry, you might be able to guess is the radius of the circle. So what I've done here, As I have said, the C X, which is essentially a rectangle, is position based on the upper left hand corner of that rectangle. So this upper left hand corner is exactly 100 pixels over and 100 pixels down. Where is now? If I refresh, See Ex is saying. Put the center of the circle exactly in this case, 200 pixels over and 100 pixels down, so circles are located based on their centers. Rectangles and some other objects are located based on their upper left hand corners that also could get a little confusing and funky just so you know. So just you know, you have to remember that. And then I said a radius of five for this circle. And so this is a diameter of exactly 10. So it's the same with is this radius of five diameter 10. This is a width of 10 etcetera. You can probably get the just here. So basic idea again. SPG assembled at geometric objects. You add a bunch of attributes such as its location. It's width, its height, its radius on it does what you might expect. I'm gonna do one more here you can also a pen, things like lines. OK, and here are the attributes changed yet again. So instead of X or C X, what we have is X one. So the x of the first object and I say, why one and let's put that also on 100 down and I'm gonna do an x two and why two? And so the x two I'm gonna put it 400 the Y two at 200. And so for the line, you also have to add another attributes, which is the stroke color. Some of skin and given black stroke. Put in my semi colon refresh and you'll see a line. So again, what am I looking at here? What were all those things? X one, The first X value A line starts here and ends here. So it has essentially two positions and so the second position is X two. And why to so x two is pushed All of the over here. Why? To push down here. So it creates a line from here to here and it automatically figures out the SPG, you know, had a sort of put the angle in there. Just sort of connect those two things. Basic idea. I can set the stroke color. I could change the stroke with if I wanted to all kinds of things. So, you know, SPG has all kinds of things beyond rectangles, circles and lines. You can add symbols you can add, you know, essentially geometric like polygons that have all kinds of weird shapes. But the basic idea is always the same. You add the object using SVG language. You add the attributes that are required for you to be able to see it and to place it somewhere on the screen, and that's it. So, like, as we're creating our interactive chart a little bit later on, we'll just be doing this. Will be adding objects in a certain location and colorizing them etcetera, based on various attributes. Hopefully, this makes sense. Should be pretty straightforward. So next we're gonna move on to really actually working with some data. 3. Getting Started Working with Data in D3: so that's great. You know, we can create shapes and lines and all kinds of things in SPG in the browser using D three . But D three is really all about working with data. So why don't we start doing that? Let's load some data and see what we can do with it. So I'm a start just by deleting the stuff that we just did earlier where we added the rectangle in the circle in the line. I don't need that stuff anymore. And I'm just gonna create a new line. And what I'm gonna do, first of all, is I'm gonna be using something built into D three called d three that CS v. And when you do a d three dot CSP is that will load, as you would guess, a C S v file. And I'm working with a file called Boston Housing dot CS fee, which is available in the folder with stuff you downloaded for the course here. And let's before we start. Let's take a look at that. See, SV file and I can explain what's going on in there. So a CS fee file is a comma delimited file, meaning that you have fields and data that are just separated by commas. So, as you can see here, I'm looking at it sort of natively in the text editor. Here I have field names which are always in the first row in a CSP file separated by commas . So I have a field called Crime one called Charles etcetera, all separated by commas and then each row of data down below. It is one data value for the field associate in the same position, separated by comma from the next one and then from the next one, etcetera, etcetera. So you could look at it in text editor. It's just a raw text file with the values separated by commas. You can actually open up these files in Excel, which is having a look at it now, and it just lays it out more like a typical spreadsheet. Excel, by the way, can export see SV files to see if you have data that's not in CSP format, and you want to use a comment of delimited file. You can export from Excel any format from Excel into a CSP. So just real quickly what is the data here? We have Boston housing data. This is sort of a famous data set which contains district by district, different variables for various things about new housing districts in Boston. So we have the crime rate in the district. We have, ah, binary value just called Charles, which is either a zero or one. Most of them are zeros. But every now and then you find a housing district that has a one in it. Uh, and what that one represents is this district is next to the Charles River in Boston. That's all that one represents. We also this one which is measuring nitrous oxide in the atmosphere in that district. For whatever reason, we have the number of rooms in a dwelling in that region. The average or the median number of rooms, the age, the median age of the dwelling, Meaning like, when was it built 65 years ago? In this case, the distance from some key metro areas. We have the, um the percentage of poor people in that district and also the median value of a dwelling in that district. And, um, I'm not sure if this is in thousands or what the value is here, but that's what these fields mean, And so that's what the data looks like when we look at it, just sort of straight up format. So if I go back to the code here, I've started out by typing in d three dot CS fee. And then you put in the name of the file and one important note about this. D three cannot read data files like this from just like a file folder. So you cannot run this code simply by dropping on html file with JavaScript in it into your browser. This is why you may have noticed my you. RL's also look like this. It's sites Colon 80 80 because I'm running a very simple Web browser locally on my development machine. One of the simplest ways to do that Do this is go to bit NAMI B i t. And am I dot or guy believe, and you can download a map stack. So in my computer's ma'am, which is me, no Macintosh Apache, my sequel PHP, and you can download this application and then it essentially run a Web server locally. It's a very easy way to do it. There are a 1,000,000 other ways to do it. But if you're not super technical bit NAMI, ma'am, stacks were great waiting to get started. So you have to run from a server. That's the quick thing of you hit errors, trying to not use a server. This will be why Just so you know. All right, so let's take a look at the code, so d three dot CSP d three dot CSP native natively loads see SV files these comma delimited files. D three also has d three dot tsv, which will load a tab delimited file where the fields air separated by tabs. There's also now d three dot dsv, which will essentially read any delimited values. So in other words, you might have data that comes with vertical pipes in between every data field you consort of manually set What the dilemma is in the EU's d three dot dsv. So long story short, this is just sort of the function or the method for how to do this stuff. And I'm just gonna show you the syntax. And so the basic idea is I say d three dot CSP path to the file in this case is in the same folder as this code, which is why there's no folder path here and then D three. Version five started using promises. So I'm not gonna get into a big lesson here about promises and what they are. But the basic idea is that d three both JavaScript, really generally for years and years could do a synchronous things. Meaning you might ask for a file and then javascript you want to do something with the data in that file? And it used to be a synchronous meaning you would ask for the file and then you'd have to have code written, that would say, And once that gets here, once we've done that work, then do stuff. And JavaScript now uses this syntax where you say d three dot c s v In this case for D three, you know, that's how Syntex works here and then used dot then, and whatever is inside that then will not get triggered until D three has downloaded and parsed that CSB file. So it just makes it a lot easier toe. Essentially, don't make mistakes where you try to call code before the previous stuff has happened, especially in your calling files, because if this file is, uh, on the Web summer and you he would code that was talking to the web to go get a file and then download that data and then purse it. That's, um, can take a while. And so if the coaches triggers too quickly, you can get into trouble fast. So long story short promises save you from making that mistake. All right, so d three dot c S v nema file or path to the file dot Then and then I want to do something . And what I'm gonna do is I'm going to call a function because now I could do a bunch of stuff all in one place. So this is how that looks d three dot c s v dot Then function, you know, curly braces and anything in here. Whatever I want to do inside here I can do now. One thing I'm gonna do also is I'm gonna say function data now that word data here is just a parameter and what that means In this case, if you're familiar with JavaScript, you can call a function, and then you're passing a function of the parameter into the function and then you can do stuff with that parameter. In functions like this, the parameter is more of a reflection of what has happened. So in other words, d three dot c s v is reading in that C S v file. And then whatever happens in there, I'm then saying I want to do stuff with it in this function. And so the first thing I'm gonna do with this is I'm gonna say console dot log data. And so if you're programmer, you already know what this is doing. If you're not, this may be new. But the basic idea is that in modern Web browsers you have the Web inspector. And so if I dio command option I on chrome or control, Option I on PC and cram, it opens up this web inspector where you have like development tools, one of which is called the Consul and the Consul. When I load this code, you will see if I do console dot log, which again is built into most modern browsers. It'll essential right out whatever I have asked it to right out. So let me change the Eurail hair to use this. What were the folder that were working in now, which is the 03 data folder. And if I now run that code, look what happens in the council now that data that got reading from the CSB file is there because I asked it to be written there and I can see that I have 506 elements because there are 506 rows in the data set. And if I hit this little air over here, it opens up and I can see that it's actually broken into segments 100 100 rose at a time. For whatever reason, I don't know why does it? But it does. And then if I open up that I can see each individual row of data. And so if I check this against my original data said, If I go back to the CSB file my first row, the crime rate is 0.632 And sure enough, that's the number I see here. And the nitrous oxide is 0.0 point 537999 whatever. And that matches what I have over here so literally row by row, I've written it to the console just so I can see that the data is there. It's not throwing an error or anything else. And by the way, each one of these rows you'll notice this is Jason JavaScript. Object notations of the C S V got converted into Jason, which is a data format that JavaScript just really loves. D 3/10 to work with it. A lot of most JavaScript that you work in these days will be working with Jason when you're talking about data. And the Jason format is just curly brace field name, colon field value comma, another field name, colon value, etcetera, etcetera, etcetera. You can see over here we see dot, dot dot. But I can again open up each row and see every one of the fields in every single value. So you can sort of inspect the data in this way and make sure everything's happening in the way it's supposed to happen just by doing console dot log. So I now have data. It's not era ring, it's working. It's doing exactly what I wanted to do. So now we can actually start doing some stuff with this data, so let's let's get to it. I'm gonna comment out the consul doubt log blanks. We don't need that anymore. And what I'm gonna do is this. I'm gonna just sort of start typing here. I'm gonna say spg dot select all quote dot d o t. And so what's happening here? You'll notice before we did something sort of similar. We said d three dot select hash chart pound sign chart. And I was saying, Hey, d three, please select the the Div with the i d chart. That's already in the dom the document object model. And we're seeing this simp something very similar here. First, I'm saying, use the S V g object that we created I could have said d three dots electile or as Fiji Die Select All kind of doesn't matter. But I'm saying work within this thing that we already have. It's like every single one, not just one of the 1st 1 which is what d three dot select as. All of them like every single thing that has the class dot Now these don't exist yet, which I'm talk about in a second, but select all of those things if they exist and if not, it's okay cause we're gonna do stuff. Anyways, there's one of those weird things about D three that you can sort of do this even though they don't they don't exist, and it still works. So just take my word on that one. So I'm gonna say dot select all dot And then I'm gonna start doing stuff with those because the way these selectors work, which if you're familiar with Jake weary, you're already used to working with selectors Very similar idea. You select stuff and then you do stuff with it and has also chained methods. So I say svg dot select all. And then if I do another dot something or other and another dot something rather after that , it'll all get chained all working on the same thing until you hit a semi colon, in which case is sort of done. So, for instance, here I'm gonna say that slicked all dots and I'm gonna say with these things, I want you to use data. That's what the dot data is doing. And then I'm passing in that parameter that I pulled out earlier. By the way, these parameters could be named anything. I could call this thing Fred and if I as long as I referred to it as Fred later that's gonna work to doesn't have to be called data. Just so you know, this is have to be dot data, but the parameter name could be anything. So I'm just gonna use data just cause it's simple. So dot data data used that data and then I'm gonna say enter. And this is another kind of an odd specific thing about D three, where essentially there's there's this Enter command. There's also one called exit. And so the deal here is I'm saying, All right, d three. I want you just like anything that has a class dot I want you to work with data and specifically this data that I have and then when I want to do is for every object entering the screen, which is gonna be one for each row of data. I want you to do stuff with it. So that's what the dot enter is doing. If I if I had was, let's say, updating the data and some rose had disappeared from a data set because I filter them out or something, I could call it dot exit and then I would be telling it may be to remove any dots on the screen that are exiting because they're disappearing from the data. So we're not gonna really go into dot exit at all, but dot Enter is for every single thing being added to the screen, I want you to do stuff. So what I want you do. Well, I'm gonna say, uh dot append a circle because I wanted a circle for every single row of data. And so, you know, earlier when we were testing adding circles, we said s v g dot upend circle, which was a pending one circle, right? That's great. What's really powerful and cool about D three is that when I say select something used data and for each one of these things, enter it. And then for each one of those I'm saying append a circle. Essentially, this acts like a loop. It's literally looping through the data one road of time and for each one of those things, adding a circle to the stage, which is super cool and powerful. And so now I'm gonna say for that circle, I want you at an attribute. That's how the chained methods work, right? And now I'm working on that circle because I appended something. And for each one of those do stuff, and I'm gonna say I need to tell it where the center of it should be. And I'm just gonna mainly set that to 100 kind like we did before. I need to set the c y value. Make that 100. Also, I'm gonna set the radius to, let's say, five, and I'm gonna have a new attributes which I'm gonna call. Well, I'm not gonna call. It is Phil. And so what this is is the fill color now a couple of notes about that. First of all, you have to use the word Phil. You know, if you're doing this in CSS, which you can do by the way I could instead of saying, attribute, Phil, I could say attribute class and give it a class name and then put a class up here in my CSS and established that fill color up there, and I have to add after call Phil, they're not color because this is SPG. And this is the word that spg uses for Phil car. But long story short, I can produce a CSS, but in this case, I'm intentionally doing it as a manually set fill color in the JavaScript. Because later on, I'm going to ah, be adjusting. I feel color based on the data. That's why I'm doing it this way. You could definitely do it either way depends what you're trying to do. So if I save this thing and I go now and I reload the page we're working on earlier, But what happens? I have what looks like a circle. And so I'm in my web inspector. In addition to the console, I have this thing called elements and elements. I should show you all of the elements in the page, the entire document object model. So I have my div with idea of chart in here. If I open that up, I have my SPG. And if I open that up, look at that. I can see my circles and it's not just a one circle. It's many, many, many circles. But of course they all have the same c x and see why. So, essentially, I have 500 plus circles sitting right on top of each other right there. So in other words. The code is doing exactly what it's supposed to be doing it it's doing exactly what I want . So we're doing really great. Nothing to do before we go away here is I'm just gonna add one thing I'm gonna say circles equals this stuff. I'm setting a variable. And the reason I'm doing this is because if I want to refer to these circles that I've created later on quickly and easily, I now have them essentially attached to an object. Kind of like I said, you know, s V G equals this stuff, and I could refer to SPG later on and work with it. That's why I'm doing circles equals so that I just have access to it later on. And to that point, I'm gonna declare that circles variable up here, which introduces another really important idea in programming which is referred to as scope . And so I'm not gonna here really to explain scope and depth. But the basic idea is that if I say you know, circles equals something and I don't declare it outside of this function, then that variable names circles is only available to me as long as I'm inside these curly braces. So, in other words, if I tried to do something with circles out here, you know, later on and my script it's not gonna work, cause the script doesn't know that it exists. But if I declare it up here, I say there's a variable. It's going to call circles and you keep your eye out for it. Then when I do stuff with it and you know, sort of a sign it a value in here, then it's still available to me later on. That's why we have these global variables, like within height and circles. And, uh, SPG is also global variable. So we'll be working with those later on. All right, So next we're gonna start applying more attributes to the circles that are actually gonna be data driven and start making this thing really come to life. 4. Making Data-Driven Graphics in D3: all right, so we can start doing stuff with these circles now, based on the data that we have loading and working the first time actually to do is I'm gonna go back in here. And I was gonna add something to these circles. And when I'm gonna add is that class because, you know, I'm doing this select all dot class things up here and they don't exist yet. I'm doing stuff with them anyways, but they want that. Adam, I might as well make sure they have that class because then later on, if I ever wanted to refer back to them using a select all, you know class dot things, then they'll have them. So this doesn't serve any purpose right now except to know that it's there for use later on . I'm also going to do this. I'm gonna add something else. In addition, attributes we can add styles directly and a style attribute will be added to the object directly into the tag, as you'll see in a second. So the style I'm gonna add is opacity. Message the opacity to 0.5, and so capacity can be anywhere between zero and one zero is invisible. One is 100% opaque, and so a 0.5 is 50% translucent. So I'm gonna hit, save. I'm gonna refresh the page and you will see that it looks exactly the same because I still have 506 dots run on top of each other. Even though they're half trans listened, It looks like a single dot still be. But I can see down here in the inspector that they have a style of a pass. It e 0.5 each one of them. And by the way they have the class equals dot So everything is being added appropriately. The code is doing what it's supposed to be doing. So, you know, it's obviously a great place to start. So the next thing I'm gonna do, which is, you know, really what we're here to do, like most importantly in D three, is too. Change the placement of these objects based on data, right. A scatter plot is dots on a chart placed in the X axis horizontally in a certain position, based on the number, Why access a basement certain position, and in our case, we're gonna use Thea the DOT size, also based on data. So let's let's do the X value first. So here I'm setting the center on the horizontal axis manually. 200 pixels from the left. That's great. Whatever. It's not really dated visualization, though. Instead of sending it manually and statically, what I can do is use a function. And so the function looks like this and you know, so it's kind of like the function earlier where we have a function and then parameter. So what is this parameter D now, by the way, once again, I don't have to call this d. I could call this Fred Joe or X Y Z doesn't matter, but I'm calling it because that's sort of a norm in D three. And what's really powerful and amazing about D three is that every circle as being added to the stage because I said, you know, select stuff used data, and for everyone that's being added at a circle to it, it didn't just add the circles. It also bound the data for each circle to each circle, meaning every row of data that is driving this circles existence is also bound to that object. So D three is aware of the data associated with each one of those objects. So if I say let's use the function instead of saying this manually and I just say console looks console that log D I hit, refresh on the page, save and refresh and watch what happens. First of all, all the circles kind of get stuck over here because I haven't told it a value to use. Yeah, just so you know. But if I go back to my console, look at what I have here now, like we saw earlier every row of data. If I scroll away, up to the top is now visible in the console because I asked it to be written there. And so this is the first row of data. Remember, crime is 0.63 to, uh, noxious nitrous oxide is 0.5379 etcetera. And so that data is bound to it. So I can use that data any time I refer to that object. So let me just get rid of that. And what if I did this? So the function now, in order to set that C X value, I have to use return because what this is doing is I must say that 200 actually is. I'm saying, said the attributes the C X attribute to the results of this function, and you have to use the word returns. If I just say this return 100 and I hit Refresh, watch what happens. It's exactly what we had before where I have hundreds of dots, all in the same position. Sex is 100 c wise 100. So it's nothing has changed from what I did earlier, except instead of saying set the c x 200 you all in one spot. I'm saying Use a function, but I'm still returning. Uh, static values. That's not that interesting if I take out that return, by the way. So I just safe 100 here and I hit. Refresh the circles and up over here because there is no C X that's being set D three is confused. And so if you hit an error like this, which you probably will do nine times that it's at attendance because you forgot to use the word return here, so make sure it's return value, but I don't want to set this value to be static. That's not the point here. I want to set it to be driven by the data. So instead I'm gonna say Use that D parameter and use d dot poor. And so this is how you refer to Jason values in JavaScript. It's D cause that's the object name that we assigned here dot field name and remember, we have a field that is called poor right? The percentage of poor people in that district. So when I say return d dot poor, it's saying, used that field for this circles value that's been bound to it. One wrote a time. So if I hit, refresh, watch what's gonna happen? I have no longer 500 dots around on top of each other, but they're all bright stuck over here. And so why is that? Well, because the percentage of poor people in this first dot is 4.98% which means that I've asked d three to place that dot 4.98 pixels from the left. The next ones nine pixels from the left. Next ones for the next ones. About three, etcetera, etcetera, etcetera. Those poor values a very small numbers So they're all stuck way over there and left hand side. So just so I can see them all. What if I multiply them all by Let's say 50 now I hit, refresh, and look, Now I can see them. And because they're spread out, I can now see the translucency. There's only one dot Here there's a whole bunch on top of each other right here, etcetera, etcetera. Now they're running off the screen. So I'm just gonna mainly changes to a 30 for now, just so I can see them. This is not the way you do data visualisation cause scale matters, right? You would never manually just multiply my number. Um, but I just want to see where they live and see how it feels. And it does seem to be working. So it's good enough for now. Now, I would do something very similar. Where, instead of using ah, set value ah, hard value for the see why I'm gonna set that using a function. Also, instead of using the poor field, I want to use the rooms field. I am a new say brooms times 50 in this case and I'm a hit refresh and Wow. Lo and behold, look that we have something that looks like a scatter plot. And so once again, it's manually setting the parameters, you know, in terms of how, how much on multiplying numbers by which is weird. But it's good enough to get a sense of what this data looks like. And so I have poor. You're more poor to the right. And you have. Don't forget, this is another weird thing. Zero on the Y axis is up here at the top and a high. Why number is down here. So in other words, the more poor you are, the fewer rooms you have in your dwelling, Which makes sense. But of course, it's going up vertically, which feels a little weird. We'll deal with that later on. Now, finally, I'm gonna add also for my our value, right the size of the bubble, another function, and I'm gonna use the value field, right. The price of each dwelling hit, refresh. And I have giant dots and I have smaller dots. But the's air really giant. They're all on top of each other, and I could make the easy ones even smaller. So I'm just gonna divide by two again just to see what that looks like. And that's good. So now I have a little nice teeny dots and I have nice big dots clustering. And once again, just from a data standpoint, it all makes sense. Less poor is over here, meaning more wealthy, a lot more bigger dots, meaning higher value, more poor, smaller dots, lower value homes. That's just it makes sense conceptually when we think about how these kinds of things work from a data standpoint. So the last thing I'm gonna do, because I'm just gonna add a style to my CSS up here because I want my dots, my things with class dot to have two attributes associated with them. The 1st 1 is a stroke, and I'm setting the stroke color manually to black on. But I'm also gonna add a stroke with and this is the syntax for that and the stroke with I'm gonna set to ah one. And I think it's It's one. Actually a minute. I think I have to do one PX um and so I think it does one pixel by default in SPG. And if I say this and I hit, refresh we really can't see it because the dots are already black and the capacity is 50% of the stroke is you really can't tell the difference, but we're going to using that dynamically later on. Which is why I said it this way in the Azaz. A class with style. All right, so next we're going to start working with really setting these scales of these things properly, using another really powerful tool built into D three. 5. Using D3 Scales : All right, This is gonna be a big one. This is gonna be a pretty complicated lesson, A lot of code, but a lot of its repetitive. So once you get the concepts, it will come together relatively straightforward. But there's a lot to go through here. Just say, you know So the last lesson you know, we placed these dots on the screen just by multiplying things right. We had small values for the poor, so he's sort of multiplied by 30 just to get him to spread out manually. And that's just not the right way to do it. Um, what we really need to do is to use a tool built in two D three to set our scales dynamically based on the data and based on the amount of space available to us and D three has built into it these amazing tools to do that. And so these are D three scales, and there's a bunch of different ways to do scales and d three. I'm just going to do one of them here, actually end up doing a couple during this lesson. But I'm gonna start off using one that you probably will find yourself using quite a bit, which is a linear scale. So the first thing I'm gonna do is I'm just going to create a variable called X Scale cause this Gail's gonna used for our X axis are horizontal placement. And I saw Miss eight X scale equals d three dots scale linear. And that's because this is a linear scale, meaning that it's gonna have essentially a starting point and unending point. And if you pass in values anywhere between those two numbers, it'll essentially put something on the screen based on anywhere between those two numbers the same ratio, which all started shaving a second. So a scale consists of two things. There's the domain, and then there's also the range. And so the domain is also often referred to as the input values and the ranges refer to as the output value. So I was gonna manually set my domain and range and just explain what they are. So the basic idea here is I'm saying I'm gonna use a scale, and I'm gonna pass in values and those past in values or the input values, and then this is gonna magically convert those into X coordinates. on the X axis between zero and 500. It's the way you actually use it is instead of saying, return d dot poor times 30 like we did earlier. Instead, we say return ex scale Didot poor. And now, when I'm saying is okay to figure out where to put things on the X value, use this function called X scale, using this circles poor value. And so that's the input value. So somewhere between zero and 30 I'm guessing. Or maybe the minimum and maximum values available within that field. And so, in other words, if it was, if d dot poor was 15 for this circle will be right in the middle. In between these two linear the scale, the linear values and therefore is gonna return and place on the X axis that exactly a 250 again a halfway between zero and 500. So the input value is the data value and the range the output value is the placement in the X coordinates. So let's see what happens if I just sort of hit save here and hit Refresh. Look at this. So it goes all the way potentially from his small zero all the way up to it should be 500 which should be about halfway. Why's it going beyond 500? Maybe I must have values that are above 30 and that's what a linear scale is. It will do anywhere between these two values, leaving handle numbers that go beyond those two values. So let's take a look at our data here. If I go over here and look at my poor field and I sort from largest to smallest. Sure enough, the highest value is actually about 38. And so that's why things are extending beyond the right handed. So if I change us, that's it. I thought guest the maximum was 40 hit, save, hit, refresh, watch. It happens. Everything squishes over now. Now there no values higher than 500. In fact, that's a little bit smaller than 500 because a little bit below 40 if that makes sense. One thing you'll notice is that both the domain and the range you pass in an array after these little brackets are so it's an array with the first value and a second value. If you're doing scales and you have errors, it's just not working, right? Or maybe it's even throwing an actual error. Odds are pretty good. You've forgotten the brackets inside these parentheses were the comma or something like that. This is a very common mistake, especially when you're just getting started. So we still have, you know, some issues here, which is that I am first of all, you know, sitting my maximum value at 500 from I write my range, right. The actual output value, where it actually goes on the screen that you really be a thousands. Let me just change that for now. Again, just manually get refreshed. And sure enough looking, it spreads out. This is the power of scales, right? It makes it so much easier to do stuff like this. But worse than that is I'm making a guess. I'm guessing the minimum value for that field might be zero. The maximum value might be 40. In fact, the first guess I had was wrong, right? Perfect example of a mistake. This is also a bad way to do it. What if I have a giant data set and I didn't know the minimum and maximum values were even worse. What if I was working with dynamic data and this data was changing. And so therefore, the minimum maximum might really be shifting over time, so I can't manually set those numbers. It just doesn't make sense to do that. Which brings me to the next really big, powerful, important, helpful tool that's built into D three, where I can actually, you know, calculate the minimum and maximum values. So once again, I'm gonna create a variable. I'm just gonna call X men, Max, because this is give me the min Max for the X placement again, and I'm gonna use d three dot extent and d three dot extent does exactly what I'm saying. It's actually just finds the minimum and maximum values. That's just the syntax. It's the way I do it. As I pass in the data once again, I have this variable called data. So I'm passing that in, and then I have to use a function to get out of it. What I want to get out of it. It's a good time use function d just cause that's a good norm to use. But I could call that d whatever I wanted and the reason I have to do a function is because that data is essentially a collection of a bunch of fields. I have to tell d three dot extent which field I care about. So I want to say return d dot poor Now if I just did return d dot poor it's gonna get very confused because in a C S V file, all of that data is actually stored as a text. And so d three things. All of those values, even ones that are we know their numbers because we look at him or humans, we can tell what the number is. D three thinks it's text it something. It thinks that the string 0.632 So actually to convert this into a number and I'm gonna use just a built in JavaScript function called purse float. And so parse float is literally using JavaScript to say, Take this string and return the floating value. The actual decimal number that that string represents 0.632 If I use parse into I nt, then we'll be rounding the numbers up or down two integers which we don't want because we want the actual values. So purse float just does that. All right, so now I have the min max value. And let's just, you know, right that to the console so I can see what it looks like. And make sure I'm not seeing any weird errors. Some to say console dot log min Max, go back over here, go to my console hit, refresh, and look, I haven't array. See the little brackets And my minimum value is a 1.73 whatever. And my maximum value is that 37.97 etcetera. And so I can see each individual value. It's working. So I have these numbers. What do I do with them? Well, you might guess rather than manually setting my minimum and maximum for my domain, I'm gonna use that variable instead. Some essay used the X men Max. Use the first value for the input the minimum and use the second value for the maximum. And so you'll notice the first value is that zero index position in an array and JavaScript And the second value is at the first index position. A little confusing if you're not a programmer, but that's just had job script works. He uses zero indexing for accessing the first element in an array. And so now if I hit, refresh once again you will now see that it goes all the way from zero now because my if I haven't whatever my minimum is, it's gonna place it at zero. Whatever my maximum is, it's gonna place it at 1000 and anything in between is going to place anything in between. And so it's zero. But don't forget, this is the center of the circles at zero. So therefore it's running off the left hand edge or, in this case, running off the right hand edge. But it's placed exactly at zero or 1000 for those smallest end largest dots. So my ex scale is working beautifully. So I'm gonna do the exact same thing for my why. And my r sum would call this a Lyman back Simon Collison or Min Max. And for my why Min Max values. I don't want the poor field. I want the rooms field and for my arm and max value again. I don't want the poor. I want the value because those the fields that are driving the Y position in this case and the size of the bubble in this case. And then once again, I'm gonna use a similar thing. I'm gonna create two more scales. I'm gonna create a Y scale and in our scale And instead of the X Men, Max, I'm gonna use the Wyman Max. So for my Wyman Max, I'm gonna say 0 to 300. We'll just see what that looks like for now. And they for my our scale. I'm gonna use the arm and Max instead of the X Men. Max. And I'm just gonna manually said I want I don't want my circles to be any smaller than two or let's say any bigger than 10 radius of tens of diameter of 20. And so once again, I do the same thing I did down here. I say use the y scale with this value. And I used the our scale with this value. And I don't need that divisor anymore. So if I save, I hit, refresh and look at what we have. So we go all the way from the very top down to I only said it to 300. I guess my height is What is it? 500. It's only change out to 500 see what happens. Yes, now it goes all the way to the bottom from all the way to the top, alway the bottom all the way to left all the way to the right, and so is using up all of the space that I have available to me, which is a great starting point. But, you know, it's running off the edge. That's weird. So there's an easy way to fix that, too. You know, I'm telling it to start at zero and end at 500 started zero and entered 1000. But why don't actually set that so that it handles that mawr elegantly and the way I'm gonna do that as I have my width and height as variables up here, I'm gonna add a new variable called Margin on my set That to 30. Let's say so. The 30 pixels of margin in my chart is what I'm looking for. And so now I don't want put that my minimum value at zero. I want to put it at the margin. In other words, 30 pixels from the left and then my maximum value instead of 1000. I want to put out the with minus the margin, so it's gonna be 970 pixels. But the reason I'm doing this is what if I wanted to double the size, I could just change this number and it would automatically figure out how to make all my adjustments down here. And so similarly, I'm gonna say for my why values I want the minimum value instead of being at zero again to be the margin in this case instead of with my ass margin, I'm gonna say height, my highest margin because I'm not talking about going this way with my wise. It's all the way from here to here. So had saved hit, refresh. And now everything is moved in by 30 pixels from all of the different edges. But this brings up an important sort of interesting thing. And I mentioned this briefly before. I think where, you know, we have less poor, so wealthier, more poor to the right, and the more poor have fewer rooms. But it's it goes up, and that just sort of feels weird for people. Even it's a lower number because the Y zero up here and high wise down here. So how do we fix that? You know, using scales become so easy to fix it because all I have to do is say, you know what? For my input values, instead of having my minimum value and that's associated with the furthest you know, the lowest. Why, which is at the top and my maximum value with the highest Y. I can just swap these. I can say, put on maximum one at the top and the minimum one at the bottom. And I could have left these the same and said Swap these two. But either one works. Now, if I hit refresh, the whole thing is gonna flip vertically. And now, yes, the poorer I get the fewer rooms, right, cause usually reading the scale for the wise, going from a low number toe, a high number. So it just did that automatically very easily for me. So scales aren't just for placement, you can do other things with scales, and I'm gonna use another kind of scale here, and I'm gonna call this one see scale, because I'm gonna be using this one for the colors So instead of using a linear scale, I'm gonna use us unordinary scale. So this is scale dot scale orginal. And this also has a domain and whips a range still has input and output values. In this case, the domain is essentially, um, hard coated single values. In my case, which again I could make this dynamic. I wanted to, but there's no need to, and the output values are essentially directly associated with each one of these. So a linear scale goes anywhere from here to here. In fact, as you saw earlier, it'll even go outside the bounds of the demand you provide. Whereas an ordinary scale literally associates the first value and then the range to the first value in the domain and the second value with second values of the directly tied. That's what I'm gonna do here is I'm gonna just give it a hexi decimal value of color value . And I have for my maximum value, the one I'm gonna turn things orange for the minimum value. They're gonna be this color gray. And so the way I'm gonna use this one is to form. I fill color, and so I'm gonna change this to a function, Andi, as you can imagine, return C scale. And in this case, I'm gonna use the d dot Charles. And so what's happening here is I'm saying, if you remember that the Charles Field, if I go back to the spreadsheet here, is this one the hedges, zeros and ones. Every now and then you see a one which means that this district is near the Charles River. And so I'm literally saying, passing an either zur or one from that field if it zero passed me a gray value, if it's a one, pass me an orange value. And so now that ever signed that I go back, I hit, refresh and boom. There we have it. We have orange dots, we have grey dots. Now the orange dots are a little hard to see for two reasons. One is there opacity. And that's easy enough to fix one. Add something else to this instead of setting this manually. Once again, I can use a function. And so I'm gonna again use the bound data. And instead of sitting in a lamb to say return Dida, Charles equals one. If so, return one if not return, let's say 0.3. So if you're not familiar with the shorthand if else statement in JavaScript this is what it looks like. This literally says if this is true, Dita Charles equals one. This is what tells you it's an if statement. Then do this otherwise do this and so is going to return that value. Based on what? You know what What's true here? So now, once again, hit, refresh and boom these air perfectly opaque Whereas these are nice and faded back Very little a pass ity But as you can see, I still have an issue because these orange dots are behind some of these black dots and I really want the orange ones to stand out. And especially if we had a really small orange dot behind like multiple black dots, he maybe you wouldn't even be able to see it at all. So this is also flexible and the way it's flexible is to understand a very important thing about svg. SPG is all about the order. The elements appear in the dom on the page. So the first row of data laid out this first dotnet dropped it here the 2nd 1 is here. The 3rd 1 is here. And so if all three of these were on top of each other, this 3rd 1 here would literally be on top of this one here. This one would not be visible, whereas this one would be visible. And so it's all about the placement in the order. So that tells me what if I sorted the data so that all the data was ordered by the Charles River field and all the zeros come first, all the gray ones and all the orange ones come later, So the orange ones will then be on top of those gray ones. So sorting and Java script is a little weird, the syntax. But it's not hard. It's just a little weird and a little confusing sometimes. So the quick and easy way to do sorting is to just use the built in jobs, get function. I'm just going to them to say data equals data dot sort, and what you do here is once again, you use a function and they're two parameters that are used in the function. And essentially, it just reads like this and I'll just explain it. Charles, minus beat Charles. So essentially, what dated out sort does and JavaScript is. It goes through the data one row, one element of times, actually sort of two elements at the time, the first number of hits and then the second or the first thing it hits the first row of data. Let's call it in the second row of data and by saying return eight out, Charles minus beat out Charles were just telling Javascript. If it's the low numbers, make him first. If it's the big numbers may come second. If I If I reverse thes beat out Charles minus eight Charles, I would actually reverse sort it. So it may seem a little confusing. Definitely. Look up sorting and JavaScript in another tutorial to learn more about it. But for now, don't worry about it. This is the syntax is just how it works. So once again, now for these, like, look at these dots over here that are sort of behind these other dots. When I hit Refresh. Now they're on top because they're coming later, when being pushed on to the, uh, campus onto the stage by d three and I was gonna do one other thing in the code very quickly. Um, you know, we've talked a little bit about variable scope here, and we have our global variables up here. I'm actually gonna actually add my ex scale. And why scale variables here? Because I need to use those outside of this function later on. This is just future prove ings. I know I'm gonna want a reference thes elsewhere. And so now if I declare him up here, rather up here, then they'll be available to me later on. 6. Using D3 Axes: All right. So we've still some other things that we want to tweak in this project. And, um, actually noticed a mistake that I made earlier. If you remember, when we look at the code, um, you know, I had added this class this dot class, and I had set the stroke to this color. But I have quotes around the color value, and so you notice we don't see the stroke here. And so classic example of the kind of mistake that I make all the time. You know, if I don't, you don't need quote marks around that color value, so I need to take those out. Now if I hit Refresh. And now we can see this nice black outline around our orange dots. And because their 100% opacity I see them, these other ones that are, you know, essentially lower rapacity. You don't really notice it, but it is actually very subtly there because don't forget, this is actually a gray feel color, I believe. Long story short. I just wanted to fix that one real quick. So what we're gonna do in this lesson is add the access line. So here's the finished version and we have, you know, our maximum value minimum value. We have our little vertical and horizontal lines. You know, we have axes. And how do you create an access? Well, you know, we could just manually create it right? I could literally manually draw a horizontal line that starts here and ends here manually. Draw this little line mainly. Drop this little line, mainly draw the labels. It's said it one by one by one. That'd be kind of a pain in the butt. Why would you do it that way? That's just crazy. Luckily, of course, I'm going to say D three has tools built in to do this very easily. So kind of like the last lesson. This one's going to be pretty involved. It's gonna take a while. Axes are It's a great tool. Built in two. D three takes a few steps, but again, copy paste. It's actually pretty straightforward concept. It just takes a few different steps in a few different lines of code to do it. So let me go back to our working document here and our code, and the first thing I need to do is I'm gonna create a variable that I'm just gonna call X axis. And so I'm gonna say X access equals D three dot hopes access bottom and what's not Boston bottom. And I wanted to use my ex scale. So what's happening here? I'm creating an object, and I'm saying I want to use D threes built in access Bottom method and an access bottom is literally just a bottom access. That's the kind of access that lives at the bottom of charts normally, which is what It's an X axis, right? That's just how we refer to it. And you'll see it doesn't actually end up at the bottom of the page by default. We have to move it. But we also have to tell it what scale to use, because then D three will automatically make it the right with using that domain and range that we set up above in the scale. So it sort of really helps make it easy to tweak your axes down the road as your data changes, and I'll show you that in a moment. Next thing I need to do is I need to create another object that I'm gonna call X X SG and what's the X Axis G and what this is gonna contain is an SPG group element. So spg dot upend G and so grouped elements. G elements are really good things know how to use. Essentially, If you put stuff inside of a group element in SPG, then you can sort of act on that single grouped element as a single element. And so, for instance, if I go back here, this axis essentially consists of two labels. One of the top one of the bottom to tick marks, one of the bottom one of the top and the vertical line that connects them. It's That's five different objects if you're to create them mainly. And even if you wanted to create a manually, you could. But you'd want to put him into one G one grouped element, so you can then actually move them around as a single object. Rather have removing all individually. That would just be crazy, right? So long story short, I create my grouped element. I'm actually gonna give that group a couple of accurate, so even give it on i d. And I was gonna call X axis for my i d so I can refer to it later, and I'm also gonna add a class and the class. I'm just gonna call access. And that's because I don't need to have X axis class. That's a different from my y axis class, because they both share the same color and visual treatment etcetera, both for the labels and lines. So one share class will do the trick for this. And then the last thing I need to do is I need to then essentially take that group element that I created that object and call the access that I also created. There's just this syntax is just how it works. Don't get too hung up on it. That's just how does it so now that I've created the Axis? Added it are, you know, also created a group element with a couple of attributes and then use that group element to call the access. If I go back in here, hit refresh hopes that the new on sorry hit, refresh and Boom. We have a quote unquote bottom access, even though it's at the top and you'll notice a D three did some pretty cool things, you know. First of all, it automatically used the scale, so it starts at whatever. That minimum value is 1.7 and goes all the way up to 38 ish at which you can tell right This goes from 30 to 35. It's this wide. This is less why this is a lie like three, not five difference. It also automatically added tick marks at some regular intervals and even added the values right. So it's doing things based on algorithms that are very smart, very powerful. I don't want to use the built in defaults, which we're gonna fix later on. But it's pretty good, right? This is a really good start, So the next thing I want to do is I want to move the access to the bottom of the chart where it belongs. Just doesn't really, really want to live at the top. It's a norm that your ex access lives at the bottom of the chart and your Y axis lives to the left of the chart. So the way to do that is to use something called Transform because essentially what we wanted is we wanna move this whole group, so after we call the access, we can just add another attribute, which is a transform attributes and what I'm gonna uses the translate method within the transform attributes and translate method looks like this. Now you'll notice. First of all, this is a string. So I call transform attributes and I translate it and translate essentially translates to I'm moving it zero pixels on the X axis and 100 pixels on the Y axis. So I'm saying, don't move it all horizontally, but move it down 100 pixels. So if I hit refresh now, this whole access group, the whole thing should move down 100 pixels to around there. So if I hit refresh Boom there it iss right did exactly what I wanted to do. So, as you can imagine, I don't really want to move it manually. 100 pixels. I could manually move it. 470 pixels, right Member heights, 500 miles, 30 margin, and it would go right here. But why would I use hard coded values when some of those values may change down the roads and said, I'm actually change this hard coded number and use the variables that have already established in the way I'm gonna do that is, if you're familiar with Java script, weaken do what's called string concatenation, which is a big word just to mean I want to take my string and combine it with variables and sort of put him back together as a string. And the way to do that is essentially, you know, I have opening quote and unending quote, and what I want to do is have end the quote and open the quote again and then separated with plus signs and then in the middle here, I'm gonna add the variable. So if you remember, the variable is we have our height minus margin. So you'll notice I put in parentheses because if I tried it, can Cat made a string and don't put the parentheses around it? Sometimes it'll do weird things where it will be, you know, height minus margin. And it'll actually end up. Is those two numbers sort of put together, and it'll end up being a big number rather than actually doing the subtraction first on, then putting that 470 pixels into that string. You know, try it, experiment with it and you'll see what I'm talking about. The long story short. If I do this now, if I had saved and hit refresh, my access line goes right to the bottom, it's exactly where I want it. Now I have an issue where I have a circle that's crossing it, cause once again, this is also being placed exactly centered right here, and we'll deal with that later on. So what I want to do now is I want to fix this issue where I have, you know, interesting tick marks. D three is just doing automatically for me, which is great, but there's a few issues here. One is that you know, there's no reason for this tick market 15 Like who cares where 15 is by default? I recommend that when you're doing data visualizations that you use as a few tick marks, as you can possibly get away with. So my default position is always to have the bottom number and the top number and nothing else in between. You have to convince me to include extra tick marks, extra values, because if they don't serve a purpose, then they shouldn't be there because they're really a visual distraction. They take your eye away from the data, which is really where you want your audience focused. So there's a bunch of different ways to do this. One thing is built in two D three axes, of course, because they're so great, I can do things like, say, add to this, you know, X axis. He goes d three dot excess bottoms x scale. I could just say ticks zero. And if I save and hit, refresh Now watch what happens. I have no ticks, no labels, no extra tick marks, just the beginning and ending tick mark so and that I could manually place the bottom and the top number here. But that's not the most useful way to doing. Instead, I can use something called tick values. And so tick values is kind of because I can interest manually say, I want tickets values at, let's say, three whips three and 12 and you'll notice that these air in an array Okay, so just, you know, again, if you do this and something weird happens, you're probably forgetting the brackets in the comma. And so if I say put, take values at three and 12 and I hit Refresh Look, there's a tick that tick at three. And then there's 1 to 12 you know, and Aiken, because it's an array have as many of these I want that I wanted 33. Boom! There's 1 33 now. Of course, I don't want randomly placed tick values. That's just kind of weird. Instead, I want to just have one of the bottom number and one at the top number. And don't forget we already have a variable that contains our bottom and top numbers. Right are minimum and maximum values, so I can copy that variable. Instead of manually doing this, I can say Use my tent X Men Max, First Value and My X Men Max Maximum value, second value save. And now I have one at the bottom and one of the top, and you'll notice it's using integers by default. That's what you know. The D D D three access methods use. There's a way to change it to use the float value on, but I'm not gonna bother doing now. We can always tweak those kinds of things later on, so the next thing I want to fix related to reducing visual distraction is thecolonialplayers, because I also strongly recommend that you never use black against a white background for your access lines or labels again, you want to reduce contrast, reduce distraction. You don't want your audience to be focused on your access lines and labels. They have to be able to read him, but they don't need to be drawing attention to themselves. So I was recommend using a like rain we already created ah style. We added a class to those objects and so I can create a class in my CSS using dot access. And when I need to do is I need to say dot access line and dot access path. And I'm gonna set the ah stroke for both of those to be a nice like Ray. So why did I do Don Access line and got access path? Well, if we look at the actual access in the inspector right, the elements here here's the group element, which contains all the things right. And if I open that up lips and you can see it has the class axis. If I open that up, there's a path, which is how D three creates the horizontal line and there's also each tick and each tick is a group which consists of a line, which is the vertical connector and the text. And so for whatever reason, D three creates paths and lines. And so both of those need to have that, like, grace, stroke color. And there's also the text which contains the actual label itself. And so, while I'm at it, I might as well say dot axis text. And I want that to use the fill color. And remember, I have to use Phil, not the word color here. If I use color, nothing's gonna happen. So again, good place to debug your code. You're probably gonna use color by default if you do it a lot of HTML and CSS, you can't. You gotta use Phil. So fill with same gray go back hit refresh. And now they're nice, like rates readable, But it's not distracting. So now let's do the same thing for the y axis, right? So I'm gonna go back down to my axes and I'm gonna create Oh, why Access object? And instead of a bottom scale, it used what's called a left scale. And instead of using the x scale, I'm gonna use the Y scale object. How many is my why Min Max values? And I'm gonna create another object called Why Access G. And this, of course, uses my arm in a brother. Assign it an idea of why access and again has the same class. And then I'm going to use that. Why? Access group? I'm gonna call the y axis object. And instead of translating zero horizontally and 470 or whatever it is vertically in this case, I want to have this thing instead of being right over here way at the zero point, which is where it would be by default. I don't want to move vertically at all. I want to move it horizontally. 30 pixels. So if I go back here instead of doing the contamination on that value and salmon to do it on the first value, so now it's gonna move it horizontally and not vertically. But of course, I don't want to move it. Height minus margin. I just want to move it 30 pixels over from the left. And so I'm just going to say, move it over the same amount as the margin variable. I could Hagit hard code at 2 30 if I wanted to, but I'm just gonna do it as margin for now. So now if I hit, Refresh There it ISS. Now you will notice that you know, I have again circles crossing lines because again they're placed exactly the same spot which we're gonna fix later on. And the axes themselves cross each other, which isn't necessarily a problem. But we are going to fix that as we fix some of the other things. And this is another case where the axes, you know, make it much easier to do than you might think otherwise. And so what I'm gonna do is I'm gonna actually you know, we have our variables up here with height margin. It said I'm gonna add another variable that I'm gonna just gonna call our values. And I'm gonna just assign this to be an array of a list of two things in this case which is going to be two and 10. If you remember, we have our minimum, and maximum bubble size are meant. The smallest one is two pixels and radius. The biggest one is 10 pixels. And so I want to want to use those values in a few different spots. The first place I'm gonna use it is in setting my scale. So if you remember for our range right, our output values, we said, put it from the left. You know, the minimum value will be exactly 30 pixels from the left, and the maximum value will be the full width of minus the 30. So 1001 is a 30 which is 9 70 and that's fine. But if I want to just shove everything over right, I want I don't want this guy right here. I want him shoved over a little bit. And how much do I want him shoved over? Why one shoved over literally, exactly the same amount as the radius right half the width of the circle. Because then it will be right over here, and the edge of it will be exactly at the edge of the access itself. So I can do that using that our values. So I can say, put the minimum X value on the X coordinates at the margin, plus our values, that thing that I created maximum. So in other words, it's always gonna be sorry. Not 10 just one. It's always gonna be in this case because there are values is set to 10. It's gonna be a 30 plus tens of 40 pixels over and the same thing the width minus margin minus our values. Maximum value. And so now, if I hit, refresh everything is gonna show over just a little bit, right? So literally this guy is now hitting the edge and I could tweak that. I can add one or two pixels to it if I wanted to, But that's something you can tweak yourself later on. So I have my our values. I'm adding it to this year, and I'm gonna do the same thing down below for the why I don't want it from the top. I wanted the top plus the maximum radius, and I want it again. The height minus margin minus that radius. So again, if I hit refresh now, everything will shove in a little bit vertically and you'll notice some was gonna close this guy up. So doesn't keep, uh, highlighting as I go back and forth. And I might as well change these because why, said Thies, hard coded when these could be set manually or abusing dynamic data as well, so I'm gonna use the minimum and the maximum value that I have coming from my variables down here. So once again, save hit, refresh. Nothing visible. Change their cause. We already saw what we had done earlier. Now, one of the thing you'll notice is that this circle is, you know, not even to the edge because this circle is smaller. We're shoving everything in by 10 on This one has a small radius. That's why this one's at the edge. But this one isn't. And you know, while I'm messing around with my numbers here, I'm gonna make the biggest circle a little bit bigger. I'm gonna call it 15. Now if I say that the biggest circles are a little bit bigger, things are still automatically shoved in, moved over, placed exactly where they need to be. And that's the value of using variables rather than setting things manually. If I had a bunch of places where I'd set the r values manually, I'd have to change. Then every spot where is now? I just change it in one place and in updates everywhere I needed to. All right. Things looking pretty good. I think all that's left to do now is to animate this and add a little bit of interactivity , and we'll be good to go. 7. Animation in D3 : All right. So our scatter plot bubble chart here is looking pretty good. I'm really happy with it. And, um, next, what I want to do is to animate it, bring it to life because, you know, we're using JavaScript. We're creating a dynamic thing that lives in a web browser, and we have available to us the tools to at least bring it to life visually, a little bit more, rather than just load this thing and have it be a static graphic weaken. Just give a little bit of eye candy, which is actually a very important thing. You know, aesthetics matter in communications, and that's what this is. This is communications. And so, if you could make it beautiful and engaging an animation is great way to do that, we might as well do it. So I'm just gonna go to the code over here. And the first thing I'm gonna do is you know, we created these circles. We gave the circles attributes like their X and y position there, radius, size, fill, color, rapacity, etcetera. And so what I'm gonna do first is I'm gonna change the radius of these circles. I'm just gonna delete the function. I'm actually gonna cut it using, you know, command X on the Mac control Exxon PC so I can paste it later on. And I'm just gonna change it manually, Back to a zero. Something hit, save and refresh and load it. And what do we see? What we see? Nothing, Right? Because all of the circles which, by the way, are still there. So if I go into the CO, the elements here and open up perhaps the chart and the SPG, we still have circles. They still have X and y attributes. And there's still positioned exactly where they're supposed to be on the screen, as you can see as I roll over these, but they all have a radius of zero. And so they're objects that have no width and height, so they're essentially invisible. But they're there. All right, so they still exist. They're still on the screen, They just don't have any visibility. And we're gonna change that in animation. So the way to do that is this two quick things First thing I'm gonna do is I'm gonna add a function call down here. So once once my script is done, I have, you know, created my SPG object Sets of variables create the SPG object. Read the data, sorted it set up my scale stuff, added the circles out of the axis lines. And now I'm gonna say, Please do run an update. And this This is a function that I'm gonna create called update. I could call this thing. Whatever I wanted, I was gonna call it update and then create a new function down here and you'll notice that it is outside of this function that we've been working on above. Remember these these curly braces that ended the function that started with D three dot CS fee, Which brings to the forefront here a very similar idea to variable scope. Essentially, functions have scope to. And so if I were toe write the code to run whatever I want to have happen in this update, the animation inside of this function, like where the rest of this stuff is, then I wouldn't have access to it outside that function. Now, in this lesson that I'm teaching on d three, we're not going to do anything with that, But it's a good best practice to put your updates, stuff outside of that data call function because then later on like, say, I had a button on the page. I want to click that button that maybe loads new data or changes things that I want to reanimate stuff. If it's outside of that original function, then I have access to it when I do things like click on buttons. So it's just a good best practice to do it this way. So I'm gonna call a function called Update, and then I have to create that function. And this is the syntax to do that. And now that function is going to consist of the code to make animation happen. And so, like I just said, you know, we have his object called circles, which holds our circles that we created and bound to data and added attributes to so what I can do. This update function is referred to that object. That's why we added that variable name, that object name. It's one minute call is I'm gonna say just circles dot transition And this is just another great method. Build into D three that allows you to create animations happen. You want a transition things on the stage and make stuff happen. And so what I want to make happen is, you know, I changed my radius to zero. And so I want to animate the radius over time. And so the way to do that is to say, circled transition dot attribute Because what I want a transition is the attributes itself . And so I want to transition the are attribute the radius go back in here and paste in that function that I copied out earlier, and so literally I'm saying take my circles animate the are attributes and animated to this value that we used earlier. All right, so I'm gonna save and I'm a hit refresh and watch what happens. They all animated onto onto the stage, and it happens very quickly because the default speed the animation is fairly fast. Um and so I was gonna load it again. Just you can see it one more time. It's the animate on. It's okay. It's better than not animating, I guess. But it is really fast. And so instead of just animating them all at once, what I want to do is have them delay and I'm just going to show the syntax for delaying things and just show you one quick thing. So before you do the attributes change, you want to tell it to make the delay happen. And so let's say I went in here and I said, Just delay 1000 milliseconds and the delay. The value is always in milliseconds, so 1000 milliseconds is one second. So if I hit save, I hit Refresh. What's gonna happen, is it? We're gonna see a Blakes blank screen for a second, and then I still animate on very, very quickly, so blank and then animate. So that's OK. That's at least I can see that they're animating on separately from the axes. It's already slightly better than it was. But what I really want to do is I wanna have each dot animate on individually one by one in the order in which they appear on the on the stage on the screen. So the way to do that as I can also once again change this delay into a function. And so what I'm gonna do is I'm gonna say function, maybe something a little bit different here. In addition to passing in the data value itself, what you can do in any function like we've done many times where we pass in the bound data and then we can refer to the field names to do stuff with it. You can also, in any one of these functions, also refer to the index number of whatever is being passed through. And so what does that mean? I've talked about indices before where, you know, I created a ray called X Men Max, and it was a, you know, an array with two items in it. So the first item is that index position zero, and the second item is an index position one. So just the order in which these things are are stored in these functions where have bound data, which has 506 elements in it? When I say do stuff and do stuff based on the index value, which is always the second parameter available to you in these rays, essentially, it means that it's gonna be looping through those 506 values. And I have access to that number 12345 all over after 506. So, in fact, if I console doubt, log that I now now that I've referred to it. Yeah, I didn't refer to it down here, but I could do the same thing in any one of these functions. But I refer to it here. So therefore, I can access it here. Consul, dialogue it hit, refresh and watch what happens? It writes him out. See, all of those numbers are just written out because I have access to all those numbers all the way from 0 to 505 right? Not five or six. Good starts at zero. And so what I'm gonna do now isn't say Okay. Instead of delaying 1000 milliseconds, I want to delay. And again, I have to use that return word. I want to delay exactly that number. So the first circle that appears is gonna delay zero milliseconds. It's not gonna delay at all because it's zero index, the 2nd 1 which is that the one index is gonna delay one millisecond. The third one's going to lay to milliseconds. And a five run in the 6th 1 is going to lay 505 milliseconds just over half a second. So if I refresh my screen, you're going to see them animate on one by one pretty quickly. It looks pretty sweet at this point, but it's little too fast. I'm just gonna now, just manually, you know, Let's say multiply it by 10 and now it's going to slow down. So the 506th dot is going to be delayed 5000 and 60 milliseconds. So just over five seconds. And so this whole animations gonna take five seconds. And now it looks really elegant and nice and clean and simple. And I can sort of see how it builds across the entire data set. It just looks beautiful. It's really a nice way of looking at things. So one other thing worth noting is that transitions, you know, animations and D three can really happen on, you know, just about anything. Right? So here I am, you know, causing a transition to occur. I'm delaying it. And then the thing I'm actually transitioning is the are attributes, right, The radius of the circles. If I wanted to, I could change, you know, enemy. Any of the other attributes I've set the exposition, the Y position, the fill color, the capacity, etcetera. And so you know, for instance, What if I change the X value to zero by default and then transition the X value to be this thing? What would happen is all the dots would start over here and slide into place, right? Or if I transition the opacity and not PR value Instead of the dots being tiny and getting bigger from of invisible Teoh zero radius to a bigger radius, they would just be invisible and gets slightly more opaque. Aziz, the capacity feels in so you can animate anything. It's really great. And D three makes it pretty easy to do it. So this thing is really coming together nicely. All I have to do now is add a little bit of interactivity and what I'm gonna do in the next lesson is show how to add a very simple rollover effect. 8. Interactivity in D3: All right. So our scatter plot looks great. It's animating. All we want to do now is add some interactivity just to show you how that works. And so what I'm gonna do, Simon and a hover event, a tool tip to show the data associated with dots or something really simple. And the first thing you need to do is actually create a div, which is essentially gonna contain my tool tip elements. And some was gonna create a div. And I'm gonna give an idea of tool tips so I can refer to it later. And while I'm at it, I might as well add Thesis es s class, which, because I want to make sure that the thing looks the way I wanted to look right. So I'm gonna create a tip, rather a CSS class. Just for that I d tool tip for salmon do is I'm gonna say position Absolute. So for those of you who know CSS, absolute positioning just means that wherever I decide to tell Javascript to put this div, it's gonna be placed in an absolute position, meaning relative to the top left hand corner of the entire browser, not sort of within the parameters of something that it sits inside of just makes it easier to manage exact positioning. I'm gonna give it a background color of white, and I'm gonna add a little bit of padding. Um, I think all the way around actually, just 20 pixels of padding. This just so when I add content into the tool tip, you know, text and whatever else I put in there, it's not squished all the way to the edges of that Div. I'm gonna give it a border. Um, and I think I'm just gonna do, like, a solid one pixel black border for now, we're not I'm not really designing this. I'm just sort of making it visible so we can see the edges so we can sort of judge it in terms of success that it is working. So let me just hit save on this. I'm gonna go refresh the page and what's gonna happen this and let me close at my inspector here. There's my tool tip, right? It's stuck over here because it's a day of that comes after this device, just sort of sitting down here at the bottom. Haven't told her to live anywhere. It's visible, even though it has no content in it because of the padding on. Of course, that's great. It exists. But now I need to do stuff with it. And so first time to do is I'm actually an ad into the class that it has zero opacity is enough. I refresh its invisible. It's still there. But it's invisible because I only want that to become visible. When I roll over a dot and when I add content to it right, that kind of makes sense. Okay, so I wanted to come to life when I roll over dot How am I gonna do that? Well, let's go to our circles are dots and, you know, we have these chained events. First, I selected all things with the class. I made it action, you know, sort of stuff happened based on data. The stuff I made to do was a pen circles and the circles have attributes once ever added all these attributes. There are other things I can do, such as adding mouse over dot on mouse over event. And so, if you use Jake weary, you're familiar with this concept dot on mouse over dot on mouse moved out on mouse out is how it's referred to in D three. So if I say dot on mouse over and I use a function, then what I can do is I'm telling it to do stuff when I mouse over it, as you would expect. So what I'm gonna do here is I was just going to start off pretty simple here and you'll notice that I'm passing in the bound data, by the way, right. So I'm just gonna say this, I'm gonna create a variable. I'm gonna call html. I'm gonna say html equals d dot poor. So I'm literally just saying, put that poor percentage of poor people in this housing district into this variable and then I'm gonna say I need to sort of decide where I want the tool tip to be on the screen. Actually, before I do that, let's just do this HTML equals d that poor. And then all I have to say is, um d three select that tool tip div that we created and give it HTML, which is dot html. In this case, I'm passing the variable name age to once again. I could call this a variable name? Anything I want did info. Right now, as long as I say html about a she male info, it's gonna work. But I'm just using a simple variable called HTML. Hopefully, that's not confusing. So I've assigned the variable. I'm selecting the tool tip. I'm saying Put that html into it as HTML. And so now if I refresh the page again, it's not visible. But if I go back up to my class and comment out this line now, it's gonna be visible right now you can see those numbers changing as I roll over different dots, right? So let me make that a passage easier again because the next thing I'm gonna dio is actually place and make visible this tool tip after I add stuff to it. So I've added my ht male. It's invisible cause I've made it invisible again. So the next thing I want to do is I want to say, Let's set the style whips for this tool tip div. And when I want to do is first of all, make the left position to, let's say, just 100 pixels. Okay? From the left hand edge, I'm also gonna set this style. I'm say, put it 100 pixels from the top. Just sort of mainly setting these numbers to start, and I have to make it visible. So I have to add the style opacity, and I'm gonna sit that to I'm not gonna do one. I'm gonna make it sort of slightly translucent so you can see the dots behind it. But mostly, you know, mostly more opaque of in translucent save. Go back hit, Refresh. So my tool tip is invisible because I'm not rolled over anything. As soon as I am mass over something, it becomes visible and it's over there. Exactly 100 pixels from this corner, 100 over and 100 damn left top, Right. As I roll over the different ones, you can see that the size of it sort of changes based on having the number is how many decimal points there are etcetera. So that's goods. Good start. But the next thing I want to do is I'm gonna actually make this placement more dynamic. Um, I'm not gonna do this perfectly, but I'll show you what I'm doing and then you can always adjust it yourself. later on, rather than just manually saying Place it 100 pixels from the left, which is kind of odd, like, Why would I want put it there? I actually haven't followed my mouse. I really wanted to be exactly where wherever I roll over the dot I want the tool tip to appear there. So D three has built into it. D three dot events dot page x. So let me just say that hit refresh. Now what it's gonna do is going to say D three tell me where the mouse is right now in terms of its exposition and put the tool tip right there. And so there it ISS. Now you'll notice that it's aligned to the left hand edge of the tool tip. It's not centered over with my dot of my mouse, rather, so I have to actually do that manually so I could say D three day event out of Page X. I'm just gonna mainly say Maybe, maybe that's 200 pixels wide. I don't know something. Subtract 100 so manually doing it again. Not the best way to do it. But it's fine for now. And so now it's a little bit too far to the left. But as I might add, more content that May center better. So I'm not gonna worry about that right now. I just want to get it sorted generally in the right position, ish for the moment. So I wondered the same thing for the why positioning. And so I'm gonna say D three dot event that page, Why I'm gonna save minus 100 right now. Once again, refresh. And now it's following my mess up and down, right all the way around, not perfectly positioned, but again, I can tweet that later on. So that's great. We're making good progress here. The one thing you'll notice, though, is that even though this is doing what I wanted to do, the one thing it's not doing is once I move away, it's not disappearing. So that's weird. That's no good. I gotta fix that, too. So as you can imagine, if you have done any programming with Hickory before, I also have to add a dot on mouse out event passed in function, and in this case I don't even need to bind the data. I mean, I don't need to pass that bound data to dysfunction Islam. It is just to say, Hey, select that tool tip and hide it for me. So d three does select the tool tip Div and let's set the style And I'm just going to something really simple. I'm just gonna say, move it 1000 pixels to the left, Negative 1000 right off the screen and while I'm at it But I don't really need to do both, but I'm gonna I don't know why. Let's set the capacity back to zero to And so if I just do that had saved hit refresh. Now it follows my mouse and its active as soon as the dots available on the screen, even while its animating right. And once I move off, it disappears. So now I have a functioning tool tip, really doing pretty much what I wanted to do. But I think I want to add more content to the tool tip. This is functionally enough, but I just want to show one of the concept here. You don't have to just pass in a value you know we can do string concatenation member. We talked about that earlier. What if I wanted to sort of give you more information in the tool tip. Well, one thing I could do is I could say, OK, HTML equals text first. I want you know, this is the X value. So I was going to say X, I'm gonna tell you that this is the pore, um, field. And so that's great. So now if I hit refresh Now you can look, think I broke something. Oh, I forgot to add the plus science, See that I forgot to can Can't make those strains another great, uh, code debugging thing where you've done something Everything that breaks and things like forgetting plus signs in between is a classic example of a mistake you'll make. So now I see that full string that both of things contaminated together sort of put together, and I might as well give you all of the field values. Right? We have Ford. Everything's going on here. I have the X, the why the radius of the circle and also the color, right? So let me change all these. I'm assuring you the why the are and the color and the why is the lips Crooms field. So let's put that over here, the R is the median value of each property, and then the color is based on that Charles River field. So if I do this, though, if I don't make a quick change what you'll notice I'm saying HTML equals this. And then I'm saying HTML equals that. So I'm essentially resetting the extra mile variable each time here. That's no good. What I need to do is actually do plus equals for these subsequent ones. And so if you're not familiar with this shorthand, I'm saying HTML equals something for this first row and I'm saying, Now add this, then add this and then add this to it. So I'm just adding to it along the way. So now if I say even hit refresh now all the information is in there, but it's all in the same lines. I haven't added line breaks or done any other styling, not the best way to do it, but one simple way to do it. I can literally just mainly add line breaks. There are other ways to do this, but I was gonna do the fast and easy way here for now, so I'm gonna add line breaks to the 1st 3 I don't need it for the last one hit Refresh, and now I have all of my information in there and it's flashing and blinking because it's essentially behind my mouse, which is over a dot. But as soon as it appears now, I'm mouse out on that dot that I'm over. So I need to mainly change that y position. I'm just gonna say, minus 1 50 for now and see if that gets it out of the way. So that's great. It's, you know, it's fine for now to hard code these values. It's worth noting that the right way to do this in the way I would normally do this and you should do this is, rather than manually saying, minus 100 minus 1 50 For these two things, you can instead detect the with of that Div after you've added the HTML to it and then say event type Ajax, minus that dibs with divided by two right, you want to subtract half the with because you want to be centered on your mouse and same thing for the height. Detect the height once you've added the extreme el to it and then say Subtract the height and then maybe a few extra pixels. So you want that That square sort of slid the tilted slightly above your mouse just quick and easy ways to do it. You know there are other ways, but that that's a pretty quick and effective and accurate way of doing it. This is good. So we have tool tips there following the mouse. That doing, you know, pretty much what I want him to do is certainly a lot of work to be done in terms of styling and making look beautiful on making things a little bit more dynamic. But it works well enough for our purposes today, so we're pretty much done, except as one minor thing that's bothering me about this bubble chart that we've been working on, and I'm gonna fix that in our next and final lesson. 9. D3 - One More Thing: So we've done everything that we set out to do with our scatter plot. Everything is working great. It's coming to life. It's animating all those things. But there's one thing about this scatter plot that's been bugging me since the moment that we began creating it. Um, if you remember earlier we had a problem where I flipped the whole thing vertically, right? Because I wanted, um, these guys up here versus down here because it was weird to have, um, high value, live at the bottom, right in low value, live at the tops. We flipped it vertically. Remember that I have a similar issue with our horizontal scale because what I have here is a low number meaning a low percentage of poor people in a high number, a high percentage of poor people. But pour nous is about a lack of something. And so if I am, if I have more poor people in a district, I have less valuable homes, smaller dots and fewer rooms right where were at the bottom of this scale on the Y axis, and so that just it just feels wrong. In fact, it's a known thing. Research proven people expect high values to be at the at the top, which is what we did earlier were reflected vertically but also sort of up into the right. Um, so a we do have a high value, ah, high percentage of poor people. But it's people with less wealth over here, and so it just feels wrong. And so what I want to do is I want to flip our X axis just like we flip r y axis earlier. And so it's the exact same process that we followed earlier, where we, instead of having our Wyman max lower value, higher value, you know, lower value aside, associated with the low why which is at the top, we literally just sweat with swap them. So the maximum is now here and the minimum is over here. Where do the exact same thing? I'm gonna say, Use the maximum value on the left and the minimum value on the right. So now if I just hit save hit, refresh bone now it's flipped around. And so, as a chart reader, this feels more natural to me that high wealth, which means less pour nous but high wealth is up here in the upper right hand corner. Now I have a similar a related problem where I have a high number on the left in a low number on the right. Now that's technically correct, because those are the numbers. We're measuring the percentage of poor people, but it's still just sort of feels wrong. And so what I want to do is get rid of those numbers and manually put in different labels. It'll just make more sense to the chart reader. And so, if you remember earlier when we created our axes, we manually set the tick values we said use the lowest one and the highest number, highest one, and that works great. That's a really good way of doing it for a lot of charts. But instead of doing that using the built in tick values function, I'm gonna go back and set the ticks. If you remember into this when I first showed you the Axis, I was gonna say, You know what? You zero ticks don't don't put to any ticks in there. And so if I hit refresh my labels disappear, so I have to mainly now put them in myself. So the quick and easy way to do that is I'm just gonna manually add text. I'm gonna put it here after I have created my axes before I call my update. I'm just going to say you know what? Let's add text to our SPG. I'm not going to use a variable name. I'm not going to do this in exactly the most perfect way ever. But just very quickly, let's add some text and I need that text to live on the X axis. I'm gonna use this scale cause I wanted to be placed exactly where I want it. I want you to first put this text this this first piece of text at the X um uh, expedition using the x scale that we set up earlier. And I want to use that X men Max variable and I want to put the minimum value in their first. So the exposition is at this scale for that minimum number, and then I'm gonna say for the white opposition, let's also use, uh, let's say the same thing. I'm gonna use the y scale and I'm used. The why Min Max and I mosque in use the minimum value because now don't forget we are our lowest wise or at the bottom of our chart, which is where I want this tick to exist. And then I tell you have to tell it what the text should read. And the way you do that is here. You know, if you add a text element that up in text, you actually say dot text equals whatever or dot text, parentheses, whatever. And so I'm gonna say for the minimum value, which is the low percentage of poor people, I'm gonna call that more wealthy because that's really what we're looking at here. So if I go back and hit refresh, I now have the words more wealthy over here cause that's what this is. It's more wealth, Les pour nous, and that makes more sense just to our audience. But of course I have a couple problems. First of all, the text is a lining up perfectly with this position over here, but it's aligning to the left hand edge of the text and running off the screen. So what I want to do is center it and also make that look more like label the way I'd recommend which is smaller grey Less contrast e simpler, etcetera. So I'm gonna do that in a couple different ways. First I'm gonna fix is the positioning. So I wanted to be centered and D three has built into it. Well, SPG really has built into it. So therefore, d three also does the text anchor AC tribute. And so I can set the anchoring of that text to either this the start, the middle or the end. And so if I say that's it said to start which it is by default, it means that left line into that position I've chosen. If I say end ital right a lot and by saying middle, it'll center line. So if I refresh now, it's center aligned, so that's good. That's a good start. But now I want to change the formatting of this text. And then after that, I'm gonna move it vertically as well, because I don't know why. It's what I do know why. But it's sitting up here, whereas I wanted to be down here. But first, let's do the actual look and feel, so I'm gonna add a class and we've done this before. I'm gonna say attribute, class and I'm just gonna call this class access label. And now, if I go back up and add the CSS class for access label on, I'll put it next to these guys. So it's easy to find Later on, I'm gonna do that same light, grey fill color. And I want to use a font of a nice on Sarah Font. I'm gonna say fun size of 10 pixels. I wanted to be nice and small, you know, Ideally, I want to sort of look like this guy over here, and so that's pretty good. Pretty close. Good enough for now. I'm not gonna tweak it crazily for this lesson, but I do want to fix the fact that it's stuck up here, right? It's perfectly lined with the bottom of our scale, which is where this guy is positioned, right? The lowest value lives exactly there, which is why it's up here. So you know, there's a few different ways to do that. One simple, quick and easy way is, rather than saying it, put it in the Y position exactly at the bottom, the minimum value Do that. Plus, let's say our margin right, because that's gonna push it down. Remember, we shoved everything in 30 pixels. If I shove it back out 30 pixels, maybe it'll be exactly where I wanted to be. And lo and behold it ISS. Now, sometimes you have to tweet that a little bit. Sometimes it should not perfectly exactly where you want it at a couple pixels if you need to. But you know, that works just fine. And I want to do the same thing. But for the left Most label. So I'm just gonna duplicate it, right? A pen text. Now, the ex positioning is going to be based on the maximum value, which in this case, is the less wealthy, right? I wanted to be in the same way position. I still wanted to be center aligned and use that same class. But in this case, the label is less wealthy, safe, refresh. And now it is exactly how I wanted to be. So I hope that this course on D three has been helpful and interesting. Really. We've just been setting up some foundational skills, you know, it's gonna be relatively straightforward now for you, hopefully to go in and look up d three syntax and add more skills and features two projects that you're working on. You know, if you worked with Jake, Jake Weary or other jobs complain just in the past, a lot of this probably was even easier for you to learn. If not, you know, you've learned a lot of key things here, which you'll be able to replicate and and apply to new learnings as you go forward with D three. What I definitely recommend is check out d three Js dot org's the d three website. Go to the examples page and you will find endless examples of great D three projects where you'll be able to see source code and play with it. Some concepts and the fear more complex and others to be sure. But this should be a good starting point for you, Mike, I said, I really hope you enjoyed the course. Of course, I hope you learned a lot and I wish you happy. D three ng going forward