Draw Axes, Gridlines, and Labels With Svelte + D3.js

Using Svelte and D3 to draw axes, gridlines, and labels

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Better Data Visualizations with Svelte course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Better Data Visualizations with Svelte, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Better Data Visualizations with Svelte
  • [00:00 - 00:15] Hey everyone, in this lesson we're going to be adding peripheral elements to our chart. So although we have the series of circles, and they are positioned according to real data, there's no context around these circles, right?

    [00:16 - 00:30] Without axes, for example, the viewer can't really see what any of these values mean. And so an integral part of any chart, but especially the scatter plot, are going to be peripheral elements like axes with ticks and grid lines and axes titles.

    [00:31 - 00:51] So in this lesson, we're going to be building those from scratch using more SVG elements, in particular the text element and the line element. And by the end of this lesson, we're going to have really nice looking peripheral elements, some axes that look like this.

    [00:52 - 00:59] So there's a lot to look forward to, let's go ahead and get into it. So first, let's start by asking where we left off, right?

    [01:00 - 01:10] We have all of these circles and the grade of each student is on the x-axis. And the number of hours studied by each student is on the y-axis.

    [01:11 - 01:22] So let's start off by constructing an x-axis, meaning the horizontal axis down here. Now if you're to envision what an x-axis looks like, it's basically meant to provide context on the horizontal dimension.

    [01:23 - 01:40] So with this being 0 and this being 100, because this is the percent scored on a final exam, and then any number of ticks in between 0 and 100 for baseline reference for the viewer. So to summarize, we're going to be creating a line down here that has multiple ticks.

    [01:41 - 01:53] Maybe we'll do 0, 25, 50, 75, and 100 to provide guidance to the viewer. Now in order to do this, we're going to use what is called a component.

    [01:54 - 02:05] Now a quick lesson into the Svelte internals and how Svelte works behind the scenes, we don't want all of our code to live in one file, right? We don't want all of our code to live in app.svelte.

    [02:06 - 02:15] Because if we did that, this file would become incredibly long, right? It would be maybe a thousand lines of code and all of those lines of code might be serving very different purposes.

    [02:16 - 02:35] And so what's a lot more intuitive than one lengthy 1000 line file is splitting up our code into character, characteristically distinct chunks of code in what we call components, and then importing and placing those components within our markup in app.svelte . So that's a lot of theory.

    [02:36 - 02:50] Let's do it in practice because I think it illustrates pretty easily what I'm talking about. We begin by importing an access and we'll write the following code import and the name of whatever we want this component to be.

    [02:51 - 03:00] In our case, we want it to be access X and then the path where we can find that file. So here the auto complete is actually getting it right.

    [03:01 - 03:13] It's going to be dollar sign components slash access X dot Svelte, where this is the path and the file name that we want to import this from. So if you save this, you'll see an error.

    [03:14 - 03:21] And the reason for that is because access X does not exist here, right? So if I save this and go into the console, you'll see failed to reload.

    [03:22 - 03:31] This could be due to syntax errors or importing non-existent modules. Indeed it is because components slash access X does not exist.

    [03:32 - 03:41] What I want you to do is over in your components folder, right click and click new file. Or if you want, you can click the components folder and then click this new file icon up here.

    [03:42 - 03:52] Either way, it's going to open up this interface where we can create a new file and we're going to call it access X dot Selt. Now by default, this is going to be blank.

    [03:53 - 04:04] But what I want you to start off by doing is just create a text element and give it an X of 100 and a Y of 100. And then let's put hello world inside of it.

    [04:05 - 04:07] Okay. So default, nothing shows up.

    [04:08 - 04:13] And the reason for that is although we've imported access X, its value is never read. Quote unquote.

    [04:14 - 04:25] And what that really means is that we're never using this anywhere in our markup. And so this component, although it contains a text element needs to be injected inside of our existing markup.

    [04:26 - 04:42] And so we actually just use this kind of HTML slash XML type appearance where we'll do opening a bracket, access X and then closing bracket. And this, once you save and refresh, you'll see the text element does in fact render.

    [04:43 - 05:01] And so just to clarify what's happening here, right? Access X dot S felt is very similar to app dots felt in that it's a S felt file that's going to contain a script tag where you might remember is where logic lives, some markup, which is this, and maybe some styles, which is where your CSS will live.

    [05:02 - 05:24] And once we create all this in its own file, we can then import it as we do on line 18 and inject it as we do on line 22, which allows for a more maintainable, more readable code base that you will thank yourself for in the future as you don't have to scroll through 1000 lines of code. So we now have an X axis, which is very exciting.

    [05:25 - 05:29] But the problem is it's currently just hello world. And we actually want it to be some data.

    [05:30 - 05:40] So let's begin by defining what we actually want our ticks to be in our X axis. And to solve this in our script tag, we can define a new variable called X ticks.

    [05:41 - 05:58] Now because we're going between zero and 100, as that's the scale for grades, let's just do zero 100 and then a few values in between, we can do zero, 25, 50, 75, and 100. Now if you hit save, nothing's going to change because we're not using this.

    [05:59 - 06:08] And your question now might be, how do I use X ticks within my markup? Well, if you recall from app.s felt, there's this very handy tool called the each block.

    [06:09 - 06:22] And that's exactly what we're going to use to render our ticks. So rather than this single text element, let's replace that within each block, where we iterate through each X ticks, and we call them tick.

    [06:23 - 06:42] And then within this each block, for each of the five ticks, we want to render one thing, which is going to be a text element. Now for now, we can just make the exposition of each of these ticks tick the Y position zero and then add the tick as the actual rendered value.

    [06:43 - 06:54] And if we write this and click save, you'll notice you can't actually see anything. But if we inspect element and look at the markup, you actually will see these elements exist.

    [06:55 - 07:00] The problem is they're just off the screen because they have a Y value of zero. So let's make that 100.

    [07:01 - 07:08] And now you can start to see each of our values, which is exactly what we wanted to see. Okay.

    [07:09 - 07:12] The problem is we don't want these at 100. We want them at the bottom of our chart.

    [07:13 - 07:23] And we also don't want them scaled literally, right, with their raw values. We want them scaled using the existing X scale that we've already created in app.s felt.

    [07:24 - 07:31] Okay. And so in order to achieve this, we need to do what's called importing new props.

    [07:32 - 07:41] Okay. And props, which is short for properties, are basically how we pass information from this file app.s felt into access X.s felt.

    [07:42 - 07:50] So that X scale that exists here can also be referenced and understood in access X.s felt. Okay.

    [07:51 - 08:01] So here's the syntax for how you use components or properties in felt props, right? What we'll do is we'll say X scale equals X scale.

    [08:02 - 08:11] And because these are the same name, actually, we can just delete this declaration and just reference X scale directly, right? Now we have X scale.

    [08:12 - 08:28] And in order to accept it in access X.s felt, there's a bit of a confusing syntax that you're going to get headaches over at first, but it will become second nature to you soon, which is export, let, and then the name of that prop. So here, the name is in fact, X scale.

    [08:29 - 08:40] And if I go ahead and console dot log X scale. And then I fix my typo, you'll see that X scale does in fact exist in access X.

    [08:41 - 08:52] s felt. And so to clarify, one more time, what's happening, we're passing X scale. This right here, a function into access X as a prop to accept it.

    [08:53 - 09:06] We're writing export, let X scale, which now makes it usable within access X dot felt. So in order to use this, we just need to scale these raw values, 0, 25, 50, 75, and 100.

    [09:07 - 09:18] So instead of the X value being 100, it's X scale of 100, which you might remember is 400. Let's go ahead and type X scale and then open and close around tick and click save.

    [09:19 - 09:29] And now you see zero, 25, 50, 75, and 100 are positioned according to their scaled values. So this is really good progress.

    [09:30 - 09:48] And now we want to do the exact same thing for our height, because we don't want these to be at the 100 position, we want them to be at the bottom of the chart, right ? So let's go back into access X dot felt and pass height as a property, which we 're able to do like this, because it has the same name as the value that we're referencing.

    [09:49 - 10:03] So we'll save this, go back over to access X and export, let height. Now we can go ahead and push this access down according to the height of the chart.

    [10:04 - 10:15] Now one way we could do this would be like so, where now you see these are at the bottom. But a safer way to do this is actually to translate the entire chart element so that all of the ticks are pushed down at once.

    [10:16 - 10:21] Now what does that mean? Let's get a brief introduction to the transform property.

    [10:22 - 10:31] Okay. And so you can see I've wrote a little bit about it here, where we can use this syntax, transform, translate XY to apply a shift to an element.

    [10:32 - 10:46] So if we do a transform of zero comma 20, our pixels would shift down 20 pixels and to the left or to the right zero pixels. So there's some documentation for transform, translate, which you can read here .

    [10:47 - 10:55] You might notice it's a very powerful property with different rotations, translations, skews and scales. But in our case, the translation is going to be pretty simple.

    [10:56 - 11:08] And another note is in order to transform slash translate all of these elements at once, we need to wrap them in a G container. Now the question is what is a G and SVG?

    [11:09 - 11:17] And all you really have to think of in this context, a G element is a grouping element. It itself has no visual properties.

    [11:18 - 11:33] You can't see a G element, but it will apply its relevant transforms and its classes or whatever else to all of its children as well. So a G with this transform will push down all of the ticks all at once to make for easy transformations.

    [11:34 - 11:53] So with that in mind, let's wrap our axis in a G element, give it a class of X axis. And then let's apply that transform that we just talked about where we'll give it a transform of what it actually has written as perfect, translate of zero comma height.

    [11:54 - 12:08] So there's many ways that you could write this in Svelte. Maybe the easiest way is like so, where we write it with regular quotation marks and then we render the variable in these mustache braces.

    [12:09 - 12:15] So you'll notice the syntax highlighting suggests that this is in fact properly written. The comma is optional.

    [12:16 - 12:28] Technically, I think it's better practice to not use it, but really it doesn't matter if you want to use the comma between the X transformation and the Y transformation in my understanding. So G was left open because I haven't closed it.

    [12:29 - 12:38] So let's close it around the each block and click save. Now you'll notice that each of these Y ticks has, or each of these X ticks has a Y value of zero, right?

    [12:39 - 12:50] But they're all pushed down because of this transform translate. So just to illustrate this one more time, if I push this 200 pixels to the left , everything would shift 200 pixels to the left.

    [12:51 - 12:58] So I hope that illustrates both what a G element is and what a transform translate is as well. Okay.

    [12:59 - 13:04] So we made really good progress in that we have five ticks at the bottom of our chart. They're all visible.

    [13:05 - 13:12] Let's go ahead and add a percent sign. So it's obvious that these reference percents and we're getting a pretty good axis near the bottom.

    [13:13 - 13:23] The only thing we need to do now is add tick lines. And in order to do this, we actually want to add what's called a line element, which looks like this.

    [13:24 - 13:41] But instead of, you know, creating another line element and giving it the same X position as our text element, instead of duplicating that code, let's actually position both this line and this text element in a single G tag. So again, G is just a grouping tag.

    [13:42 - 13:51] And this is going to represent an individual tick, which you can designate with this class tick or you can call it whatever you want. But that's what this represents is in fact a tick.

    [13:52 - 14:05] Now instead of using X and Y, we can keep the X to a zero because we're going to transform slash translate the entire G grouping element. So let's apply another transform.

    [14:06 - 14:11] And this time, what do we want to translate? We want to translate it horizontally rather than vertically.

    [14:12 - 14:21] So we'll translate the X scale of tick on the horizontal axis and then give it no vertical transformation. So we'll do X scale of tick.

    [14:22 - 14:33] And remember, we're just moving this value from this zero or from this text element up to this transform. And then we'll add a vertical transformation of zero.

    [14:34 - 14:41] We'll then close this G element around the text and save. And again, you'll notice nothing visibly changes, which is what we want.

    [14:42 - 14:51] But now instead of a bunch of text elements, you're seeing mini G elements nested within the parent axis. And within that G element is a text element.

    [14:52 - 15:03] So using this principle, we can now create lines. And remember, the point is to create little ticks that give context as to what these text elements are in fact referencing.

    [15:04 - 15:10] So let's go ahead and create a line. And let's just give it an X one of zero and X two of zero.

    [15:11 - 15:23] A Y one of zero and a Y two of six. And the reason for this is because we want the line to be positioned at the exact same starting and ending point on the horizontal axis.

    [15:24 - 15:30] And we want to start up position zero and go upward six pixels. So let's go ahead and add a nice little stroke.

    [15:31 - 15:41] You could make it black for now if you wanted, but I'm going to type this long string, which gives it a really nice faint gray color. And let's save that.

    [15:42 - 15:48] We'll make the self closing because it opens and closes. And now the question is where are our lines?

    [15:49 - 15:58] The answer is they're below our chart and they're not yet visible. So this isn't perfect because we want to see the ticks themselves.

    [15:59 - 16:04] We can get into the best way to fix that here in a second. For now, we know that we have tick labels.

    [16:05 - 16:17] We know that we have text and everything is looking quite nice. Let's also move our text elements down a bit so they're closer to the ticks that are referencing them.

    [16:18 - 16:34] Now, if we really want these text elements under our ticks, which I know you can't see right now, but I promise they are in fact there, which you can verify by clicking into an individual tick. If we want these to be under the line elements, we're going to use two new properties.

    [16:35 - 16:50] This is going to be the dy property and the dominant baseline property. So we're going to be using these two to basically push our text elements directly under the lines that we've created up here.

    [16:51 - 17:02] So the first thing that we'll use is the dy property, which can effectively be thought of as a nudge on the vertical dimension. A dx would be a nudge on the horizontal dimension and dy is for vertical.

    [17:03 - 17:09] So although this is six pixels down, we also want it to be nudged. We'll say nine pixels down.

    [17:10 - 17:21] So if we save this, you're going to now see that our text elements are not in fact visible, which don't fret. This is just because we haven't added chart margin yet, which we will soon for now.

    [17:22 - 17:33] Let's just go ahead and make sure that we can see this by replacing the declaration of height in our transform with 300. And now we can actually see each of our individual text elements.

    [17:34 - 17:39] Okay, we will undo that just to be clear, but for now we're going to do it so we can actually see. So what do we have here, right?

    [17:40 - 17:58] We have a tick with a line and then a text element directly below it, but it's still kind of hugging the tick a little too closely. So we could increase our dy until we're satisfied, but a safer way to approach this problem is to use what's called the dominant baseline property.

    [17:59 - 18:09] And the dominant baseline property controls text alignment on the vertical axis . So you may be used to text align left, center and right, which is on the horizontal dimension.

    [18:10 - 18:23] Dominant baseline is going to determine where the text is positioned vertically . And so we're going to want to use a dominant baseline of middle, which will basically position this in the middle of the box that it's currently occupying.

    [18:24 - 18:33] And this is a good practice as you're positioning like axes, for examples, is to play around different dominant baselines to find the right alignment. So we'll do dominant baseline.

    [18:34 - 18:41] And then in quotation marks, we'll write middle and we'll save. And I use you this really nice alignment of these elements.

    [18:42 - 18:44] But you might not like this. There's this left alignment problem, right?

    [18:45 - 18:58] So horizontally, they start where the tick ends. And the way that we can approach this in SVG and then consequently in our spell application is another property this time called text anchor.

    [18:59 - 19:10] And so we're also going to want to apply a middle text anchor, which will center this text horizontally as well as vertically from dominant baseline. We'll save this and now look how nice our ticks look.

    [19:11 - 19:21] They are positioned cleanly directly next to the ticks themselves. So let's move this back down to 400 to our height.

    [19:22 - 19:31] And I know we won't be able to see it, but we'll solve that soon. For now, let's go ahead and move back in to the other axis, which is going to be the y-axis.

    [19:32 - 19:38] Now recall that the x-axis, which we just created, is referencing grades, right ? 0 to 100.

    [19:39 - 19:48] The y-axis references hours studied for the final exam in our theoretical classroom. We'll follow the exact same structure as our x-axis in a lot of ways.

    [19:49 - 20:01] We'll import axis y from this file path, which looks for axis y dots felt in our components folder. We'll create a new component and call it axis y dots felt.

    [20:02 - 20:15] And then we will make sure that we actually create it by writing axis y, opening and closing it. So now we have a component, but again, you know, the main issue here is going to be that there's nothing actually rendering.

    [20:16 - 20:24] You might remember that we can render a text element if we wanted with an x and a y value, as we did last time. But of course, we don't want to do that.

    [20:25 - 20:34] We want to render multiple ticks on the left side of our chart, ranging from zero to minimum, to whatever this person scored, right? The maximum in our data.

    [20:35 - 20:44] So let's go ahead and import rather than x scale and height. Let's go ahead and import y scale, which we could do like so.

    [20:45 - 21:01] Or we could just skip the equal sign like we did last time. Now we can accept it in axis y dots felt with the following code, export let y scale, and confirm that it does in fact exists by writing console log of y scale.

    [21:02 - 21:10] Now if I go to my console, I see it does in fact exist. Now for our x axis, it was easy to think of what the ticks would be, right?

    [21:11 - 21:31] You might recall that we did x ticks as zero, 25, 50, 75, and 100, because it's a pretty normal baseline for grades in most school systems. But the y scale is a bit more difficult because unless you're looking closely at the data right here, you might not see what the highest number of hours studied is.

    [21:32 - 21:43] And so what we actually want to do is use the existing y scale to find the ticks that we want to render. And so there's this really cool method within the y scale function that we have .

    [21:44 - 21:54] You see all of these are methods clamp, copy, domain, invert. And there's one in particular called ticks, which is what we want to use to render our y ticks.

    [21:55 - 22:09] So rather than hard coding the ticks that we want to use as we did an x scale, let's write the following. Let y ticks equal y scale dot ticks in the number of ticks roughly that we want to see.

    [22:10 - 22:12] And let's say it's five. Let's save this.

    [22:13 - 22:23] And now let's console dot log y ticks and see what it spits up. It spits out an array of seven values, zero, 10, 20, 30, 40, 50, and 60.

    [22:24 - 22:28] And we said five, but it gave us seven. And that's because the ticks method is not 100% accurate.

    [22:29 - 22:36] It's going to try its hardest to return a nice looking scale, but it might not be exactly the number that you provide. I want slightly fewer.

    [22:37 - 22:43] So I'm going to do four and see what it returns. Now it returns an array of length four, zero, 20, 40, and 60.

    [22:44 - 22:53] Well, this seems like a pretty good set of ticks to me. So I'm going to use the exact same code as I did in my x axis to render these ticks.

    [22:54 - 23:19] I'm going to position each y tick as a tick and for each of those ticks, I'm going to render for now a text element at the zero position on the x axis, right, the left most side of the chart and position it according to the data. Sorry, why according to the data for its y position.

    [23:20 - 23:26] Now let's just render the tick text and close our each block and see what we see. Already we're starting to see what we want.

    [23:27 - 23:39] Zero, 20, 40, and 60, which you can't see yet, but I promise it is in fact there. But rather than render these text elements alone, we also want lines.

    [23:40 - 23:49] So let's create G elements just like we did last time. And instead of x of zero and y of y scale, let's make this a y of zero.

    [23:50 - 23:59] I'm going to use the correct quotation marks and then apply a transform translate here. So transform, translate.

    [24:00 - 24:13] Now remember that these are all positioned at the zero position on the x axis, but on the y axis they're positioned according to their y scale of their tick. Let's close that, close the translation, click save.

    [24:14 - 24:26] You'll notice that it looks identical as it should. And while we're here, let's wrap the entire thing in a G element as well so that we can transform or do whatever we need to in the future.

    [24:27 - 24:32] Now we have a pretty functional axis, but we also want lines, right? We don't just want text.

    [24:33 - 24:40] Really nice charts will have these horizontal lines that span the entire chart. So let's get started by writing this and see what we need.

    [24:41 - 24:47] We know that the x1 should be zero because it starts at the leftmost side of our chart. We know that the y is being handled by this translation.

    [24:48 - 24:57] So actually the y1 and the y2 are just zero. But the x2 is an interesting problem because we want it to span from the start of the chart to the very end.

    [24:58 - 25:05] And the question is, what is the end of the chart? Well, those astute among you may know that the end of the chart is the width.

    [25:06 - 25:16] So let's import that as a prop into our axis y. Again, we'll write width, click save, and then accept it using export let width .

    [25:17 - 25:27] And now we can use this as the x2 property in our axis. Now maybe we want to add a nice little stroke to this.

    [25:28 - 25:36] You could do this HSLA string or you could call it black, whatever you want, this is up to you. I'm going to use this nice gray and click save.

    [25:37 - 25:43] And now you see lines under each of our text elements. So we have done a lot so far.

    [25:44 - 25:48] And we still have more. This is a long lesson because peripheral elements are tricky.

    [25:49 - 26:03] But before we move on to the next step of this lesson, which is going to be the margin object, let's review what we've created. And we'll do this by looking at the markup rather than using our words, we'll look at our output so we can really see what we've done.

    [26:04 - 26:12] We have an SVG element with the width and height of 400. Within that SVG element, we have two axes, axis x and axis y.

    [26:13 - 26:18] Then we have all of our circles, right? Axis x is at the very bottom of our chart.

    [26:19 - 26:27] It's so low that we can't even see it right now. And within that axis, there are a series of ticks, each with their own tick mark and their own text element.

    [26:28 - 26:33] So we've done that on the x axis. We've also done it on the y axis, which we thankfully can see.

    [26:34 - 26:45] We have created four ticks at 0, 20, 40 and 60, which you can't see. Each of those ticks having a line spanning the entire chart and a text element.

    [26:46 - 26:57] And now that we know what we've done, we know that we've created these beautiful peripheral elements, it would be a disservice to not show them. So let's make sure that we can actually see our x axis.

    [26:58 - 27:09] And the way that we're going to do this is by adding what's called margin. Now this visual from Amelia Watt and Berger does a really good example of showing what it means to add margin to our chart, right?

    [27:10 - 27:16] So basically, you can think of your chart in a few different rectangles. The outermost rectangle can be thought of as the wrapper of the chart.

    [27:17 - 27:27] This is everything, including the peripheral elements. And the inside, the smallest part of your chart is this green rectangle, everything living within the chart bounds, right?

    [27:28 - 27:42] But the difference between this green rectangle and this orange wrapper are what we call the margins, where we basically predefined space on the left, on the top, on the bottom, and on the right. And in that space is where we want to render our peripheral elements.

    [27:43 - 28:03] So if we had a really long strings, for example, we could create a sufficient margin to render those strings and have them visible on the screen and shrink our inner chart, these green bounds, as much as we need to in order to have space for those peripheral elements. So in order to do this, we're going to be creating a margin object that looks like this.

    [28:04 - 28:14] And we're going to be translating our entire chart according to that margin. So recall what we already talked about with transform translate to get through this last bit of the lesson.

    [28:15 - 28:18] And let's get into it. So let's go ahead and create a margin object.

    [28:19 - 28:32] And because we want to reference this, maybe throughout the entire chart, we should reference the object here. Let's create a new variable that's a constant called a margin and give it the following numbers.

    [28:33 - 28:42] This auto complete is tempting me, but I'm going to write them out directly for you. Let's do a top of 20, a right of 15, a bottom of 20, and a left of zero.

    [28:43 - 28:44] Why did I pick these numbers? Because I'm a genius.

    [28:45 - 28:46] No, I'm kidding. It's because I've already written this.

    [28:47 - 28:54] I've already created this chart and I know the magic numbers we need. But finding these exact numbers might be more of an art than a science.

    [28:55 - 29:00] It might be a lot of testing and seeing what works. So don't feel bad if like you don't get these numbers exactly right on the first try.

    [29:01 - 29:05] You definitely shouldn't be able to. So now that we have this margin, what do we want to do with it?

    [29:06 - 29:24] Well, if you'll recall from that image we were looking at, the bounds of the chart were kind of pushed down and to the left as much as they needed to according to the margin to fit these peripheral elements. So that's exactly what we're going to do is transform the entire inner chart according to these margin elements.

    [29:25 - 29:33] So within our SVG tag as you see here, we're going to create another grouping element. I know you're learning to love grouping elements because there's so many of them in this lesson.

    [29:34 - 29:39] And you'll remember that a grouping element is a G tag. Then we'll write transform.

    [29:40 - 29:46] And within this transform, we want to do the following. We want to translate according to the following numbers.

    [29:47 - 30:03] We want it to be translated horizontally according to margin left and vertically according to margin dot top. Then we'll close this, close the G element and make sure that we wrap everything inside of our SVG in it and click save.

    [30:04 - 30:08] Now, let's see what happens whenever we click save. What do we notice?

    [30:09 - 30:14] We notice that the chart does in fact shift down, right? We have this width of 400 and this height of 400.

    [30:15 - 30:25] But the entire chart is translated zero pixels to the right and 20 pixels down, which is good. But I really only solved one problem, which is the 60 number.

    [30:26 - 30:32] And we still can't see the bottom axis. So although we have translated the entire chart, this obviously didn't fix our issue.

    [30:33 - 30:40] And the reason for this is because we need to account for this margin in our existing scales. Now, what do I mean by that?

    [30:41 - 30:46] Let's take a deeper look at what we're doing with X scale and Y scale. All right.

    [30:47 - 31:08] With X scale, we're taking in raw data from zero to 100 and based on the position of that data in zero to 100's domain, we're returning a number between zero and width, where width is 400. Now, based on these numbers, if we pass 400, for example, into our X scale, or if we pass 100 into our X scale, we'll get a width of 400.

    [31:09 - 31:27] Now that's at the very end of our chart, right? But remember that we just created a new margin and we gave it a margin right of 15 pixels, which means that actually if we positioned this circle, this 100 circle at the 400 pixel position in our chart, it would be off the screen, right?

    [31:28 - 31:39] It would exceed the chart plus the margin that we've already created. And so what we need to do is create new variables for inner width and our inner height, which can basically be thought of the bounded chart itself.

    [31:40 - 32:02] And rather than use these width and these heights, we're going to use these inner widths and inner heights to render our circles within the chart bounds. So go ahead and create a new variable with me under width called inner width and declare it to be equal to width minus our two horizontal margins, margin left and margin right.

    [32:03 - 32:11] And I want you to do the same thing for height where my auto completion is going to do that for me. Height minus margin top and margin bottom.

    [32:12 - 32:22] And to be safe, let's move our margin declaration above our width and height. Now we have inner width and inner height, but they're not being used anywhere.

    [32:23 - 32:28] Let's go ahead and swap them out. So instead of using width and our X scale, let's pass inner width.

    [32:29 - 32:35] And instead of using height in our Y scale, let's use inner height. Upon saving that, you'll see the entire chart shrinks.

    [32:36 - 32:41] You notice the difference? The entire chart is shrinking because our scales are shrinking too.

    [32:42 - 32:59] And this is a really good sign because it means that we're making really good progress into seeing all of our ticks all at once. But we still can't see the X axis, which is the final step in this lesson is to account for our inner width and our inner height in the existing declarations that we have within our chart.

    [33:00 - 33:13] So remember how we have axis X passing height as a prop and axis X and width as a prop and axis Y. But remember that we just created inner width and inner height to account for the margin itself.

    [33:14 - 33:22] And so rather than passing height and width directly, let's pass their inner alternatives. So now we'll say height is actually going to be equal to inner height.

    [33:23 - 33:35] And width is going to be equal to inner width. Now upon saving, we can actually see mostly all of our ticks with a few exceptions that we can fix with some tweaks.

    [33:36 - 33:51] But for the most part, we're starting to see something really impressive with our peripheral elements, right? We see four Y ticks, each of them meaningfully positioned with a nice line and five X ticks, each of them with the percent nicely positioned and with nice ticks as well.

    [33:52 - 34:02] So we've done a lot around the axes in our chart. And maybe the final step in this lesson is going to be polishing our chart so that it looks just a little bit nicer.

    [34:03 - 34:17] And to be honest, if you're tired of this lesson because I've already talked to you for 30 minutes, just go to the next lesson. Beautifying your chart elements is not necessary to learn the fundamentals, but it is kind of fun to bring beauty to this data.

    [34:18 - 34:30] So we're going to spend just a couple of minutes making our chart a little bit prettier, using some nice colors, some nice fonts, et cetera. The first thing that we'll do is use less intense colors in our chart.

    [34:31 - 34:48] In our Y axis in particular, we're going to want to make all of these lines a different color other than the bottom one. You've probably seen this in charts before where this line and this line and this line will be this faint gray you can hardly see, but the bottom line will be a darker black to kind of provide context.

    [34:49 - 34:51] This is the zero position. This is the bottom of our chart.

    [34:52 - 35:01] So let's go into axis dot y and let's see where we reference our lines, right? Each of these lines has an X one, a Y one, a Y two and an X two.

    [35:02 - 35:13] And currently we're defining the stroke as this long string, but we can actually define it according to data rather than just providing a string. Now what do I mean by that?

    [35:14 - 35:27] Remember that we want to color the bottom one according to its index, where it is the zero with tick that's being rendered and we want to color that differently. So we need to revisit this each block we've created on line eight, okay?

    [35:28 - 35:47] And each block can take two parameters here at the end of it before it closes, where the first in our case tick is the name of each iterated element and the second will be its index. So you can literally call it index or you could call it I or you could call it number or you could call it whatever you want to call it.

    [35:48 - 35:59] The point is it will represent its index in the loop. So in our case, because the first Y tick is zero, we want to color that differently.

    [36:00 - 36:08] And so to do that, we're going to use what's called the ternary operator. Now the way that the ternary operator works is it basically provides a condition.

    [36:09 - 36:17] And if that condition is true, it will render the value that comes after it. If not, it will render the second value provided.

    [36:18 - 36:24] That's a whole lot of nothing that I should just write out so you actually understand what it means. So I'm going to ask you a question.

    [36:25 - 36:28] Does one equal one? I think the answer is yes.

    [36:29 - 36:35] And if one does equal one, then it's going to evaluate this condition, whatever it is. Maybe it could be red.

    [36:36 - 36:42] Maybe it could be green. Whatever you want to make it, otherwise it could be the false position.

    [36:43 - 36:47] So this is how a ternary works. Is this condition true?

    [36:48 - 36:51] If so, return this value. If not return this value.

    [36:52 - 37:04] So in our case, we don't want to use one equals one because that's always going to return true. We want to say, does the index of this iterated label or this iterated line equal zero?

    [37:05 - 37:10] Is it the first element in our axis? If so, give it this dark color.

    [37:11 - 37:21] Maybe we'll do eight F, eight F, eight F. If not, let's do this faint color like E5, E7 Eb. And again, I don't know these because I'm a wizard.

    [37:22 - 37:27] It's because I predefined these and I already had them in my back pocket. And then let's close this line and click save.

    [37:28 - 37:42] And now you'll see the bottom line has a different fill color than those above it where these are fainter and this is in fact darker. So we're making pretty good progress into beautifying our chart just a little bit.

    [37:43 - 37:51] Let's also bring these text elements up a little. So while we're already here, maybe let's just add a y nudge of negative three to push these elements up.

    [37:52 - 38:02] Or if you don't like that, if you want more, you could do negative six, negative five, whatever you want, just to provide some space between the text elements and their lines below. Okay.

    [38:03 - 38:13] Now we want to add some x axis polish. So currently you can't really see the zero and 100 is falling off as well.

    [38:14 - 38:23] Now one way that we could fix this is by providing maybe a text anchor. One way we could fix this is by pushing everything to the left.

    [38:24 - 38:34] There are a lot of ways that you could in fact approach this. But for now, I think the safest way to do this is just to make the zero percent visible and not worry about the rest.

    [38:35 - 38:40] Okay. So for the sake of simplicity, let's go into axis X and let's see what's happening in our text elements.

    [38:41 - 38:54] Now you'll recall that text anchor is what horizontally centers our text elements, right middle right now. I could also make this start and you would see everything shift to the right or I can make it end and everything would shift to the left.

    [38:55 - 39:07] But I actually do want to focus on that start element because what you'll notice is in this start position, zero percent actually looks pretty good, but 100 falls off and I want the rest of them centered. So how do we fix this?

    [39:08 - 39:25] The turnary operator once again. Let's go ahead and add the index to this each block as well as we did with our y axis and then use it in our text anchor property where we'll say if index is equal to zero, meaning it's the first tick return start.

    [39:26 - 39:34] Otherwise return middle. Now if I save, you can see zero, but the rest of these are positioned exactly as we want them to.

    [39:35 - 39:38] So we now have some visible ticks down here. Maybe you could add some more polish here again.

    [39:39 - 39:42] This is all optional. Maybe we could push down our text elements even more.

    [39:43 - 39:50] Maybe we can make them 10 or anything else you want. Let's go ahead and leave it at 10 and let's see what else we need to do.

    [39:51 - 40:06] I think the final thing that would be kind of nice is to make the 100 percent visible, which we can actually just do in our app dots, felt margin. So instead of 15 pixels to the right, make it 20 and voila, we can actually see our 100%.

    [40:07 - 40:15] But maybe the final thing that we can do is add some styling to our ticks themselves. Now they're this black and they don't look bad, but they're a bit bold.

    [40:16 - 40:19] They're a bit strong. Let's make them a fainter gray that look a bit better.

    [40:20 - 40:32] And for this, this is the final step, I promise. We're going to add a style tag to our app dots felt and we're going to want to style our ticks to make them look a little bit fainter.

    [40:33 - 40:38] So you could try something like this. And if you don't know CSS, you'll probably learn it as we go through this course a little bit.

    [40:39 - 40:49] But basically we're selecting everything with the class of tick. So this has a tick class and this needs one.

    [40:50 - 40:54] I forgot that. So let's add a tick class to our axis y dots felt.

    [40:55 - 41:03] And now we can look back at this app dot felt. This is going to find everything that has a class of tick and give it something .

    [41:04 - 41:09] Give it a certain rule. We don't want to give it to the tick element, which is a G. We want to give it to the text element.

    [41:10 - 41:15] Okay. And if you're not a CSS expert, if I'm confusing you, don't feel intimidated.

    [41:16 - 41:21] This is just a bit of visual flair. So it's not super important, but CSS is a good tool to learn.

    [41:22 - 41:28] So hopefully this preliminary introduction is going to teach you a little bit. So we don't want to target the tick elements.

    [41:29 - 41:34] We want to target their text within. And I'm going to apply a few rules.

    [41:35 - 41:42] I'm going to give it a font weight of 400, which is the thickness of the font. I'm going to give it a font size of 12 pixels, which is the size of the font.

    [41:43 - 41:50] And I'm going to give it a fill of, sure, 8 f, 8 f, 8 f, 8 f. Now, if I save this, you'll actually see nothing changes.

    [41:51 - 42:09] And the reason for this is because the CSS selector is unused, which is weird, because if I go into access X dots felt, and I apply it to this style instead, it actually does apply. And you might be asking, why does it apply in access X dots felt, but it doesn 't apply in app dots felt.

    [42:10 - 42:31] And the reason is styles in felt are scoped, meaning I could apply styles to this particular file, like H one or text or div or whatever else. And they would apply here, but not anywhere else in my app, which is actually really nice as you get into more complex applications to have styles scoped to the only files that they're referenced in.

    [42:32 - 42:38] So that's normally pretty helpful. But in our case, we actually want to apply this to all ticks tick text elements .

    [42:39 - 42:54] So let's, you know, go back and re add this text and wrap it in what's called global. And now all of these rules actually do apply to our chart and they look pretty great.

    [42:55 - 42:58] Okay. Now I actually did these steps slightly out of order.

    [42:59 - 43:09] And I realized I forgot to go over final grade and hours studied, which are kind of the axes titles in this lesson. So I kind of lied to you when I said this was the last thing.

    [43:10 - 43:15] I'm sorry, we're going to add these titles, which are going to be pretty quick. I promise.

    [43:16 - 43:17] And let's start off with the Y axis. Okay.

    [43:18 - 43:26] So right here, we wanted to read 60 hours studied right now. It just reads 60, but we want to add that title in the tick itself.

    [43:27 - 43:35] So in this tick, you could write hours studied, which would then render it after every single tick. But we only want to do it for the top one.

    [43:36 - 43:52] And thankfully we've already talked about the ternary operator. And so thankfully we can just use this ternary operator once again, like so, where we say, if index is equal to zero, but in our case, we actually want to do the last tick.

    [43:53 - 44:01] So we'll do Y ticks dot length minus one. If that is true, then render hours studied.

    [44:02 - 44:05] Otherwise render nothing. Notice that.

    [44:06 - 44:13] And now you start to see what we want, but you know, so we need a space. So you click space and now you have that title already finished, right?

    [44:14 - 44:18] The Y axis very easy. Thankfully, the X axis is pretty easy too.

    [44:19 - 44:23] Now let's create a new text element. And we're going to make this the X axis title.

    [44:24 - 44:30] So let's put it at zero, zero for now. And right final grade.

    [44:31 - 44:38] Now by default, you see it's right here at the bottom of the chart and the bottom left, thanks to this translation. We want it the very right of the chart.

    [44:39 - 44:49] So we actually need to import a new prop, which is the width of the chart, which if you'll recall, we do an app dots felt. So remember, this is going to be in our axis X.

    [44:50 - 45:00] So let's say width equals inner width. Now back in axis X dots felt, we can accept that prop by using export let with.

    [45:01 - 45:07] And now finally, rather than zero, we can add width as it's exposition. And it's almost there.

    [45:08 - 45:13] It's just a bit out of place. So we're going to leverage these tools again, dominant baseline and text anchor .

    [45:14 - 45:20] You might notice they're pretty handy when designing charts, right? So let's start off with dominant baseline.

    [45:21 - 45:24] There are a few options. We could do middle and you'll see it gets pushed down.

    [45:25 - 45:33] We could do start and you'll see it gets pushed up or we could do hanging where it gets pushed down the most amount possible. We'll do start in our case.

    [45:34 - 45:43] And then we'll also add a bit of an adjustment upward by giving it a D Y of negative six or some value like this. It can really be personal preference.

    [45:44 - 46:02] Now our text is positioned correctly vertically, but it's still off center horizontally, which will fix using the text anchor property. So the auto completion got it text anchor of end is going to push this back to the bottom right corner of our chart.

    [46:03 - 46:16] Now finally for some visual flair, I'm going to add a Unicode arrow by writing ampersand r a r r. And now an arrow renders, which is the best part of this entire chart so far.

    [46:17 - 46:33] Now you'll notice that this title is not stylistically similar to these ticks or this title. We can make it similar by adding another class like access label or title or whatever you want to call it.

    [46:34 - 46:47] This again is personal preference. Let's just do access title and let's go back into app dots felt and rather than just targeting tick text, let's also target access title.

    [46:48 - 46:58] Now when I save, you'll notice it renders at the bottom and it has the same styles as the rest of our visual elements. So 50 minutes later, what have we accomplished?

    [46:59 - 47:26] We've taken our very simple scatter plot, which let me remind you used to look just like this and we added axes, access labels and tick lines to make it look like this, much more beautiful with a lot more context for the viewer so they actually know what they're looking at. So I want to thank you for sitting through this lesson if you didn't skip around or leave already because I know this was pretty tough to get through.

    [47:27 - 47:43] And I also want to provide some context and say it's okay if this was hard. If you were confused at times, some of it was maybe because of my instruction and I'm sorry, but a lot of it was probably because peripheral elements in data visualization are historically hard, right?

    [47:44 - 47:47] We're dealing with a lot of different factors. We're dealing with SVG and its attributes.

    [47:48 - 47:52] We're dealing with transforms and translations. We're dealing with some D3 internals.

    [47:53 - 48:02] We're dealing with margin objects. So there's a lot at hand here and it's okay if you run into problems on this because I still do like five years after doing this.

    [48:03 - 48:05] Okay. So don't feel bad, but thank you for sticking in.

    [48:06 - 48:13] I promise the future lessons. First of all, the future lessons dealing with peripheral elements are going to be a lot easier because you understand the pattern.

    [48:14 - 48:22] But then also the next couple of lessons that we're going to be doing on this scatterpot in particular are really fun and really easy. So I'm excited to get into those.

    [48:23 - 48:26] Please ping me with any questions about peripheral elements. It's okay if they're hard.

    [48:27 - 48:33] But I'm really excited to see you in the next lesson where we'll work on responsiveness for our chart. Thank you.