Adding Dynamic, Data-Based Styling to a Svelte Beeswarm Plot
Adding dynamic, data-based styling to our beeswarm chart
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.
Get unlimited access to Better Data Visualizations with Svelte, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:12] And this lesson will be styling our circles. So although our force diagram works and each circle is positioned properly and the force diagram is responsive, this still is pretty imperfect.
[00:13 - 00:24] Every circle looks identical and we have no idea why they are positioned the way they're positioned. The two ways to address that are first adding some peripheral elements like axes.
[00:25 - 00:32] And we'll tackle that next lesson. But first we're going to do something easier, which is make each circle look distinct from one another.
[00:33 - 00:39] Now we can target two properties to do this. The first is each circle's fill, or its color.
[00:40 - 00:50] Basically we're going to fill each circle according to its continent. So we have some clear grouping as well as on the y-axis also in each circle's fill.
[00:51 - 01:01] And the second will be each circle's size. We'll go ahead and add a radius to each circle that is dynamic and updates depending on that country's happiness score.
[01:02 - 01:20] Now of course this is double encoding since that's also what's presented on the x-axis, but it's still a good exercise and it will expose you to a new D3 scale that accounts for the radius of a circle. So first let's do the easier of the two, which is add a color to each circle.
[01:21 - 01:29] In order to do this, yes according to its content. And in order to do this we're going to need a brand new D3 scale that we have not worked with yet.
[01:30 - 01:36] That's called scale ordinal. So briefly I'll bring up the documentation for D3 scale ordinal.
[01:37 - 01:44] Again the way that I'm going to do this is just by googling it and finding the first couple of results. You might need the keyword D3.
[01:45 - 01:56] And observable as it usually does will have really good documentation for this and I would encourage you to read through this. But what you're going to notice over and over again is this use of color.
[01:57 - 02:09] In specific we could pass in a domain and range. It could be quantitative in nature or it could be categorical or ordinal and it will return an equivalent position within the range.
[02:10 - 02:19] So this is essentially the exact same as what you've already seen in D3 scales. And that it takes in a domain which is an input and a range which is an output.
[02:20 - 02:28] And in our case it's pretty easy to imagine what our input and output are going to be. But first let's go ahead and import it.
[02:29 - 02:39] And again this is from the exact same D3 scale module. And then we're going to create a new scale and we will call it color scale.
[02:40 - 02:51] Now this is going to be scale ordinal again because that's what we just imported. And just to remind you it uses the exact same domain which is an input and range which is an output.
[02:52 - 02:59] So what is the input? Well you might notice that I place this directly below the continents group that we've already created online 57.
[03:00 - 03:12] Let's review what this is by console.loggingit. And what you'll notice is that continents, oh I need to comment on this because it'll be broken for now.
[03:13 - 03:32] Continence is an array of six items and you'll notice these are actually arranged according to their mean happiness score in ascending order. Where Oceana is the happiest continent according to the data.
[03:33 - 03:40] So we have six items in our continents array. And already we can imagine this is what will be put within our domain.
[03:41 - 03:47] We want to fill things according to their continent. So that will be the domain.
[03:48 - 03:52] Then the question is what's the range? In the range we basically need six colors.
[03:53 - 04:06] You could invent these colors on your own or if you'd like you can copy the exact same colors that I use which I'll go ahead and paste right here. I've just found these colors are generally good for use within this data visualization.
[04:07 - 04:12] I think it looks pretty nice. If you disagree definitely create your own colors or tweak these as you see fit .
[04:13 - 04:19] Now I'm going to save this and nothing's going to change yet because I'm not using the color scale. But then using this is quite simple.
[04:20 - 04:33] Down here in our circle element that we're rendering online 92 right now we're passing this constant fill of steel blue. Let's instead pass the color scale of node dot continent.
[04:34 - 04:46] Remember that node dot continent exists within our data right we have continent as a property. And then we're passing this so it'll look for the equivalent input and based on its position within color scale.
[04:47 - 04:58] We'll return its equivalent color in range. Okay, so if just to belabor this point maybe too much if Africa is the first point in our continents array.
[04:59 - 05:09] If we pass Africa into color scale it will return the first item in our color range. In this case DDAODD.
[05:10 - 05:15] And the same will go for the second item Asia will be equivalent to this. South America will be equivalent to this.
[05:16 - 05:19] North America Europe, Oceania. So that's how we'll use color scale.
[05:20 - 05:27] Let's go ahead and save. And we already see these beautiful colors begin to populate and replace our ugly steel blue.
[05:28 - 05:36] You might notice you can't really see these top elements. So I would recommend you put a stroke on your circles which is as simple as stroke and whatever color you want.
[05:37 - 05:40] I'm going to do a stroke of black. Optionally you can make them thicker if you want.
[05:41 - 05:47] You know you can make it a very thick width. Although I would recommend just using one which is also the default so you can omit it.
[05:48 - 05:57] And now we have each of these circles looking pretty nice. We actually start to see the beginnings of a real styled chart because all of our colors, all of our circles are not the same color.
[05:58 - 06:10] So that's the first thing that we're going to tackle is styling our circles color. You know to be consistent you might want to import this scale ordinal on the same line that you import the other scales.
[06:11 - 06:18] You can move it up to line 49. That's optional but if you'd like to do that to keep your imports consistent you can definitely do so.
[06:19 - 06:35] Now we have our circles properly filled and now we can move on to the second objective of this lesson which is sizing our circles according to their happiness score. Now this is going to use yet another D3 scale.
[06:36 - 06:44] This one called D3 scale square root. Very hard to say over and over again I would encourage you to try it or don't.
[06:45 - 06:54] That's up to you but scale square root is the scale that we are trying to import. I'm sorry for probably getting tongue tied over and over again whenever I do try to say it.
[06:55 - 07:00] There are a few places that you can read about this. First is obviously on GitHub and observable.
[07:01 - 07:12] Second this D3 in depth article kind of explains the intuition behind why we use it. And the reason is we want to set the area rather than the radius proportional to data.
[07:13 - 07:26] This is just how humans and brains perceive the size of elements. Circles increase according to their area so we need to account for that in how we create scales.
[07:27 - 07:31] It's pretty fun to read about this so I would encourage you to do so. It'll probably be on the scope of this course.
[07:32 - 07:44] So just know that if you're working with circles you should probably be using scale square root. With that being said the internals of scale square root are essentially the same as every other D3 scale you've seen.
[07:45 - 07:53] They take in a domain and a range where domain is the input and range is the output. So it's very easy to see how we could use this in our example.
[07:54 - 07:59] We'll go ahead and create a new D3 scale. We'll move that over really quick.
[08:00 - 08:09] We'll create a new D3 scale. And we'll call it radius scale.
[08:10 - 08:18] And this will be a scale square root with a domain. Again I'm writing this over and over again so it really gets in your head.
[08:19 - 08:24] Range is output. Now what is the domain and what is the range?
[08:25 - 08:31] Those are the questions. Well we already know the domain of potential happiness scores.
[08:32 - 08:39] And we have it right up here on line 51. Remember as I said earlier that we're kind of double encoding this happiness score.
[08:40 - 08:52] We already know from our brains that it goes from 0 to 10 and that realistically nothing goes below 1 or above 9 which is why we made this the x scale domain. So we actually want it to be the exact same domain for our radius scale.
[08:53 - 08:56] So we'll go ahead and paste that here. Now what do we want the range to be?
[08:57 - 09:06] Well the answer is whatever you want the size of your circles to be. So let's actually just put some testing numbers in and see what we like and then come to a final conclusion later.
[09:07 - 09:15] Start off with 1 and 15. Now we have this radius scale but you might notice a bug because I don't think we've imported scale square root yet.
[09:16 - 09:19] I guess we did. So you won't see a bug.
[09:20 - 09:33] And then radius scale now can be used in our application. Down here we have r=radius where radius is this hard coded variable that you might recall is 5.
[09:34 - 09:41] We don't want to use the hard coded radius variable anymore. We want to use radius scale of node.happiness.
[09:42 - 09:48] Let's save this and see what happens. We see that our circles definitely increase in size but they don't look very good.
[09:49 - 09:57] There's something broken and what's broken is that these circles are overlapping. The reason for this is we're referencing radius that all caps variable in one other place.
[09:58 - 10:12] And that's in our force simulation. Up here in this reactive block you might remember that we have a force collide which basically tells the force diagram how to account for each element's size so that they don't overlap with one another.
[10:13 - 10:17] It prevents collision. We're using radius here which is obviously an issue.
[10:18 - 10:37] So rather than passing radius directly we need to use our radius scale. Now right now the force collide is then passing in radius as a standalone variable but we need to use another accessor just like this where we take in D and we return D.happiness just like this where we take in D and we return D.
[10:38 - 10:55] continent. We need to take in D and return radius scale of happiness. Now you might see that it's suggesting you add one and the reason for this is that there's a little bit more space between elements so you definitely can do that if you'd like.
[10:56 - 10:57] You don't need to. It's up to personal preference.
[10:58 - 11:07] But now we can see that our circles are actually being positioned properly. They're actually respecting each other's radii so they're not all overlapping in some huge jumbled mess.
[11:08 - 11:15] Now the issue is obviously that they're just too big. So this is why I said we should just go ahead and try some test numbers and then adjust later.
[11:16 - 11:23] I think one might be too small over here maybe so I'm going to make that three. And then I think 15 is simply too large.
[11:24 - 11:28] Let's change it to eight. And then let's refresh.
[11:29 - 11:37] And now you see that these elements actually look pretty good. There's a very marginal difference between the three and the eight but it's enough to be noticeable.
[11:38 - 11:40] And I think that that's pretty good. I like these sizes.
[11:41 - 11:50] So I'm going to leave three and eight which I think is pretty good. But what you might also want to do is change these on really small screens.
[11:51 - 11:57] So say you were even tinier than this screen. You were on a very small mobile device and these bubbles are looking a little bit crowded.
[11:58 - 12:08] We could make this element reactive to the size of the entire application to make even smaller bubbles on small screens. How do we do that?
[12:09 - 12:16] Well we're going to want to pay attention to the width variable and update scale square root if it passes a certain threshold. How do we do that?
[12:17 - 12:22] Yes, a reactive label. I'm going to assume you said it to yourself because we've said it so many times in this course.
[12:23 - 12:31] You're going to do dollar sign colon radius scale. And then where do we want to reflect the width within our application or within our scale?
[12:32 - 12:46] It's going to be in the range. If width is above a certain number or below a certain number, we want to return a different range, smaller numbers, than if it is above or below that threshold .
[12:47 - 12:58] So let's go ahead and say if width is less than 568. Random breakpoint, but people love to use 68 as kind of their suffix for like breakpoints and web design.
[12:59 - 13:04] You might see 968 a lot. I don't know, it's up to you. But you could do 568, you could do 600, whatever you want.
[13:05 - 13:11] And then if it's smaller than 568, we want these circles to be even tinier. Let's say we want it to be 2 to 6.
[13:12 - 13:18] And if not, if it's above 568, we want it to be 3 to 8. Let's go ahead and save this, refresh.
[13:19 - 13:23] Now you can see those bubbles are a bit smaller. And if I resize, you see they get bigger.
[13:24 - 13:31] So notice right as I pass this 568 point, you see the bubbles get bigger or smaller. So you could make this any number of things.
[13:32 - 13:40] You could check for even smaller breakpoint, like 368, make them super tiny. But here, you know, what you would be using is this ternary operator, which we 've reviewed before.
[13:41 - 13:48] The question mark and the colon basically says, if this is true, return this. If it's false, return this.
[13:49 - 13:57] So here we're dynamically creating a new radius scale, if and when we need to, based on the width of our screen. So, what have we done in this lesson?
[13:58 - 14:13] We've gone from an unstyled, yet functional D34 diagram to a pretty nice looking force diagram that has circles that are styled according to their content. I think that's a great improvement based on where we started.
[14:14 - 14:22] Obviously still, it's not clear why these circles are positioned where they are , which is pretty crucial. So in our next lesson, we'll take on peripheral elements.
[14:23 - 14:36] There's tricky peripheral elements that we love designing to add some context to this visualization, with an x-axis that shows happiness and a y-axis that shows each country's content. So, I'll see you in the next lesson.