1 00:00:00,000 --> 00:00:00,726 2 00:00:00,726 --> 00:00:01,900 ATHENA BRAUN: Hey, everyone. 3 00:00:01,900 --> 00:00:03,400 Thanks so much for coming out today. 4 00:00:03,400 --> 00:00:07,360 I'm going to walk you guys through a quick exercise with D3. 5 00:00:07,360 --> 00:00:10,300 D3 is a JavaScript library, so it isn't a language itself. 6 00:00:10,300 --> 00:00:12,430 It's actually using native JavaScript. 7 00:00:12,430 --> 00:00:14,830 It was all built by one human being. 8 00:00:14,830 --> 00:00:17,930 He's a very cool guy who was really good at this. 9 00:00:17,930 --> 00:00:20,380 And his whole idea was that he wanted to put together 10 00:00:20,380 --> 00:00:23,830 a library that would, in relatively few lines of code, 11 00:00:23,830 --> 00:00:27,670 give you the ability to make really interesting, interactive, 12 00:00:27,670 --> 00:00:30,920 and adaptable data visualizations. 13 00:00:30,920 --> 00:00:34,000 So a lot of what we're going to be dealing with today 14 00:00:34,000 --> 00:00:37,420 is what it's like to load in data, what it's 15 00:00:37,420 --> 00:00:40,730 like to do that synchronicity versus asynchronously. 16 00:00:40,730 --> 00:00:46,840 And then we're going to build a pretty simple bar graph here where we're 17 00:00:46,840 --> 00:00:48,580 going to have some clicking capability. 18 00:00:48,580 --> 00:00:50,740 And all of this is being generated dynamically. 19 00:00:50,740 --> 00:00:52,698 So I'm going to step you guys through the code. 20 00:00:52,698 --> 00:00:54,550 So you have an idea of what this looks like. 21 00:00:54,550 --> 00:00:56,320 Feel free to stop me at any point. 22 00:00:56,320 --> 00:00:59,110 But a few things that I do want to mention right off 23 00:00:59,110 --> 00:01:02,080 the bat is that in order to get any of this to work 24 00:01:02,080 --> 00:01:04,700 you are going to need a web server up and running. 25 00:01:04,700 --> 00:01:06,127 So just keep that in mind. 26 00:01:06,127 --> 00:01:07,960 The whole reason that any of this is running 27 00:01:07,960 --> 00:01:09,970 is because I have a terminal window here where 28 00:01:09,970 --> 00:01:13,000 I've already like typed in HTTP server. 29 00:01:13,000 --> 00:01:14,980 And this is all running. 30 00:01:14,980 --> 00:01:18,400 Good to go before I start looking at code? 31 00:01:18,400 --> 00:01:19,540 Awesome. 32 00:01:19,540 --> 00:01:20,260 Great. 33 00:01:20,260 --> 00:01:24,910 So first thing first, is we're going to talk about index.html. 34 00:01:24,910 --> 00:01:27,480 You don't have to do this in an index.html. 35 00:01:27,480 --> 00:01:30,220 Since this is a pretty simple website with only one page, 36 00:01:30,220 --> 00:01:31,767 I decided to put it in index. 37 00:01:31,767 --> 00:01:33,850 But you could, of course, have data visualizations 38 00:01:33,850 --> 00:01:36,740 on any of your website pages. 39 00:01:36,740 --> 00:01:39,790 So we're going to have some typical boilerplate code here where 40 00:01:39,790 --> 00:01:43,930 we see things like the metal char set, the meta names, the title. 41 00:01:43,930 --> 00:01:48,160 And then immediately, I start including things like Bootstrap CSS, which 42 00:01:48,160 --> 00:01:50,290 I use a little bit of. 43 00:01:50,290 --> 00:01:53,860 Here, I've made an API call to Google to get some fancy fonts. 44 00:01:53,860 --> 00:01:56,140 This is absolutely not D3 related. 45 00:01:56,140 --> 00:01:58,850 And then I've included some of my own style sheets. 46 00:01:58,850 --> 00:02:00,845 These are normal things you can do. 47 00:02:00,845 --> 00:02:01,720 You don't have to do. 48 00:02:01,720 --> 00:02:04,750 Have absolutely nothing to do with D3 itself. 49 00:02:04,750 --> 00:02:06,660 It's more the stuff that we do in the body 50 00:02:06,660 --> 00:02:09,520 and that we include at the bottom of the body that is actually 51 00:02:09,520 --> 00:02:13,870 D3 specific where, even here, I've just sort of configured the page so 52 00:02:13,870 --> 00:02:15,790 that I have a div for my header. 53 00:02:15,790 --> 00:02:18,100 And then I have a div where most of my visualizations 54 00:02:18,100 --> 00:02:21,950 and most of the interesting components of this page are going to exist. 55 00:02:21,950 --> 00:02:23,750 So let's talk about that a little bit. 56 00:02:23,750 --> 00:02:28,550 I'm using the Bootstrap container class here, 57 00:02:28,550 --> 00:02:32,960 which basically lets me resize as I would like to. 58 00:02:32,960 --> 00:02:36,670 So if you ever like click and drag the web page, 59 00:02:36,670 --> 00:02:38,980 your data visualizations will resize accordingly. 60 00:02:38,980 --> 00:02:41,770 So you don't end up with things that are like awkwardly cut off 61 00:02:41,770 --> 00:02:43,540 or that start to look a little bit weird. 62 00:02:43,540 --> 00:02:47,230 This is more of an aesthetic choice, as opposed to a functional choice, 63 00:02:47,230 --> 00:02:49,990 but it ends up being a nice way to do this. 64 00:02:49,990 --> 00:02:53,110 And when you're using anything within the container, 65 00:02:53,110 --> 00:02:55,210 the next class that you have to have is row. 66 00:02:55,210 --> 00:02:57,376 If you're ever interested in looking any of this up, 67 00:02:57,376 --> 00:03:00,130 you can Google bootstrap grid layout, and you'll immediately 68 00:03:00,130 --> 00:03:03,310 get documentation for this. 69 00:03:03,310 --> 00:03:05,620 And what's important to know about the grid layout 70 00:03:05,620 --> 00:03:10,000 is that the web page is split into 12 columns. 71 00:03:10,000 --> 00:03:15,010 So you'll see here that I actually have two divs, each taking up six columns. 72 00:03:15,010 --> 00:03:18,070 This is really just so that I could get a nice effect of splitting 73 00:03:18,070 --> 00:03:21,550 the page in half between the data visualization itself 74 00:03:21,550 --> 00:03:24,050 and any of the information that I was going to show. 75 00:03:24,050 --> 00:03:26,050 You could absolutely configure this differently. 76 00:03:26,050 --> 00:03:29,830 You could have your data visualization take up the entire width of the screen. 77 00:03:29,830 --> 00:03:32,960 You could have it take up considerably less of the screen. 78 00:03:32,960 --> 00:03:35,830 But for my purposes, this is what I wanted to do. 79 00:03:35,830 --> 00:03:38,380 And what I really want to point out is that I 80 00:03:38,380 --> 00:03:41,770 have made very judicious use of IDs here, 81 00:03:41,770 --> 00:03:45,250 where within D3 we're going to have the capability to, 82 00:03:45,250 --> 00:03:49,870 similar to native JavaScript, actually select components out of the DOM, 83 00:03:49,870 --> 00:03:51,520 out of the document object model. 84 00:03:51,520 --> 00:03:54,850 And the easiest way to do that is in fact to do it by ID. 85 00:03:54,850 --> 00:03:57,280 So get very accustomed to using IDs. 86 00:03:57,280 --> 00:03:59,710 And try to keep in mind that the IDs that you use 87 00:03:59,710 --> 00:04:03,040 should be descriptive enough that, you know, you either don't forget them, 88 00:04:03,040 --> 00:04:05,230 or when you're actually writing your JavaScript it's 89 00:04:05,230 --> 00:04:10,760 easy enough to know what you're actually referring to within the HTML itself. 90 00:04:10,760 --> 00:04:14,131 So you'll notice here I actually have two columns that are happening. 91 00:04:14,131 --> 00:04:16,839 One where I've said, OK, I'm going to actually display the chart. 92 00:04:16,839 --> 00:04:19,370 And one where I'm going to display the information. 93 00:04:19,370 --> 00:04:22,286 And within the information, I've said, OK, I'm going to have a header. 94 00:04:22,286 --> 00:04:25,180 And then I have this other div that I've said is going to be albums. 95 00:04:25,180 --> 00:04:29,770 The other really important thing here that is now actually D3 specific 96 00:04:29,770 --> 00:04:33,340 is that I need to be sure to include the D3 JavaScript library. 97 00:04:33,340 --> 00:04:38,140 If I don't include this, we literally aren't working with D3 at this point. 98 00:04:38,140 --> 00:04:42,580 In order to find this file, you can literally just Google D3 JavaScript. 99 00:04:42,580 --> 00:04:46,720 And you will find a link in order to include it in a script tag. 100 00:04:46,720 --> 00:04:49,330 I always highly recommend, whenever you can, 101 00:04:49,330 --> 00:04:53,080 following that link that you would otherwise just include 102 00:04:53,080 --> 00:04:56,920 and actually copying and pasting all of that source code into a file. 103 00:04:56,920 --> 00:04:59,170 Because that way you never have to deal with latency 104 00:04:59,170 --> 00:05:03,660 if your connection is slow, and now your JavaScript libraries aren't running. 105 00:05:03,660 --> 00:05:07,940 So in fact, this file exists natively within my directory 106 00:05:07,940 --> 00:05:13,040 here so that I don't have to deal with any of these issues of poor connection, 107 00:05:13,040 --> 00:05:15,450 and now my visualizations aren't running. 108 00:05:15,450 --> 00:05:18,377 And you know, of course, I have my Bootstrap JS. 109 00:05:18,377 --> 00:05:20,960 I'm going to use a little bit of jQuery, which I think you all 110 00:05:20,960 --> 00:05:24,290 saw in one of the most recent P sets. 111 00:05:24,290 --> 00:05:27,110 I'll point it out, but it's really a very small use. 112 00:05:27,110 --> 00:05:29,720 And then, finally, I'm going to use Q, which 113 00:05:29,720 --> 00:05:31,490 is just another JavaScript library. 114 00:05:31,490 --> 00:05:36,350 And the whole purpose of this is to make sure that my data gets loaded properly. 115 00:05:36,350 --> 00:05:39,980 So having looked now at the JavaScript itself, 116 00:05:39,980 --> 00:05:42,330 I've also included one more JavaScript file, 117 00:05:42,330 --> 00:05:44,254 which is the file that I've actually written 118 00:05:44,254 --> 00:05:46,670 and where any of the logic that I have done for my project 119 00:05:46,670 --> 00:05:47,912 will actually exist. 120 00:05:47,912 --> 00:05:50,370 For your projects, they might be a little more complicated, 121 00:05:50,370 --> 00:05:53,150 where, in fact, you might have several JavaScript files that 122 00:05:53,150 --> 00:05:55,010 are all interacting with each other. 123 00:05:55,010 --> 00:05:58,220 Always be sure that you're including your JavaScript files. 124 00:05:58,220 --> 00:06:00,950 It's one of my favorite debugging stories where I'm like, well, 125 00:06:00,950 --> 00:06:02,390 I've written all of this code. 126 00:06:02,390 --> 00:06:03,244 Nothing is working. 127 00:06:03,244 --> 00:06:04,160 Nothing is showing up. 128 00:06:04,160 --> 00:06:05,190 Why isn't it showing up? 129 00:06:05,190 --> 00:06:07,530 And it's because I've forgotten to include the file. 130 00:06:07,530 --> 00:06:09,946 So it's always good to keep this mental checklist of like, 131 00:06:09,946 --> 00:06:12,740 have I included the files that I need to include. 132 00:06:12,740 --> 00:06:18,070 So if we hop over to main.js, the first thing I really want to talk about 133 00:06:18,070 --> 00:06:24,190 is this idea of asynchronous JavaScript loading where, in fact, I'm 134 00:06:24,190 --> 00:06:28,890 going to be loading data sets that, again, exist natively on my computer. 135 00:06:28,890 --> 00:06:33,760 And just to give you guys a quick idea of what those look like-- 136 00:06:33,760 --> 00:06:39,205 oh, goodness, well here we can actually open them up over here. 137 00:06:39,205 --> 00:06:45,874 138 00:06:45,874 --> 00:06:47,540 So you'll see I have two data sets here. 139 00:06:47,540 --> 00:06:52,450 I'm just going to go ahead and open the artists data set. 140 00:06:52,450 --> 00:06:57,910 So all of this data is coming out of the SQL lecture. 141 00:06:57,910 --> 00:07:00,010 So some of it should look vaguely familiar. 142 00:07:00,010 --> 00:07:02,590 Because it came out of the SQL lecture, I actually ended up 143 00:07:02,590 --> 00:07:04,840 having to treat my data a little bit differently 144 00:07:04,840 --> 00:07:06,656 to make things line up properly. 145 00:07:06,656 --> 00:07:08,530 You'll remember that in the SQL lecture David 146 00:07:08,530 --> 00:07:12,350 was talking about ways to make your database more efficient. 147 00:07:12,350 --> 00:07:15,580 And as a result, rather than store an artist's name, 148 00:07:15,580 --> 00:07:19,090 he would instead just store an integer representing an artist ID, which 149 00:07:19,090 --> 00:07:20,757 is a perfectly valid way to do this. 150 00:07:20,757 --> 00:07:22,840 And it was actually a very good opportunity for me 151 00:07:22,840 --> 00:07:24,610 to show you guys how to use multiple data 152 00:07:24,610 --> 00:07:27,601 sets that actually perhaps interact with each other. 153 00:07:27,601 --> 00:07:29,350 But this is just one of the two data sets. 154 00:07:29,350 --> 00:07:32,230 You'll notice that I've saved it in a CSV format. 155 00:07:32,230 --> 00:07:35,050 This was out of convenience more than anything. 156 00:07:35,050 --> 00:07:38,590 You could absolutely save it as a tab separated 157 00:07:38,590 --> 00:07:42,340 values, which is similar to a CSV, but uses tabs as delimiters. 158 00:07:42,340 --> 00:07:44,320 Just be consistent with what you're using. 159 00:07:44,320 --> 00:07:49,120 And keep in mind that whatever type you use to save your data 160 00:07:49,120 --> 00:07:51,640 is going to correspond directly to the methods 161 00:07:51,640 --> 00:07:54,699 that you're going to be using to actually load that data. 162 00:07:54,699 --> 00:07:56,740 So if we look at this step here, this is probably 163 00:07:56,740 --> 00:07:59,950 one of the most important steps that we're going to have. 164 00:07:59,950 --> 00:08:03,730 Where, in essence, I've said, OK, for each one of these data sets, 165 00:08:03,730 --> 00:08:07,150 I want you to call D3.CSV on it. 166 00:08:07,150 --> 00:08:10,780 What D3.CSV actually does is it calls the method that 167 00:08:10,780 --> 00:08:17,560 literally reads in your CSV and saves it as an array of JavaScript objects. 168 00:08:17,560 --> 00:08:22,750 Where each one of the objects-- and I'll show this to you in the Developer Tools 169 00:08:22,750 --> 00:08:24,010 in Chrome in a second-- 170 00:08:24,010 --> 00:08:26,830 but each one of the objects is going to have a key that 171 00:08:26,830 --> 00:08:29,770 is artist ID and a key that is artist. 172 00:08:29,770 --> 00:08:31,930 And so each one of these lines here is going 173 00:08:31,930 --> 00:08:34,280 to turn into its own JavaScript object. 174 00:08:34,280 --> 00:08:38,919 So that's kind of the direct mapping that's happening there. 175 00:08:38,919 --> 00:08:41,700 So I've said, OK, for each data set, please load it in. 176 00:08:41,700 --> 00:08:44,620 And it's kind of this defer that is most interesting where we've 177 00:08:44,620 --> 00:08:48,520 said once you load this one in, wait to do anything else, 178 00:08:48,520 --> 00:08:50,920 but please also load in the next one. 179 00:08:50,920 --> 00:08:53,800 And finally, this await line is the most important 180 00:08:53,800 --> 00:08:57,520 where we've said, OK, once both of these defer statements are done, 181 00:08:57,520 --> 00:09:00,580 meaning once you've loaded in both of those data sets, now 182 00:09:00,580 --> 00:09:03,080 please call this other function. 183 00:09:03,080 --> 00:09:06,220 And what ends up happening here is this was just a function that I wrote. 184 00:09:06,220 --> 00:09:08,303 You could have done this as an anonymous function, 185 00:09:08,303 --> 00:09:10,640 but it would start to get pretty ugly pretty quickly. 186 00:09:10,640 --> 00:09:14,690 And so I went ahead and just gave it a name for simplicity's sake. 187 00:09:14,690 --> 00:09:18,850 But what Q ends up doing, and Q is coming out of this Q JavaScript 188 00:09:18,850 --> 00:09:21,550 library, it says, OK, whatever function you 189 00:09:21,550 --> 00:09:25,120 pass to await needs to take at least one argument. 190 00:09:25,120 --> 00:09:29,920 But it's going to be one plus however many defers you have. 191 00:09:29,920 --> 00:09:32,530 So you'll notice here that artist.CSV is going 192 00:09:32,530 --> 00:09:34,180 to immediately give us artist data. 193 00:09:34,180 --> 00:09:35,680 I could have called this whatever I wanted. 194 00:09:35,680 --> 00:09:36,805 I could have called it Foo. 195 00:09:36,805 --> 00:09:38,112 I could have called it Llama. 196 00:09:38,112 --> 00:09:39,820 It's just most convenient here to call it 197 00:09:39,820 --> 00:09:43,530 Artist Data so that it is clear what I've actually loaded in. 198 00:09:43,530 --> 00:09:45,730 And here, I've called this all Alb Data because I 199 00:09:45,730 --> 00:09:47,710 was lazy and didn't want to type album. 200 00:09:47,710 --> 00:09:50,050 But I could have easily done that. 201 00:09:50,050 --> 00:09:51,220 The order here matters. 202 00:09:51,220 --> 00:09:51,719 Right? 203 00:09:51,719 --> 00:09:56,740 The second defer is going to correspond to this third argument here. 204 00:09:56,740 --> 00:10:00,160 This first error is an error that potentially might be thrown 205 00:10:00,160 --> 00:10:01,940 by either one of these two functions. 206 00:10:01,940 --> 00:10:02,440 Right? 207 00:10:02,440 --> 00:10:05,760 Either one of these two calls to D3.CSV. 208 00:10:05,760 --> 00:10:09,490 If, for example, something was wrong in opening your CSV file, 209 00:10:09,490 --> 00:10:11,650 or if it wasn't able to get through the whole file, 210 00:10:11,650 --> 00:10:13,227 it will actually return an error. 211 00:10:13,227 --> 00:10:15,310 And so the first thing you want to do is make sure 212 00:10:15,310 --> 00:10:17,680 that you have actually checked the error. 213 00:10:17,680 --> 00:10:20,950 If that error exists, we're going to go ahead and return. 214 00:10:20,950 --> 00:10:23,020 As opposed to just console log, we're returning 215 00:10:23,020 --> 00:10:26,330 here so that the entire program does not continue running. 216 00:10:26,330 --> 00:10:29,800 But we're going to console log the error so that we as developers can try 217 00:10:29,800 --> 00:10:31,999 to troubleshoot exactly what happened. 218 00:10:31,999 --> 00:10:33,790 But assuming that that didn't happen, let's 219 00:10:33,790 --> 00:10:35,870 step through the rest of the code. 220 00:10:35,870 --> 00:10:39,820 So the first thing I've said is, OK, immediately I'm 221 00:10:39,820 --> 00:10:44,300 going to have a problem because my data sets don't make a lot of sense. 222 00:10:44,300 --> 00:10:47,740 And in fact, what I'm going to do here is 223 00:10:47,740 --> 00:10:51,070 I'm going to go ahead and comment in this console log, which 224 00:10:51,070 --> 00:10:53,910 is going to show us everything that's in Album Data. 225 00:10:53,910 --> 00:10:57,580 And I'm going to go ahead and put in another console log, which 226 00:10:57,580 --> 00:11:01,520 is going to show us Artist Data. 227 00:11:01,520 --> 00:11:06,740 228 00:11:06,740 --> 00:11:07,730 This is a cute trick. 229 00:11:07,730 --> 00:11:10,400 This is the Print F debugging of JavaScript. 230 00:11:10,400 --> 00:11:12,740 I highly recommend using it. 231 00:11:12,740 --> 00:11:15,440 Nothing is more frustrating than not knowing 232 00:11:15,440 --> 00:11:18,650 what your data looks like because it's then hard to make logic 233 00:11:18,650 --> 00:11:19,890 to manipulate your data. 234 00:11:19,890 --> 00:11:22,040 So the first thing I always like to do is actually 235 00:11:22,040 --> 00:11:24,470 figure out what does my data look like. 236 00:11:24,470 --> 00:11:27,920 So I always console log my data as soon as I've loaded it in. 237 00:11:27,920 --> 00:11:32,660 So, in fact, if I save this and make sure that my server is still running, 238 00:11:32,660 --> 00:11:33,950 I go back over here. 239 00:11:33,950 --> 00:11:36,760 Refresh this page. 240 00:11:36,760 --> 00:11:42,010 And then I'm going to go ahead and hope that the internet is working. 241 00:11:42,010 --> 00:11:45,920 And in fact, you see right away that I have an error. 242 00:11:45,920 --> 00:11:49,627 So this is why the console is super helpful. 243 00:11:49,627 --> 00:11:51,460 First things first is just understanding how 244 00:11:51,460 --> 00:11:53,900 to read what the console errors are telling you. 245 00:11:53,900 --> 00:11:56,420 You'll see here the line where the error occurred. 246 00:11:56,420 --> 00:12:01,750 So I know I should be looking at main JS line 22, where it has said to me, 247 00:12:01,750 --> 00:12:04,070 OK, you've referred to something called Album Data. 248 00:12:04,070 --> 00:12:05,420 And it's not defined. 249 00:12:05,420 --> 00:12:08,890 So in fact, if I go back to line 22, I can immediately say, oh yeah, 250 00:12:08,890 --> 00:12:10,090 I didn't call it Album Data. 251 00:12:10,090 --> 00:12:11,331 I called it Alb Data. 252 00:12:11,331 --> 00:12:11,830 Right? 253 00:12:11,830 --> 00:12:16,250 I can go back, save it, refresh the page again. 254 00:12:16,250 --> 00:12:19,910 And you'll notice that if you have no errors, things will load. 255 00:12:19,910 --> 00:12:21,650 If you have errors, things will not load. 256 00:12:21,650 --> 00:12:23,580 So this is always a good thing to do. 257 00:12:23,580 --> 00:12:26,330 So these two things here are actually coming 258 00:12:26,330 --> 00:12:29,090 immediately out of those console log statements that I did. 259 00:12:29,090 --> 00:12:32,660 And in fact, let me make this a little bit bigger for us. 260 00:12:32,660 --> 00:12:37,230 So Album Data, we see that it has 347 items. 261 00:12:37,230 --> 00:12:40,640 Remember, I mentioned that it was an array of JavaScript objects. 262 00:12:40,640 --> 00:12:43,580 One way you can immediately see that is that this first bracket here 263 00:12:43,580 --> 00:12:44,911 is in fact a square bracket. 264 00:12:44,911 --> 00:12:45,410 Right? 265 00:12:45,410 --> 00:12:48,410 This tells me that it's an array, similar to an array in Python 266 00:12:48,410 --> 00:12:51,220 or a list in Python or an array in C. 267 00:12:51,220 --> 00:12:52,970 If you click the little dropdown arrow, it 268 00:12:52,970 --> 00:12:56,420 does this nice thing where it segments it for you because otherwise it gets 269 00:12:56,420 --> 00:12:58,400 kind of impossible to read and to see. 270 00:12:58,400 --> 00:13:01,297 You can drop down again, and you can immediately see, OK, 271 00:13:01,297 --> 00:13:02,630 this is what my data looks like. 272 00:13:02,630 --> 00:13:03,129 Right? 273 00:13:03,129 --> 00:13:07,730 Each one of these objects has this Album ID key and has this title key, 274 00:13:07,730 --> 00:13:08,941 has this Artist ID key. 275 00:13:08,941 --> 00:13:09,440 All right? 276 00:13:09,440 --> 00:13:11,690 This will be good for me to know as I'm writing loops 277 00:13:11,690 --> 00:13:14,070 to iterate through this data. 278 00:13:14,070 --> 00:13:17,370 By the same token, I can look at the Artist Data. 279 00:13:17,370 --> 00:13:20,460 And I can say, OK, Artist Data all has an ID. 280 00:13:20,460 --> 00:13:23,010 And it has an artist that it corresponds to. 281 00:13:23,010 --> 00:13:27,150 I happen to know, from the data that I loaded in, that an artist's ID of one 282 00:13:27,150 --> 00:13:32,080 here corresponds to a same artist ID of one over here. 283 00:13:32,080 --> 00:13:32,580 Right? 284 00:13:32,580 --> 00:13:35,560 So For Those About To Rock, We Salute You, 285 00:13:35,560 --> 00:13:39,180 I know that this is supposed to be an AC/DC album. 286 00:13:39,180 --> 00:13:39,960 Right? 287 00:13:39,960 --> 00:13:42,780 So keeping that in mind, I said to myself, OK, 288 00:13:42,780 --> 00:13:44,970 what would be an interesting thing to visualize. 289 00:13:44,970 --> 00:13:46,380 Once you've loaded in your data, and once you've 290 00:13:46,380 --> 00:13:48,600 decided what your data should be, the next question 291 00:13:48,600 --> 00:13:50,308 you should really be asking is, what am I 292 00:13:50,308 --> 00:13:52,710 trying to visualize because that's going to dictate how 293 00:13:52,710 --> 00:13:55,050 you're going to run through your code. 294 00:13:55,050 --> 00:13:57,360 And so what I decided to visualize was actually 295 00:13:57,360 --> 00:14:01,890 just the number of albums that were produced by a particular artist. 296 00:14:01,890 --> 00:14:05,857 So you'll notice here on my y-axis, I've got just a number of albums. 297 00:14:05,857 --> 00:14:08,190 And on my x-axis, I actually have the name of the artist 298 00:14:08,190 --> 00:14:09,424 that this corresponds to. 299 00:14:09,424 --> 00:14:11,340 I've added a little bit of extra functionality 300 00:14:11,340 --> 00:14:13,590 that if you click on any of the bars, you can actually 301 00:14:13,590 --> 00:14:15,350 see a list of these albums. 302 00:14:15,350 --> 00:14:17,100 And we'll talk about that in a second. 303 00:14:17,100 --> 00:14:18,891 But keeping that in mind, I said to myself, 304 00:14:18,891 --> 00:14:25,230 OK, I'm going to need some way to count the number of times an artist ID occurs 305 00:14:25,230 --> 00:14:27,300 given the number of albums. 306 00:14:27,300 --> 00:14:28,380 Right? 307 00:14:28,380 --> 00:14:30,660 So the first thing I said to myself is, OK, I'm 308 00:14:30,660 --> 00:14:34,800 going to need to make some kind of mapping between an artist ID 309 00:14:34,800 --> 00:14:37,120 and the actual name of the artist. 310 00:14:37,120 --> 00:14:38,730 So what I did was I did the following. 311 00:14:38,730 --> 00:14:41,790 I said, OK, I'm going to make an artist map, which is itself 312 00:14:41,790 --> 00:14:43,531 going to be just a JavaScript object. 313 00:14:43,531 --> 00:14:45,780 Or you can think of this more like a dictionary, which 314 00:14:45,780 --> 00:14:48,910 is kind of how I was envisioning it as I wrote this code. 315 00:14:48,910 --> 00:14:53,760 And the idea here is that we're going to iterate through all of the Artist Data. 316 00:14:53,760 --> 00:14:57,625 And for each one of the JavaScript objects in the Artist Data, 317 00:14:57,625 --> 00:15:01,830 right, so for each object that has an artist ID and it has an artist's name, 318 00:15:01,830 --> 00:15:05,110 we're going to say, OK, here's that individual object. 319 00:15:05,110 --> 00:15:07,530 And we're going to say, OK, within artist 320 00:15:07,530 --> 00:15:11,700 map at the index that corresponds to that ID, 321 00:15:11,700 --> 00:15:13,830 please save the name of that artist. 322 00:15:13,830 --> 00:15:16,380 And this was just to make a quick easy mapping so that I 323 00:15:16,380 --> 00:15:19,320 could refer to these objects later. 324 00:15:19,320 --> 00:15:23,490 The more interesting stuff actually happens in this D3.nest. 325 00:15:23,490 --> 00:15:26,500 So what D3.nest does is that it says to you, 326 00:15:26,500 --> 00:15:30,420 OK, I'm going to iterate through all of this data for you. 327 00:15:30,420 --> 00:15:35,160 And what I'm going to do is I'm going to build a brand new object where 328 00:15:35,160 --> 00:15:38,910 the keys are going to correspond to something that already came out 329 00:15:38,910 --> 00:15:39,960 of your data. 330 00:15:39,960 --> 00:15:43,590 And the values, or the leaves as they like to call it, 331 00:15:43,590 --> 00:15:46,810 are going to correspond to something else out of your data. 332 00:15:46,810 --> 00:15:50,340 So what I've said here is, OK, I want a count by artist ID. 333 00:15:50,340 --> 00:15:52,050 And the reason I wanted a count by artist 334 00:15:52,050 --> 00:15:56,220 ID was because I had already made this mapping by artist ID 335 00:15:56,220 --> 00:15:58,780 so that I could easily index into it. 336 00:15:58,780 --> 00:16:04,922 So I said, OK, for each one of the pieces of data within my album data, 337 00:16:04,922 --> 00:16:06,630 so this entry is actually tells you which 338 00:16:06,630 --> 00:16:09,240 data you're going to be iterating through, I've said, 339 00:16:09,240 --> 00:16:16,080 OK, the key is going to correspond to that particular object's artist ID. 340 00:16:16,080 --> 00:16:19,620 I've then said, OK, I want you to roll up all of the leaves. 341 00:16:19,620 --> 00:16:22,914 I think this is one of the most confusing lines in this code. 342 00:16:22,914 --> 00:16:24,830 So let me just unpack it a little bit for you. 343 00:16:24,830 --> 00:16:28,510 And I've left a comment just to be a little more clear. 344 00:16:28,510 --> 00:16:30,750 But what we're basically saying here is what 345 00:16:30,750 --> 00:16:34,590 rollup does is that it searches through every single one 346 00:16:34,590 --> 00:16:37,710 of the items in your greater data set. 347 00:16:37,710 --> 00:16:42,630 And it finds the ones that match the particular key. 348 00:16:42,630 --> 00:16:46,440 So, in fact, what leaves is, if I were a console.log it, 349 00:16:46,440 --> 00:16:51,060 leaves is actually an array of objects that match that key. 350 00:16:51,060 --> 00:16:53,640 You can see then why that would be helpful for me 351 00:16:53,640 --> 00:16:57,390 because what I'm really trying to do is count the number of objects that 352 00:16:57,390 --> 00:17:00,450 correspond to a particular artist ID. 353 00:17:00,450 --> 00:17:03,540 Therefore, by getting the length of that array, which is literally 354 00:17:03,540 --> 00:17:06,569 the number of objects that have that artist ID, 355 00:17:06,569 --> 00:17:09,329 this is how I've gone through and actually counted 356 00:17:09,329 --> 00:17:12,540 how many things exist for this artist. 357 00:17:12,540 --> 00:17:15,381 The real question here is, Athena, was this the only way to do it? 358 00:17:15,381 --> 00:17:16,589 And the answer to that is no. 359 00:17:16,589 --> 00:17:18,750 In fact, with D3, there's a lot of ways that you 360 00:17:18,750 --> 00:17:20,880 can do a lot of the same operations. 361 00:17:20,880 --> 00:17:24,000 But in fact, this is probably the most concise way to do it, 362 00:17:24,000 --> 00:17:26,670 albeit maybe a little bit unclear if you're just 363 00:17:26,670 --> 00:17:28,510 using it for the first time. 364 00:17:28,510 --> 00:17:32,160 That being said, D3 actually has very good documentation. 365 00:17:32,160 --> 00:17:38,230 And so if, on your computer now, you were to Google D3.nest example, 366 00:17:38,230 --> 00:17:43,020 if you see anything from bl.ock, something like that, I look at it 367 00:17:43,020 --> 00:17:43,865 and I read blocks. 368 00:17:43,865 --> 00:17:46,560 So if you see anything from like blocks.org, 369 00:17:46,560 --> 00:17:49,440 that's great examples of visualizations that people 370 00:17:49,440 --> 00:17:52,800 have done that use different functionality out of D3. 371 00:17:52,800 --> 00:17:56,220 I highly recommend taking a look at it. 372 00:17:56,220 --> 00:17:59,430 So now I have this count by artist ID. 373 00:17:59,430 --> 00:18:02,427 And I've said to myself, great, I have all of this information. 374 00:18:02,427 --> 00:18:05,010 And I've said, all right, I probably want to make a bar graph. 375 00:18:05,010 --> 00:18:07,770 And because I want to make a bar graph, what's important to me 376 00:18:07,770 --> 00:18:10,890 is to make sure that my data is arranged in such a way 377 00:18:10,890 --> 00:18:13,480 that it's going to be easy to display it. 378 00:18:13,480 --> 00:18:16,780 So in fact, the next thing that I do is an in place sort. 379 00:18:16,780 --> 00:18:22,800 In place here meaning that I actually call this function on this array 380 00:18:22,800 --> 00:18:24,060 that I've been given. 381 00:18:24,060 --> 00:18:26,070 And it will sort it in place for me. 382 00:18:26,070 --> 00:18:27,870 The way sort works is as follows. 383 00:18:27,870 --> 00:18:31,200 Sort expects an anonymous function. 384 00:18:31,200 --> 00:18:34,050 And in fact, what source hands that anonymous function 385 00:18:34,050 --> 00:18:36,630 is two side by side objects. 386 00:18:36,630 --> 00:18:39,150 So we have object A and object B. It could be 387 00:18:39,150 --> 00:18:42,090 that object A is greater than object B. 388 00:18:42,090 --> 00:18:45,570 But in order to sort things in ascending order, what you really want 389 00:18:45,570 --> 00:18:49,290 is the difference between object A and object B. 390 00:18:49,290 --> 00:18:52,110 But keep in mind that object A really is an object. 391 00:18:52,110 --> 00:18:54,300 And as a result, it has multiple keys. 392 00:18:54,300 --> 00:18:57,430 The thing that I was interested in here was value. 393 00:18:57,430 --> 00:19:00,510 And the reason I knew it was value, so for example, 394 00:19:00,510 --> 00:19:03,570 like let's say I didn't know what I was going to get out of this count 395 00:19:03,570 --> 00:19:04,830 by artist ID. 396 00:19:04,830 --> 00:19:09,345 I could go ahead and say, OK, I'm going to a console.log it. 397 00:19:09,345 --> 00:19:09,845 Right? 398 00:19:09,845 --> 00:19:15,199 399 00:19:15,199 --> 00:19:16,990 And this is just a cute trick I like to use 400 00:19:16,990 --> 00:19:19,740 for console.log where you can actually label the thing that you're 401 00:19:19,740 --> 00:19:24,370 about to log so that you can find it easily in the console. 402 00:19:24,370 --> 00:19:25,840 So I can go ahead and save. 403 00:19:25,840 --> 00:19:27,810 Go ahead and refresh. 404 00:19:27,810 --> 00:19:31,840 And I can say, OK, like what did I get back. 405 00:19:31,840 --> 00:19:35,190 Computer, come on you can do it. 406 00:19:35,190 --> 00:19:35,690 All right. 407 00:19:35,690 --> 00:19:37,550 So here it is, this artist ID count. 408 00:19:37,550 --> 00:19:41,120 I can see immediately, again, that this first character here was a bracket. 409 00:19:41,120 --> 00:19:42,620 So I know it's going to be an array. 410 00:19:42,620 --> 00:19:45,350 And I can see that what I end up with is a bunch of objects 411 00:19:45,350 --> 00:19:47,450 where they have the key key. 412 00:19:47,450 --> 00:19:49,460 And the other key value where value is actually 413 00:19:49,460 --> 00:19:53,120 the number of objects that were counted for this particular artist ID. 414 00:19:53,120 --> 00:19:56,390 This was the only way for me to know that when I was sorting 415 00:19:56,390 --> 00:19:59,540 I should be looking at the value field and not some other field. 416 00:19:59,540 --> 00:20:02,895 I literally had to pull up the data and look at it in order to figure this out. 417 00:20:02,895 --> 00:20:04,520 There is nothing wrong with doing that. 418 00:20:04,520 --> 00:20:06,930 And in fact, I encourage you to do that. 419 00:20:06,930 --> 00:20:10,140 So once I went ahead and sorted, I said, OK, 420 00:20:10,140 --> 00:20:12,290 just for like display purposes here, I'm actually 421 00:20:12,290 --> 00:20:14,030 going to cut down some of the data we had 422 00:20:14,030 --> 00:20:17,750 because we have like 204 items of data. 423 00:20:17,750 --> 00:20:20,000 And that just like gets a little bit ugly to display. 424 00:20:20,000 --> 00:20:21,791 There are ways to get around this, but just 425 00:20:21,791 --> 00:20:24,770 like to make this attractable example, I said, OK, I'm 426 00:20:24,770 --> 00:20:29,030 going to just get rid of everything from index 0 to index 180. 427 00:20:29,030 --> 00:20:30,590 This was perfectly arbitrary. 428 00:20:30,590 --> 00:20:32,780 You absolutely don't have to do this, but it just 429 00:20:32,780 --> 00:20:35,490 simplified a little bit of this process. 430 00:20:35,490 --> 00:20:39,770 And then, finally, what I said was, OK, now that I have loaded all of my data, 431 00:20:39,770 --> 00:20:42,789 and now that I have cleaned my data in a way that I am happy with, 432 00:20:42,789 --> 00:20:45,080 I can go ahead and call a new function that is actually 433 00:20:45,080 --> 00:20:47,210 going to create the visualization. 434 00:20:47,210 --> 00:20:50,990 It's really important that you never try to create the visualization 435 00:20:50,990 --> 00:20:53,840 before you've loaded all of your data. 436 00:20:53,840 --> 00:20:56,210 Because, in fact, the way JavaScript works 437 00:20:56,210 --> 00:21:00,140 is that it might try to create your visualization before your data has 438 00:21:00,140 --> 00:21:01,310 finished loading. 439 00:21:01,310 --> 00:21:03,680 As a result, if your data doesn't yet exist, 440 00:21:03,680 --> 00:21:05,970 your visualization is going to fail. 441 00:21:05,970 --> 00:21:10,220 And if it fails, you might have to refresh the page several hundred times 442 00:21:10,220 --> 00:21:14,819 until you get lucky that maybe your data loads first and loads fast enough. 443 00:21:14,819 --> 00:21:16,610 So in fact, you'll notice here that I never 444 00:21:16,610 --> 00:21:21,292 tried to say, OK, create the visualization until I've made sure 445 00:21:21,292 --> 00:21:22,750 that everything has been loaded in. 446 00:21:22,750 --> 00:21:26,540 And this is super important. 447 00:21:26,540 --> 00:21:32,150 Easier ways to do this include actually just calling D3.CSV. 448 00:21:32,150 --> 00:21:35,270 And within that, pass it an anonymous function. 449 00:21:35,270 --> 00:21:39,080 And then do all of your data creation within D3.CSV. 450 00:21:39,080 --> 00:21:42,160 We can look at an example of that later if that's confusing. 451 00:21:42,160 --> 00:21:44,540 But this is just one way that you can do it. 452 00:21:44,540 --> 00:21:48,630 So now, I'm actually going to talk about the visualization itself. 453 00:21:48,630 --> 00:21:52,655 But before I move on, any questions? 454 00:21:52,655 --> 00:21:53,155 Yeah? 455 00:21:53,155 --> 00:21:57,180 AUDIENCE: [INAUDIBLE] 456 00:21:57,180 --> 00:21:59,749 457 00:21:59,749 --> 00:22:01,040 ATHENA BRAUN: Yeah, absolutely. 458 00:22:01,040 --> 00:22:03,710 So the question here was, just to give another quick example 459 00:22:03,710 --> 00:22:05,420 of how D3.nest works. 460 00:22:05,420 --> 00:22:11,150 So D3.nest is going to say I'm going to build you a new array of objects. 461 00:22:11,150 --> 00:22:14,530 And the array of objects that I'm going to give you is going to have a key 462 00:22:14,530 --> 00:22:16,520 and is going to have a value. 463 00:22:16,520 --> 00:22:20,480 It wants to know, as it's searching through your data, what 464 00:22:20,480 --> 00:22:23,600 key do I want to be matching against. 465 00:22:23,600 --> 00:22:28,190 And so what it does is it says, OK, as I'm iterating through your data 466 00:22:28,190 --> 00:22:31,160 I'm going to look at a particular datum. 467 00:22:31,160 --> 00:22:33,230 And I'm going to get its artist ID. 468 00:22:33,230 --> 00:22:36,920 And that is what I'm going to use as the key here. 469 00:22:36,920 --> 00:22:37,930 Right? 470 00:22:37,930 --> 00:22:39,830 Rollup is kind of the confusing part. 471 00:22:39,830 --> 00:22:43,880 Where rollup kind of does this like searching count for you, where it says, 472 00:22:43,880 --> 00:22:45,350 OK, I am holding this key. 473 00:22:45,350 --> 00:22:46,920 Let's say the key is three. 474 00:22:46,920 --> 00:22:50,480 And it's going to look through every single one of the objects 475 00:22:50,480 --> 00:22:52,140 within this album data. 476 00:22:52,140 --> 00:22:52,640 Right? 477 00:22:52,640 --> 00:22:55,520 And it's going to say, does this object match this key? 478 00:22:55,520 --> 00:22:57,710 If yes, I'm going to stick it into an array. 479 00:22:57,710 --> 00:22:58,790 Does this object match? 480 00:22:58,790 --> 00:23:00,267 If no, I'm going to discard it. 481 00:23:00,267 --> 00:23:01,100 Does this one match? 482 00:23:01,100 --> 00:23:01,790 Yes. 483 00:23:01,790 --> 00:23:02,400 No. 484 00:23:02,400 --> 00:23:02,900 Yes. 485 00:23:02,900 --> 00:23:03,890 No. 486 00:23:03,890 --> 00:23:08,480 And so at the end of the day, what rollup actually passes to this function 487 00:23:08,480 --> 00:23:12,780 is an array of all of the objects that matched that key. 488 00:23:12,780 --> 00:23:16,280 Another way to think of this is that each one of these album data 489 00:23:16,280 --> 00:23:20,240 actually had an artist ID. 490 00:23:20,240 --> 00:23:20,900 Right? 491 00:23:20,900 --> 00:23:25,010 So if this artist ID matched the current key that I was holding, 492 00:23:25,010 --> 00:23:27,710 this would be considered a match. 493 00:23:27,710 --> 00:23:30,900 Once I have that array, I can do whatever I want with that array. 494 00:23:30,900 --> 00:23:33,650 But because what I'm interested in is actually the count, 495 00:23:33,650 --> 00:23:36,440 I know that by taking the length of the array, that 496 00:23:36,440 --> 00:23:42,710 is really the same as saying how many albums corresponded to one artist. 497 00:23:42,710 --> 00:23:46,190 And this final thing here, the order, I always think is a little bit weird. 498 00:23:46,190 --> 00:23:49,580 But entries is actually where you specify the data set 499 00:23:49,580 --> 00:23:51,080 that you want to iterate through. 500 00:23:51,080 --> 00:23:52,500 Did that answer your question? 501 00:23:52,500 --> 00:23:53,180 Great. 502 00:23:53,180 --> 00:23:54,471 Anything else before I move on? 503 00:23:54,471 --> 00:23:56,591 504 00:23:56,591 --> 00:23:57,090 OK. 505 00:23:57,090 --> 00:23:58,180 Great. 506 00:23:58,180 --> 00:23:58,680 All right. 507 00:23:58,680 --> 00:24:00,660 Let's talk about the visualization. 508 00:24:00,660 --> 00:24:05,610 So there are fancier ways to do visualizations and less fancy ways. 509 00:24:05,610 --> 00:24:10,461 I always like to start by initializing a margin object where you'll 510 00:24:10,461 --> 00:24:12,960 notice that there's actually like a nice little bit of space 511 00:24:12,960 --> 00:24:14,165 here along the side. 512 00:24:14,165 --> 00:24:15,540 And there's some space over here. 513 00:24:15,540 --> 00:24:19,410 And like admittedly, this name was the world's longest artist's name. 514 00:24:19,410 --> 00:24:22,690 And so it is taking up more space than it should be. 515 00:24:22,690 --> 00:24:24,960 But there's actually a little bit of space 516 00:24:24,960 --> 00:24:28,590 wherein you can actually see that my visualization exists 517 00:24:28,590 --> 00:24:31,710 within this nice confined rectangle. 518 00:24:31,710 --> 00:24:37,110 The way I've configured that is through this margin object, where I can now 519 00:24:37,110 --> 00:24:42,810 like calculate the width and the size of my actual visualization itself 520 00:24:42,810 --> 00:24:45,330 by just changing values in one place, as opposed 521 00:24:45,330 --> 00:24:48,100 to changing values in a bunch of different places. 522 00:24:48,100 --> 00:24:51,490 So this was really more of a convenience thing more than anything, 523 00:24:51,490 --> 00:24:53,620 but I highly recommend using it. 524 00:24:53,620 --> 00:24:57,690 So this is a little bit of jQuery that I said I would point out to you guys. 525 00:24:57,690 --> 00:24:59,820 Where, in essence, I've said, OK, I don't 526 00:24:59,820 --> 00:25:03,210 want to hard code the width and the height of my visualization. 527 00:25:03,210 --> 00:25:06,000 In fact, I want my visualization to conform 528 00:25:06,000 --> 00:25:11,040 to whatever the width and the height of the element that it exists in is. 529 00:25:11,040 --> 00:25:13,380 So that's a fancy way of saying if I've already 530 00:25:13,380 --> 00:25:16,560 said that I'm going to put my visualization in a box that 531 00:25:16,560 --> 00:25:23,280 is 500 by 600 pixels, in essence, what I want to happen here is this width 532 00:25:23,280 --> 00:25:27,701 to equal 500 pixels, and this height to equals 600 pixels or the other way 533 00:25:27,701 --> 00:25:28,200 around. 534 00:25:28,200 --> 00:25:31,410 I don't quite remember which way I set it. 535 00:25:31,410 --> 00:25:34,080 And in order to do that, I've said, OK, jQuery 536 00:25:34,080 --> 00:25:39,690 please get me the HTML element that matches this ID where notice that I've 537 00:25:39,690 --> 00:25:42,590 actually passed parent element in here. 538 00:25:42,590 --> 00:25:44,880 So actually, it's worth noting that this create 539 00:25:44,880 --> 00:25:48,420 vis could be used multiple times depending on the data 540 00:25:48,420 --> 00:25:49,620 that I'm going to pass. 541 00:25:49,620 --> 00:25:51,000 So that's worth noting. 542 00:25:51,000 --> 00:25:54,060 But notice that I've said, OK, this visualization 543 00:25:54,060 --> 00:25:58,140 is going to exist in the chart display column, which you'll remember 544 00:25:58,140 --> 00:26:00,010 was the ID of this particular div here. 545 00:26:00,010 --> 00:26:00,510 All right? 546 00:26:00,510 --> 00:26:03,710 So this is why IDs were going to be super important. 547 00:26:03,710 --> 00:26:04,377 All right. 548 00:26:04,377 --> 00:26:06,210 So please get me the width of that, and then 549 00:26:06,210 --> 00:26:09,420 go ahead and subtract this margin that I've gotten you, 550 00:26:09,420 --> 00:26:10,890 both for the left and the right. 551 00:26:10,890 --> 00:26:14,107 Where we said, OK, I know that this full width is going to be this whole box. 552 00:26:14,107 --> 00:26:16,440 In fact, I want to constrain things a little bit in case 553 00:26:16,440 --> 00:26:19,530 my visualization has like straggling items 554 00:26:19,530 --> 00:26:22,500 because I don't want those to end up either off of the screen 555 00:26:22,500 --> 00:26:24,190 or out of the parent element. 556 00:26:24,190 --> 00:26:26,730 So it's absolutely worth subtracting margins here. 557 00:26:26,730 --> 00:26:28,590 And you do the same thing for the height. 558 00:26:28,590 --> 00:26:31,110 The other thing worth noting here is SVGs. 559 00:26:31,110 --> 00:26:33,439 If you ever start reading about D3, you're 560 00:26:33,439 --> 00:26:34,980 going to see this all over the place. 561 00:26:34,980 --> 00:26:39,630 SVG stands for scalable vector graphics, which is really 562 00:26:39,630 --> 00:26:42,902 just a fancy way of saying that a bunch of people got together and said, 563 00:26:42,902 --> 00:26:44,610 yeah, graphics on the internet are really 564 00:26:44,610 --> 00:26:46,710 hard because the minute you try to rescale them, 565 00:26:46,710 --> 00:26:48,660 they lose all of their resolution. 566 00:26:48,660 --> 00:26:52,260 Let's build something that isn't going to lose its resolution no matter how 567 00:26:52,260 --> 00:26:54,180 big or how small you've made it. 568 00:26:54,180 --> 00:26:56,390 And that is exactly what an SVG is. 569 00:26:56,390 --> 00:26:58,770 D3 expects SVGs. 570 00:26:58,770 --> 00:27:02,850 It will only ever append objects to SVGs. 571 00:27:02,850 --> 00:27:05,160 And so as a result, the first thing you will always 572 00:27:05,160 --> 00:27:08,430 find yourself doing whenever you deal with D3 573 00:27:08,430 --> 00:27:13,140 is you will find yourself making what you can think of as the canvas SVG. 574 00:27:13,140 --> 00:27:17,010 This is the SVG onto which all of your particular objects 575 00:27:17,010 --> 00:27:21,040 that actually build up your visualization are going to end up. 576 00:27:21,040 --> 00:27:24,960 So if we look at this, this D3.select is really 577 00:27:24,960 --> 00:27:28,740 analogous to our document.QuerySelector where 578 00:27:28,740 --> 00:27:33,210 we've said, OK, with D3, go ahead and find me the parent element. 579 00:27:33,210 --> 00:27:37,320 And the first thing that I want you to do is actually append to it an SVG. 580 00:27:37,320 --> 00:27:40,650 And we'll look at what the HTML looks like for this in a second. 581 00:27:40,650 --> 00:27:44,640 Where now, D3 really just likes chaining syntax. 582 00:27:44,640 --> 00:27:48,960 Where we said, OK, get me the parent element and append an SVG to it. 583 00:27:48,960 --> 00:27:51,780 From this point, the like pointer that I'm holding 584 00:27:51,780 --> 00:27:56,340 corresponds not to the parent element, but actually to the SVG itself. 585 00:27:56,340 --> 00:27:59,010 And I've said, OK, for this SVG that I'm holding, 586 00:27:59,010 --> 00:28:01,530 please give it the attribute of width. 587 00:28:01,530 --> 00:28:03,646 And I've given a calculation for the width. 588 00:28:03,646 --> 00:28:05,270 Please give it the attribute of height. 589 00:28:05,270 --> 00:28:08,280 And I've given a calculation for height. 590 00:28:08,280 --> 00:28:11,160 And then append to it this thing called a G group. 591 00:28:11,160 --> 00:28:13,470 A G group is really just a nicer way in D3 592 00:28:13,470 --> 00:28:16,150 to start building layers on top of layers 593 00:28:16,150 --> 00:28:20,520 so that if you want to, for example, apply styling to a bunch of things, 594 00:28:20,520 --> 00:28:24,060 if they're all on the same layer, you can apply the styling very easily. 595 00:28:24,060 --> 00:28:26,790 You could absolutely have done this without using a G group. 596 00:28:26,790 --> 00:28:30,360 But this was more as a kind of just like the rule of thumb 597 00:28:30,360 --> 00:28:32,110 that people like to use. 598 00:28:32,110 --> 00:28:35,040 And finally, what I've said is, OK, once you've 599 00:28:35,040 --> 00:28:39,180 appended this SVG, go ahead and transform it, 600 00:28:39,180 --> 00:28:41,040 which is really the same as saying, OK, I'm 601 00:28:41,040 --> 00:28:43,590 going to actually shift it somewhere on the page. 602 00:28:43,590 --> 00:28:47,400 And the shift that I want to do is a horizontal and a vertical translate 603 00:28:47,400 --> 00:28:54,720 where I've said, OK, translate it to the right 604 00:28:54,720 --> 00:28:57,090 this many pixels so that I get my margin. 605 00:28:57,090 --> 00:28:59,540 And translate it down this many pixels. 606 00:28:59,540 --> 00:29:01,100 OK? 607 00:29:01,100 --> 00:29:02,630 All right. 608 00:29:02,630 --> 00:29:04,731 Question on SVG? 609 00:29:04,731 --> 00:29:06,980 You don't have to understand what it is as long as you 610 00:29:06,980 --> 00:29:08,660 understand that it's a canvas. 611 00:29:08,660 --> 00:29:11,240 At the end of the day, that's all this is. 612 00:29:11,240 --> 00:29:15,800 Where if you think about it, this white block here, 613 00:29:15,800 --> 00:29:18,830 you can't actually see, but is basically my SVG. 614 00:29:18,830 --> 00:29:22,460 And everything that I've appended to it are just other elements 615 00:29:22,460 --> 00:29:24,440 that I have put onto that canvas. 616 00:29:24,440 --> 00:29:28,350 If that canvas wasn't there, I couldn't have put any of these elements on here. 617 00:29:28,350 --> 00:29:31,190 The next thing you should notice is that really a bar graph 618 00:29:31,190 --> 00:29:32,700 is just a bunch of rectangles. 619 00:29:32,700 --> 00:29:33,200 Right? 620 00:29:33,200 --> 00:29:36,620 And that is kind of exactly how D3 is going to treat visualizations. 621 00:29:36,620 --> 00:29:39,980 Where D3 is going to say, well, like a line graph is really 622 00:29:39,980 --> 00:29:42,920 just a couple of circles with a line running through it, 623 00:29:42,920 --> 00:29:45,140 or a bar graph is really just a bunch of rectangles 624 00:29:45,140 --> 00:29:47,810 of varying heights and widths. 625 00:29:47,810 --> 00:29:52,740 And so when we're going to be making this visualization, we're going to say, 626 00:29:52,740 --> 00:29:54,920 OK, I know that I need a bunch of rectangles, 627 00:29:54,920 --> 00:29:56,910 and I know that I need them all to fit. 628 00:29:56,910 --> 00:29:57,410 Right? 629 00:29:57,410 --> 00:30:00,840 And this is where this idea of scaling starts to come into play. 630 00:30:00,840 --> 00:30:03,590 But scaling is really hard, especially if you don't know off 631 00:30:03,590 --> 00:30:06,170 the bat how many pieces of data you have, 632 00:30:06,170 --> 00:30:09,920 what the min and max values of those data are, and like 633 00:30:09,920 --> 00:30:12,810 remember that we didn't hard code the width and the height. 634 00:30:12,810 --> 00:30:16,400 So in fact, your total scale could be changing depending 635 00:30:16,400 --> 00:30:18,170 on what your parent element is. 636 00:30:18,170 --> 00:30:19,550 So D3 has been really nice. 637 00:30:19,550 --> 00:30:22,730 And it has actually come up with these scale generators 638 00:30:22,730 --> 00:30:24,950 that let you give it a few parameters. 639 00:30:24,950 --> 00:30:27,030 And it will actually generate the scale for you. 640 00:30:27,030 --> 00:30:29,460 It takes out all of the hard thinking. 641 00:30:29,460 --> 00:30:32,570 So there's several different kinds of scales that you can use. 642 00:30:32,570 --> 00:30:36,050 Linear scales are, I think, the ones that come most easily to people 643 00:30:36,050 --> 00:30:40,130 because it's literally take this value in this domain 644 00:30:40,130 --> 00:30:43,820 and squish it to fit into the domain of my width or my height 645 00:30:43,820 --> 00:30:47,510 or the range of my height and my width. 646 00:30:47,510 --> 00:30:50,330 Ordinal scales are a little bit more tricky in D3, 647 00:30:50,330 --> 00:30:52,550 but it's worth knowing how to use them if you ever 648 00:30:52,550 --> 00:30:55,709 want to visualize something that isn't numeric. 649 00:30:55,709 --> 00:30:57,500 Where ordinal scales will do the following. 650 00:30:57,500 --> 00:31:01,400 Ordinal scales will figure out for you how many items you need to display. 651 00:31:01,400 --> 00:31:05,840 It will figure out how wide each one of those display items need to be, 652 00:31:05,840 --> 00:31:07,910 so in this case, our bar width. 653 00:31:07,910 --> 00:31:12,170 And it will figure out the space that needs to exist between each of the bars 654 00:31:12,170 --> 00:31:14,010 to make all of this work. 655 00:31:14,010 --> 00:31:17,900 So you'll notice here that I've said, OK, the range of the values 656 00:31:17,900 --> 00:31:20,895 that I need you to output are going to be from zero to my width. 657 00:31:20,895 --> 00:31:21,770 And that makes sense. 658 00:31:21,770 --> 00:31:22,640 Right? 659 00:31:22,640 --> 00:31:25,650 Where I've said this is going to be the scale for my x-axis. 660 00:31:25,650 --> 00:31:29,630 And so I know that my x-axis is going to run from the zero width pixel 661 00:31:29,630 --> 00:31:33,190 to the pixel representing my width. 662 00:31:33,190 --> 00:31:35,690 On the other hand, I've said, OK, between each of the blocks 663 00:31:35,690 --> 00:31:38,267 go ahead and give me half a pixel worth of padding just 664 00:31:38,267 --> 00:31:39,850 to make it look a little bit prettier. 665 00:31:39,850 --> 00:31:40,790 I could make this bigger. 666 00:31:40,790 --> 00:31:41,873 I could make this smaller. 667 00:31:41,873 --> 00:31:43,820 This is really just up to taste. 668 00:31:43,820 --> 00:31:47,790 And finally, it's the domain that kind of looks a little bit ugly. 669 00:31:47,790 --> 00:31:52,220 Ranges are the values that the scale is going to output given a value. 670 00:31:52,220 --> 00:31:57,680 And the domain are all of the values that your scale should expect to get. 671 00:31:57,680 --> 00:32:01,010 When it comes to scales, the domain is always going to come from your data 672 00:32:01,010 --> 00:32:02,580 itself. 673 00:32:02,580 --> 00:32:04,610 So what we end up doing is the following. 674 00:32:04,610 --> 00:32:09,320 I've said, OK, D3, please do me a favor and apply a function 675 00:32:09,320 --> 00:32:12,670 to every single one of the items in my count data, 676 00:32:12,670 --> 00:32:16,610 where the function that I want you to apply to an individual item 677 00:32:16,610 --> 00:32:18,330 is going to do the following. 678 00:32:18,330 --> 00:32:22,490 It's going to go ahead and figure out what the name of that artist 679 00:32:22,490 --> 00:32:24,620 is using my artist map. 680 00:32:24,620 --> 00:32:26,480 And keep in mind what I've done here is I've 681 00:32:26,480 --> 00:32:30,920 said, OK, datum itself is going to be of the form key value. 682 00:32:30,920 --> 00:32:35,210 And I know that the key is going to correspond to some artist ID. 683 00:32:35,210 --> 00:32:37,710 Knowing that, I can say, OK, if I give my artist 684 00:32:37,710 --> 00:32:42,840 map an artist ID, what it will return to me is actually the name of the artist. 685 00:32:42,840 --> 00:32:46,430 So I've gone ahead and said, OK, get me all of the names of the artists that 686 00:32:46,430 --> 00:32:48,390 correspond to all of the data. 687 00:32:48,390 --> 00:32:48,890 Right? 688 00:32:48,890 --> 00:32:51,560 That's exactly what this has done. 689 00:32:51,560 --> 00:32:54,380 And it has actually built me a JavaScript object, 690 00:32:54,380 --> 00:32:58,130 but really what I'm interested in here is all of the possible artist names 691 00:32:58,130 --> 00:32:59,610 that I could have gotten. 692 00:32:59,610 --> 00:33:04,580 And so by asking it, OK, you're a JavaScript object, 693 00:33:04,580 --> 00:33:07,190 please tell me what all of your keys are. 694 00:33:07,190 --> 00:33:09,880 I have, in essence said to domain, OK, here 695 00:33:09,880 --> 00:33:15,890 is an array of every single possible artist name that you could ever get. 696 00:33:15,890 --> 00:33:19,220 How it does the math to figure out which artist name 697 00:33:19,220 --> 00:33:24,020 goes where, how wide the bars have to be is all abstracted away. 698 00:33:24,020 --> 00:33:28,220 It's not important for you to know how it does it, simply that it does it. 699 00:33:28,220 --> 00:33:33,140 Quite frankly, scales and axes are some of the hardest parts to debug in D3, 700 00:33:33,140 --> 00:33:35,780 so don't feel bad if those aren't working quite the way 701 00:33:35,780 --> 00:33:37,380 you want them to right away. 702 00:33:37,380 --> 00:33:40,280 There's a lot of really great examples online. 703 00:33:40,280 --> 00:33:43,799 The linear scale is a little bit easier, where we've said, OK, all of the items 704 00:33:43,799 --> 00:33:45,590 that you're going to output are going to be 705 00:33:45,590 --> 00:33:50,870 in the range from the height minus the margin and all the way 706 00:33:50,870 --> 00:33:52,280 to the margin of the top. 707 00:33:52,280 --> 00:33:55,640 What's really important to note in terms of graphics 708 00:33:55,640 --> 00:34:00,590 is that, in fact, while your width actually moves in the direction 709 00:34:00,590 --> 00:34:03,710 that you expect it to, so like zero starting on the left hand 710 00:34:03,710 --> 00:34:06,590 side and the greater numbers moving to the right, 711 00:34:06,590 --> 00:34:07,980 height is a little bit different. 712 00:34:07,980 --> 00:34:10,040 In fact, the y-axis is inverted. 713 00:34:10,040 --> 00:34:15,110 So zero for the y-axis starts in the top left hand corner and moves down. 714 00:34:15,110 --> 00:34:19,639 So the greater values are actually further down within the graphic. 715 00:34:19,639 --> 00:34:20,810 Why did they do this? 716 00:34:20,810 --> 00:34:23,989 I'm not totally sure, but it can be a pain. 717 00:34:23,989 --> 00:34:28,219 As a result, you'll often find yourself reversing heights 718 00:34:28,219 --> 00:34:31,250 so that the values that you're getting out 719 00:34:31,250 --> 00:34:34,639 are actually corresponding not to the height itself, 720 00:34:34,639 --> 00:34:38,150 but the difference between the height that you've gotten for a bar 721 00:34:38,150 --> 00:34:41,719 and the total height of the visualization, which 722 00:34:41,719 --> 00:34:45,440 you can kind of see would correspond to the height of a bar 723 00:34:45,440 --> 00:34:48,290 that we would be thinking of. 724 00:34:48,290 --> 00:34:51,330 That's the only thing I want to note there. 725 00:34:51,330 --> 00:34:54,260 The other thing I'll note here is that I needed the y scale to know 726 00:34:54,260 --> 00:34:56,540 what its maximum value is going to be. 727 00:34:56,540 --> 00:35:00,320 And so as a result, D3 gives me a max function, 728 00:35:00,320 --> 00:35:03,860 which literally iterates through every single item in the count data. 729 00:35:03,860 --> 00:35:08,150 And it returns like an array basically of all of the values. 730 00:35:08,150 --> 00:35:10,412 And it picks the highest value. 731 00:35:10,412 --> 00:35:11,870 Could I have done this another way? 732 00:35:11,870 --> 00:35:12,980 Absolutely. 733 00:35:12,980 --> 00:35:17,196 But since D3 gives me these tools, you should absolutely use them. 734 00:35:17,196 --> 00:35:19,030 OK. 735 00:35:19,030 --> 00:35:21,550 The scales themselves actually take care of the math, 736 00:35:21,550 --> 00:35:24,730 but does not take care of any of the visuals that you see. 737 00:35:24,730 --> 00:35:29,760 And so as a result, we actually have to set up the visuals ourselves. 738 00:35:29,760 --> 00:35:33,820 Again, D3 gives you very easy methods for setting up axes, 739 00:35:33,820 --> 00:35:37,990 where if I want an axis on the left, I can literally just call axis left. 740 00:35:37,990 --> 00:35:42,280 If I want an axis on the bottom, I can go ahead and call axis on the bottom. 741 00:35:42,280 --> 00:35:45,706 It will then ask you, OK, what is the scaling I should use? 742 00:35:45,706 --> 00:35:47,830 And the nice thing is you can actually just pass it 743 00:35:47,830 --> 00:35:49,971 the new scale that you have just made. 744 00:35:49,971 --> 00:35:50,470 Right? 745 00:35:50,470 --> 00:35:51,980 So this is quick and easy. 746 00:35:51,980 --> 00:35:54,070 Once you've figured out the math for the scales, 747 00:35:54,070 --> 00:35:57,280 the rest kind of comes naturally. 748 00:35:57,280 --> 00:35:59,290 So we've said, OK, here's an object that is 749 00:35:59,290 --> 00:36:05,530 going to correspond to my axis bottom, but it's not yet on the SVG. 750 00:36:05,530 --> 00:36:09,280 And this is where we start to see this first instance of this method 751 00:36:09,280 --> 00:36:12,700 append, where append is going to say, OK, tell me 752 00:36:12,700 --> 00:36:15,430 exactly what I'm going to append. 753 00:36:15,430 --> 00:36:20,080 And when I append on that thing, tell me the attributes that it has to have. 754 00:36:20,080 --> 00:36:24,250 Again, by convention, we tend to append axes to G groups. 755 00:36:24,250 --> 00:36:28,540 The reason we do this is that if we ever want to add color to our axes, 756 00:36:28,540 --> 00:36:31,660 make things smaller on the axis, rotate the axis, 757 00:36:31,660 --> 00:36:34,060 it's much easier to do that within a G group 758 00:36:34,060 --> 00:36:37,600 than it is to actually try to find the pointer to the axis itself 759 00:36:37,600 --> 00:36:41,110 once it's already on the canvas. 760 00:36:41,110 --> 00:36:43,990 And there's this important method here specifically 761 00:36:43,990 --> 00:36:48,490 for axes named call, where in essence you've said, 762 00:36:48,490 --> 00:36:51,550 OK, I want you to append it to a G group. 763 00:36:51,550 --> 00:36:55,576 I want you to give it these classes so that I can style it later. 764 00:36:55,576 --> 00:37:00,910 And now I actually want you to call this method and make my axis. 765 00:37:00,910 --> 00:37:02,560 This takes care of everything for me. 766 00:37:02,560 --> 00:37:07,490 Once you've used this call operator, your axes just magically appear. 767 00:37:07,490 --> 00:37:08,650 OK. 768 00:37:08,650 --> 00:37:10,900 Same thing goes for the x-axis, where I've 769 00:37:10,900 --> 00:37:13,570 done a little bit of fancier things. 770 00:37:13,570 --> 00:37:16,570 One thing I do want to point out is that, in fact, everything 771 00:37:16,570 --> 00:37:20,440 wanted to start like a little funky looking 772 00:37:20,440 --> 00:37:23,392 where all of the names of the artists were actually horizontal. 773 00:37:23,392 --> 00:37:26,350 And because there were so many artists, it starts to look kind of ugly. 774 00:37:26,350 --> 00:37:26,980 Right? 775 00:37:26,980 --> 00:37:30,250 So D3 is also a lot about like playing around and figuring out 776 00:37:30,250 --> 00:37:33,640 how you can rotate things and shift things to make them look pretty. 777 00:37:33,640 --> 00:37:36,100 So, for example, if I wanted all of those artist names 778 00:37:36,100 --> 00:37:39,580 to be rotated 90 degrees from the horizontal 779 00:37:39,580 --> 00:37:42,040 so that they would look perpendicular to the axis, 780 00:37:42,040 --> 00:37:43,720 I can go ahead and set this to 90. 781 00:37:43,720 --> 00:37:47,470 And so we can see that that looks a little bit like that. 782 00:37:47,470 --> 00:37:50,781 I thought that this looked super ugly and was like hard to read. 783 00:37:50,781 --> 00:37:52,780 And I was hoping that this would be short enough 784 00:37:52,780 --> 00:37:55,090 to fit if I rotated it 75 degrees. 785 00:37:55,090 --> 00:37:58,090 Surprise, surprise, it was not. 786 00:37:58,090 --> 00:38:01,780 But aesthetically, I thought that 75 looked a little bit nicer. 787 00:38:01,780 --> 00:38:03,640 This is the only reason I've picked 75. 788 00:38:03,640 --> 00:38:06,260 This is purely an aesthetic choice. 789 00:38:06,260 --> 00:38:07,310 OK. 790 00:38:07,310 --> 00:38:08,870 So we've talked about the axis. 791 00:38:08,870 --> 00:38:10,670 We've talked about the scale. 792 00:38:10,670 --> 00:38:15,170 Once you've configured those, again, the rest is relatively easy. 793 00:38:15,170 --> 00:38:20,740 Before I move on to the bars themselves, questions about axes or scales? 794 00:38:20,740 --> 00:38:24,040 Because I think those are the harder things. 795 00:38:24,040 --> 00:38:26,530 But if you have no questions, that's also fine. 796 00:38:26,530 --> 00:38:27,030 Awesome. 797 00:38:27,030 --> 00:38:27,840 OK. 798 00:38:27,840 --> 00:38:28,590 Bars it is. 799 00:38:28,590 --> 00:38:30,990 So remember that I said the D3 kind of likes 800 00:38:30,990 --> 00:38:34,470 to break down what your visualization actually is. 801 00:38:34,470 --> 00:38:37,140 And so what these are just a bunch of rectangles. 802 00:38:37,140 --> 00:38:40,710 And so the thing that I'm actually going to append to my canvas 803 00:38:40,710 --> 00:38:43,200 are really just rectangles. 804 00:38:43,200 --> 00:38:47,190 When we're appending, let's call them like visualization items, 805 00:38:47,190 --> 00:38:53,670 there's this cycle that D3 likes to use, where it's the like enter, update, exit 806 00:38:53,670 --> 00:38:54,630 cycle. 807 00:38:54,630 --> 00:38:57,720 Where we've said, OK, here's the data you're going to use. 808 00:38:57,720 --> 00:38:59,160 Please enter it. 809 00:38:59,160 --> 00:39:03,000 This is sort of this like weird semantic thing that D3 has adopted, 810 00:39:03,000 --> 00:39:05,130 but it's very formulaic. 811 00:39:05,130 --> 00:39:07,590 And you don't really have to understand what it's doing 812 00:39:07,590 --> 00:39:09,370 as long as you remember the formula. 813 00:39:09,370 --> 00:39:12,390 And the formula is always here's the data I'm going to give you. 814 00:39:12,390 --> 00:39:17,280 Now enter into this state where we are going to manipulate this data. 815 00:39:17,280 --> 00:39:19,260 So I've said, OK, I have this data. 816 00:39:19,260 --> 00:39:20,920 I'm holding all of this data. 817 00:39:20,920 --> 00:39:24,040 And what I'm actually going to do is I'm going to append the rectangle. 818 00:39:24,040 --> 00:39:27,120 So you'll notice here that I actually have rectangle in two places. 819 00:39:27,120 --> 00:39:31,410 Select All is actually looking for pointers to rectangles, 820 00:39:31,410 --> 00:39:33,310 even if they don't exist. 821 00:39:33,310 --> 00:39:35,490 In fact, even if they don't exist, you still 822 00:39:35,490 --> 00:39:38,130 need to use Select All because what Select All will do 823 00:39:38,130 --> 00:39:42,000 is it will actually create pointers for things that don't exist, 824 00:39:42,000 --> 00:39:45,210 if your data calls for that. 825 00:39:45,210 --> 00:39:47,250 And because I have no rectangles, my data 826 00:39:47,250 --> 00:39:51,554 is obviously going to call for new rectangles to be made. 827 00:39:51,554 --> 00:39:54,220 So I'm going to say, OK, we're going to append these rectangles. 828 00:39:54,220 --> 00:39:57,360 And we're going to give them some attributes, like a class, a fill. 829 00:39:57,360 --> 00:39:59,820 And then things start to get a little bit funny 830 00:39:59,820 --> 00:40:03,450 where a lot of the things that we have to think about are 831 00:40:03,450 --> 00:40:06,150 how wide do my rectangles have to be? 832 00:40:06,150 --> 00:40:08,700 How tall do my rectangles have to be? 833 00:40:08,700 --> 00:40:11,910 And where do I start drawing my rectangles? 834 00:40:11,910 --> 00:40:16,590 Again, D3, and when it comes to graphics everything seems to do this, 835 00:40:16,590 --> 00:40:19,954 actually starts drawing from the top left hand corner. 836 00:40:19,954 --> 00:40:21,870 And so you have to say to yourself, OK, if I'm 837 00:40:21,870 --> 00:40:26,040 drawing from the top left hand corner, how far right do I have to draw? 838 00:40:26,040 --> 00:40:29,770 This is pretty easy because this axis moves in the direction we expect it to. 839 00:40:29,770 --> 00:40:32,880 But how far down I have to draw, remember that all of these values 840 00:40:32,880 --> 00:40:34,590 are actually inverted. 841 00:40:34,590 --> 00:40:37,590 So when I talk about width, in fact, I can just 842 00:40:37,590 --> 00:40:40,440 use this nice little method that comes right out 843 00:40:40,440 --> 00:40:45,270 of my scale, where my scale has already taken into account 844 00:40:45,270 --> 00:40:48,960 how many bars I'm going to need and what the spacing between the bars 845 00:40:48,960 --> 00:40:50,010 is going to be. 846 00:40:50,010 --> 00:40:53,010 And what the total width it has to work with is. 847 00:40:53,010 --> 00:40:55,140 And so as a result, it can very easily give me 848 00:40:55,140 --> 00:40:58,804 a calculation of how wide one particular bar has to be. 849 00:40:58,804 --> 00:41:00,720 And so I didn't even have to think about this. 850 00:41:00,720 --> 00:41:02,250 I could literally just say, hey, just tell me what 851 00:41:02,250 --> 00:41:04,350 the bandwidth is for a particular bar. 852 00:41:04,350 --> 00:41:05,700 Great. 853 00:41:05,700 --> 00:41:07,980 Height is the one that's a little bit funny, again, 854 00:41:07,980 --> 00:41:09,870 because we have to invert. 855 00:41:09,870 --> 00:41:12,600 So I said, OK, for every one of the pieces 856 00:41:12,600 --> 00:41:17,070 of data that you're going to get from this data that I've given you, 857 00:41:17,070 --> 00:41:20,830 please look at that data, look at its value, which, remember, 858 00:41:20,830 --> 00:41:23,100 corresponds to a count here. 859 00:41:23,100 --> 00:41:25,590 And I'm going to say, OK, I need to know what 860 00:41:25,590 --> 00:41:27,720 this is going to be in terms of pixels. 861 00:41:27,720 --> 00:41:31,600 In terms of pixels, it's going to be whatever the scale has told me it is. 862 00:41:31,600 --> 00:41:33,030 And now, I have to invert it. 863 00:41:33,030 --> 00:41:35,880 And the process of inverting it is really the same 864 00:41:35,880 --> 00:41:42,420 as subtracting this value from that minimum value at the top. 865 00:41:42,420 --> 00:41:44,820 Sometimes it's a little bit easier to visualize that, 866 00:41:44,820 --> 00:41:47,319 but just so that we can get through the rest of the example, 867 00:41:47,319 --> 00:41:50,550 I'm going to just let you guys figure that out, or look at examples. 868 00:41:50,550 --> 00:41:52,320 Again, very formulaic. 869 00:41:52,320 --> 00:41:55,380 Once you figure it out, it's pretty straightforward. 870 00:41:55,380 --> 00:41:59,157 On the other hand, if you ever do bar graphs where the bars go horizontally, 871 00:41:59,157 --> 00:42:00,240 you don't have to do this. 872 00:42:00,240 --> 00:42:03,337 You can actually just set a solid height for the bars. 873 00:42:03,337 --> 00:42:05,670 And you don't have to figure out any of the weird stuff. 874 00:42:05,670 --> 00:42:07,628 And then it's the width that's going to change. 875 00:42:07,628 --> 00:42:10,540 And that kind of comes naturally the more of these you make. 876 00:42:10,540 --> 00:42:12,225 So we've taken care of width. 877 00:42:12,225 --> 00:42:13,650 And we've taken care of height. 878 00:42:13,650 --> 00:42:15,570 The next question D3 is going to ask is it's 879 00:42:15,570 --> 00:42:18,240 going to say, OK, tell me the x and y position 880 00:42:18,240 --> 00:42:21,430 where I'm actually going to start drawing this bar. 881 00:42:21,430 --> 00:42:23,490 Remember that this y position is still going 882 00:42:23,490 --> 00:42:26,891 to have to correspond to whatever the scale has told me. 883 00:42:26,891 --> 00:42:27,390 Right? 884 00:42:27,390 --> 00:42:31,090 The scale is going to tell me relative to my axis, 885 00:42:31,090 --> 00:42:33,720 where does something with a count of three have to start. 886 00:42:33,720 --> 00:42:36,590 Where does something with a count of 21 have to start. 887 00:42:36,590 --> 00:42:39,450 And so, again, I let my scale handle all of this. 888 00:42:39,450 --> 00:42:43,080 Same thing goes for the x, where I've said, OK, the amount to the right 889 00:42:43,080 --> 00:42:45,810 that I have to shift within my canvas is really 890 00:42:45,810 --> 00:42:49,930 going to depend on every other piece of data that I already have. 891 00:42:49,930 --> 00:42:53,400 And so as a result, I, again, leave this to my scale to figure out. 892 00:42:53,400 --> 00:42:56,400 This math would be really hairy to figure out yourself. 893 00:42:56,400 --> 00:43:01,650 And so I cannot extol enough the virtues of the D3 scales. 894 00:43:01,650 --> 00:43:04,470 Notice here, again, that what I have said 895 00:43:04,470 --> 00:43:08,640 is actually, OK, actually this syntax is a little bit funny. 896 00:43:08,640 --> 00:43:11,460 You'll notice that I'm using this artist map again, 897 00:43:11,460 --> 00:43:14,220 which seems a little bit weird because we kind of already 898 00:43:14,220 --> 00:43:15,690 have this artist key. 899 00:43:15,690 --> 00:43:19,240 The reason I had to do it this way was the following. 900 00:43:19,240 --> 00:43:22,410 I said to my scale that the domain, meaning 901 00:43:22,410 --> 00:43:26,220 any of the inputs it was going to get, were actually going to be artist names. 902 00:43:26,220 --> 00:43:29,460 And so as a result, for a particular piece of data, 903 00:43:29,460 --> 00:43:32,730 rather than hand the scale an artist ID, which would come back 904 00:43:32,730 --> 00:43:42,630 undefined because this domain has no idea what a one corresponds to 905 00:43:42,630 --> 00:43:44,520 or what a three corresponds to. 906 00:43:44,520 --> 00:43:47,940 But it does know what an AC/DC corresponds to, 907 00:43:47,940 --> 00:43:50,040 or a Santana corresponds to. 908 00:43:50,040 --> 00:43:54,060 And so as a result, as I'm iterating through all of my data and count data 909 00:43:54,060 --> 00:44:00,060 making these bars, when I actually need to use my x ordinal scale to figure out 910 00:44:00,060 --> 00:44:05,750 the x position of my bars, I need to pass it a name and not just an ID. 911 00:44:05,750 --> 00:44:09,480 And so we're back to using this artist map. 912 00:44:09,480 --> 00:44:13,490 Finally, this is the last little mildly fancy thing, where you've said, 913 00:44:13,490 --> 00:44:15,680 OK, great, I've made this visualization. 914 00:44:15,680 --> 00:44:16,280 It's pretty. 915 00:44:16,280 --> 00:44:17,240 It sits there. 916 00:44:17,240 --> 00:44:21,350 But the whole idea behind 3D is to make things visual and interactive. 917 00:44:21,350 --> 00:44:23,570 And to make things interactive, you can actually 918 00:44:23,570 --> 00:44:28,430 start layering some of these JavaScript ideas, for example, listeners. 919 00:44:28,430 --> 00:44:32,480 In this case, we're going to say, OK, let's actually add a click listener. 920 00:44:32,480 --> 00:44:35,990 There are other listeners, like mouse over, mouse off. 921 00:44:35,990 --> 00:44:38,120 These are things that I highly recommend googling. 922 00:44:38,120 --> 00:44:40,760 But they work in kind of just the intuitive way 923 00:44:40,760 --> 00:44:44,660 that you might expect buttons to work with just regular JavaScript 924 00:44:44,660 --> 00:44:46,500 on a regular HTML page. 925 00:44:46,500 --> 00:44:50,990 Where I've said, OK, if someone ever clicks on a particular bar, 926 00:44:50,990 --> 00:44:54,890 please note that for that particular bar, 927 00:44:54,890 --> 00:45:00,080 I want you to get whatever is going to get returned from this function call. 928 00:45:00,080 --> 00:45:03,300 I could have written this entire function in here. 929 00:45:03,300 --> 00:45:06,350 But for the sake of clarity and segmenting, 930 00:45:06,350 --> 00:45:10,700 I made the decision to actually segment it away into another function, in case, 931 00:45:10,700 --> 00:45:13,220 for example, my application ever grew. 932 00:45:13,220 --> 00:45:15,770 And I wanted to use it on other places on the page. 933 00:45:15,770 --> 00:45:20,420 But notice what I've passed is the artist name, the artist ID, 934 00:45:20,420 --> 00:45:24,830 and the actual album data that I was dealing with there. 935 00:45:24,830 --> 00:45:27,530 And in fact, this is the entire data set. 936 00:45:27,530 --> 00:45:33,290 So to get that artist name, notice, again, that I'm using this artist map. 937 00:45:33,290 --> 00:45:34,614 Just worth noting. 938 00:45:34,614 --> 00:45:36,530 And basically, what we're going to say is, OK, 939 00:45:36,530 --> 00:45:40,700 every time someone clicks on this bar, go ahead and run this function. 940 00:45:40,700 --> 00:45:46,110 Up until this point, what we've done is literally just the following. 941 00:45:46,110 --> 00:45:46,610 Right? 942 00:45:46,610 --> 00:45:50,780 We've made axes such that they are calculated properly 943 00:45:50,780 --> 00:45:52,730 for the amount of data that we're going to do. 944 00:45:52,730 --> 00:45:53,390 Right? 945 00:45:53,390 --> 00:45:56,330 But in fact, the very first thing we did was load in this data 946 00:45:56,330 --> 00:45:59,000 and clean it in such a way that it was going to work 947 00:45:59,000 --> 00:46:00,680 with what we wanted to visualize. 948 00:46:00,680 --> 00:46:03,740 This included sorting the data. 949 00:46:03,740 --> 00:46:06,500 If this were a more fancy and real world data set, 950 00:46:06,500 --> 00:46:09,890 it might also include iterating through and taking care of anything 951 00:46:09,890 --> 00:46:11,521 like Nan values. 952 00:46:11,521 --> 00:46:12,020 Right? 953 00:46:12,020 --> 00:46:13,605 Where there literally is no value. 954 00:46:13,605 --> 00:46:15,980 These are things that you're going to have to think about 955 00:46:15,980 --> 00:46:17,582 as you're visualizing your data. 956 00:46:17,582 --> 00:46:19,040 How do you want to visualize a Nan? 957 00:46:19,040 --> 00:46:20,490 Do you want to visualize it as a zero? 958 00:46:20,490 --> 00:46:23,020 Or do you want to just literally cut it out of your data set? 959 00:46:23,020 --> 00:46:25,270 And these are kind of like big philosophical questions 960 00:46:25,270 --> 00:46:28,430 that are worth asking yourself as you visualize data. 961 00:46:28,430 --> 00:46:31,390 In addition to all of that, remember that I actually cut down our data 962 00:46:31,390 --> 00:46:34,280 set because I thought that fewer would be more interesting because it 963 00:46:34,280 --> 00:46:36,222 would be easier to read. 964 00:46:36,222 --> 00:46:38,180 And then keep in mind that we did a lot of math 965 00:46:38,180 --> 00:46:43,160 to actually handle making the axes in addition to then drawing 966 00:46:43,160 --> 00:46:45,740 the axes onto the canvas. 967 00:46:45,740 --> 00:46:49,430 That final thing we did is actually dictating 968 00:46:49,430 --> 00:46:51,140 a lot of what is happening over here. 969 00:46:51,140 --> 00:46:54,620 Remember that JavaScript, one of its primary objectives in life 970 00:46:54,620 --> 00:46:56,720 is to change the DOM. 971 00:46:56,720 --> 00:46:59,930 And so, in fact, what's happening here is that every time I click, 972 00:46:59,930 --> 00:47:02,930 I am actually appending new information to a div 973 00:47:02,930 --> 00:47:05,420 that I had already set up over here. 974 00:47:05,420 --> 00:47:10,400 If you're curious to see this in the Inspector, 975 00:47:10,400 --> 00:47:15,202 you can remember that I had this just empty div with the ID albums. 976 00:47:15,202 --> 00:47:18,410 And in fact, what that little function that I'm going to show you in a second 977 00:47:18,410 --> 00:47:22,550 is going to do is it's going to find that div and append to it 978 00:47:22,550 --> 00:47:23,872 an unordered list. 979 00:47:23,872 --> 00:47:25,580 And what this is going to end up doing is 980 00:47:25,580 --> 00:47:28,610 showing us more interesting information about the data 981 00:47:28,610 --> 00:47:31,790 that we've interacted with from the bar graph. 982 00:47:31,790 --> 00:47:34,310 So to see what that looks like, pretty quickly, 983 00:47:34,310 --> 00:47:36,980 here's our just normal querySelector where I've said, 984 00:47:36,980 --> 00:47:40,610 OK, find me this thing called the artist span. 985 00:47:40,610 --> 00:47:42,740 For reference, again, if we go back to index, 986 00:47:42,740 --> 00:47:47,780 we'll see that, in fact, I wanted some nice way to put the name of the artist 987 00:47:47,780 --> 00:47:49,670 actually within this header. 988 00:47:49,670 --> 00:47:52,820 So within this entire H3, I used a little trick 989 00:47:52,820 --> 00:47:55,970 where I said, OK, I'm going to include a span, which is really 990 00:47:55,970 --> 00:47:59,090 just an empty space in the HTML into which you can then 991 00:47:59,090 --> 00:48:01,760 put other pieces of HTML. 992 00:48:01,760 --> 00:48:03,800 In this case, I gave that span an ID. 993 00:48:03,800 --> 00:48:08,840 But notice that there's nothing in the span, at least not at the beginning. 994 00:48:08,840 --> 00:48:11,060 And again, I'll just point your attention 995 00:48:11,060 --> 00:48:14,630 to this empty div with the ID albums. 996 00:48:14,630 --> 00:48:16,820 If we go back to Main, notice that I said, 997 00:48:16,820 --> 00:48:19,880 OK, I'm going to select that span. 998 00:48:19,880 --> 00:48:22,910 And within its inner HTML, I'm going to go ahead and just append 999 00:48:22,910 --> 00:48:24,200 that artist name. 1000 00:48:24,200 --> 00:48:27,770 And that is literally what is dictating something like Pearl Jam appearing 1001 00:48:27,770 --> 00:48:30,920 here, or Santana appearing here. 1002 00:48:30,920 --> 00:48:35,087 The unordered list is a little bit more complicated, but only slightly so, 1003 00:48:35,087 --> 00:48:36,920 where you can imagine that really what I was 1004 00:48:36,920 --> 00:48:39,030 doing as I was making this was I was saying, 1005 00:48:39,030 --> 00:48:42,520 OK, I know I need to start an unordered list tag. 1006 00:48:42,520 --> 00:48:45,380 And I need to end an unordered list tag. 1007 00:48:45,380 --> 00:48:49,700 And in fact, you'll notice here that I didn't even close the unordered list. 1008 00:48:49,700 --> 00:48:51,530 In fact, Chrome and HTML were smart enough 1009 00:48:51,530 --> 00:48:55,940 to know that if I opened an unordered list, it should probably close it. 1010 00:48:55,940 --> 00:49:01,430 But to be a little bit more precise in what we're doing, you can go ahead 1011 00:49:01,430 --> 00:49:08,799 and actually just close that tag just to kind of tie up loose ends. 1012 00:49:08,799 --> 00:49:11,090 But you'll notice that I said, OK, I'm going to iterate 1013 00:49:11,090 --> 00:49:12,990 through each one of the albums. 1014 00:49:12,990 --> 00:49:16,730 And I'm going to say, OK, if the album that I'm holding right now, 1015 00:49:16,730 --> 00:49:21,830 if that artist ID matches the ID of the thing that was clicked on, 1016 00:49:21,830 --> 00:49:23,840 I'm going to consider this a match. 1017 00:49:23,840 --> 00:49:27,350 And as a result, I'm going to say, OK, this album, 1018 00:49:27,350 --> 00:49:31,460 this title actually corresponded to the artist that my user clicked on. 1019 00:49:31,460 --> 00:49:35,300 And so I'm going to append it to this growing string of HTML, 1020 00:49:35,300 --> 00:49:37,850 which I can then display later. 1021 00:49:37,850 --> 00:49:40,460 If I console logged this UL list for you, 1022 00:49:40,460 --> 00:49:43,910 you would see that it's really just an ugly string of HTML. 1023 00:49:43,910 --> 00:49:48,500 It has two UL tags on the outside and a bunch of LIs on the inside, 1024 00:49:48,500 --> 00:49:52,670 where the thing within the LI is really just this album title. 1025 00:49:52,670 --> 00:49:57,140 Notice that I'm using this JavaScript string concatenation operator. 1026 00:49:57,140 --> 00:50:01,742 And in fact, I like it a lot because you can do really fancy things with it. 1027 00:50:01,742 --> 00:50:04,700 And finally, what I said is, OK, I've iterated through all of the data. 1028 00:50:04,700 --> 00:50:06,200 I've made this new string. 1029 00:50:06,200 --> 00:50:07,700 Let's go ahead and display it. 1030 00:50:07,700 --> 00:50:12,710 And to do that, I select that div again using its ID, which was albums. 1031 00:50:12,710 --> 00:50:14,810 I go ahead and say, OK, it's inner HTML is now 1032 00:50:14,810 --> 00:50:18,620 going to equal that ridiculous string that I just made. 1033 00:50:18,620 --> 00:50:22,790 And you'll notice that if we then actually inspected 1034 00:50:22,790 --> 00:50:28,450 this element, what we have done is we've inputted this entire string here. 1035 00:50:28,450 --> 00:50:32,440 And that is how we went ahead and made a very simple visualization. 1036 00:50:32,440 --> 00:50:34,690 Are there fancier things you can do with D3? 1037 00:50:34,690 --> 00:50:35,860 Absolutely. 1038 00:50:35,860 --> 00:50:37,300 You can do brushing. 1039 00:50:37,300 --> 00:50:38,860 You can do filtering. 1040 00:50:38,860 --> 00:50:41,860 You can make your visualizations move in cool ways 1041 00:50:41,860 --> 00:50:47,230 depending on what your user has decided to input in terms of parameters. 1042 00:50:47,230 --> 00:50:49,270 Because this is just a quick demonstration, 1043 00:50:49,270 --> 00:50:51,186 I didn't want to go through all of that today. 1044 00:50:51,186 --> 00:50:56,140 But, again, I highly recommend checking out some of the examples online. 1045 00:50:56,140 --> 00:50:58,400 And with that, I think I'm going to wrap up. 1046 00:50:58,400 --> 00:51:01,980 If there's any questions, I'm happy to take them. 1047 00:51:01,980 --> 00:51:02,582 Yeah? 1048 00:51:02,582 --> 00:51:08,790 AUDIENCE: [INAUDIBLE] that you were to do something like animate the bars 1049 00:51:08,790 --> 00:51:14,085 so that they rise up [INAUDIBLE],, or something 1050 00:51:14,085 --> 00:51:18,099 like turning the bars into points instead of bars. 1051 00:51:18,099 --> 00:51:18,890 ATHENA BRAUN: Yeah. 1052 00:51:18,890 --> 00:51:20,015 So that's a great question. 1053 00:51:20,015 --> 00:51:23,300 So the question here was how easy would it be to animate the bars? 1054 00:51:23,300 --> 00:51:26,600 Or how easy would it be to make these more like circles instead 1055 00:51:26,600 --> 00:51:29,180 of actual bars? 1056 00:51:29,180 --> 00:51:31,070 So those are kind of two separate questions. 1057 00:51:31,070 --> 00:51:37,390 In terms of the animation itself, what you can do is there is actually a D3-- 1058 00:51:37,390 --> 00:51:39,582 1059 00:51:39,582 --> 00:51:40,790 I don't know what to call it. 1060 00:51:40,790 --> 00:51:43,250 I guess it's part of the chain called Transform. 1061 00:51:43,250 --> 00:51:45,250 So you would say like dot transform. 1062 00:51:45,250 --> 00:51:47,630 And what the transformation would do is it would actually 1063 00:51:47,630 --> 00:51:48,907 animate things for you. 1064 00:51:48,907 --> 00:51:50,990 Sometimes the transformations are a little finicky 1065 00:51:50,990 --> 00:51:55,020 because you have to put them in like exactly the right place. 1066 00:51:55,020 --> 00:51:58,570 And so what I would recommend doing for that is looking up examples. 1067 00:51:58,570 --> 00:52:01,070 I could probably guess it where it's supposed to go in this, 1068 00:52:01,070 --> 00:52:04,462 but I don't want to do that, because that's going to be messy. 1069 00:52:04,462 --> 00:52:06,170 On the other hand, how easy is it to make 1070 00:52:06,170 --> 00:52:07,850 these points instead of rectangles? 1071 00:52:07,850 --> 00:52:09,010 Super easy. 1072 00:52:09,010 --> 00:52:11,790 Where if you think about it, a point is really just a circle. 1073 00:52:11,790 --> 00:52:14,960 So instead of appending rectangles, what instead I could have done 1074 00:52:14,960 --> 00:52:15,870 was appended circles. 1075 00:52:15,870 --> 00:52:18,500 So I literally would just change this to circle. 1076 00:52:18,500 --> 00:52:22,440 But unlike rectangles, circles actually now we 1077 00:52:22,440 --> 00:52:25,370 need to have an idea of where it's center point is going to be. 1078 00:52:25,370 --> 00:52:28,100 And it has to have an idea of what its radius is going to be. 1079 00:52:28,100 --> 00:52:31,395 And the idea here is very similar to what you're doing with the scales 1080 00:52:31,395 --> 00:52:33,770 where you just need to configure your scales a little bit 1081 00:52:33,770 --> 00:52:37,040 differently to give you that point that you want. 1082 00:52:37,040 --> 00:52:39,500 But otherwise, it's actually fairly simple. 1083 00:52:39,500 --> 00:52:42,500 And again, great examples online. 1084 00:52:42,500 --> 00:52:44,260 Yeah. 1085 00:52:44,260 --> 00:52:44,984 All right. 1086 00:52:44,984 --> 00:52:47,400 Well, if there's no other questions, I'm going to wrap up. 1087 00:52:47,400 --> 00:52:49,320 I will gladly send this code. 1088 00:52:49,320 --> 00:52:50,790 Thanks so much for coming. 1089 00:52:50,790 --> 00:52:54,380 And this was CS50 question mark. 1090 00:52:54,380 --> 00:52:56,210