Get it Right in Black & White Episode 11 - Charts with Menus

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign yeah we're fully vaccinated here how about yourself nice all good fantastic so you all can see my screen right i'm sharing nice yep hello eric how are you welcome everyone to episode 11 of get it right in black and white charts with menus we've got a full house today we've got felipe adil nita and eric dasbach i think i'm saying that right is that right das bach great so yeah let's start by reviewing the submissions from last week this up forum from last week all right so the exercise was add labels to this reusable scatter plot let's see what folks did wow this is pretty nice the labels are animated very cool nice work it's kind of surprising the arrow that's a good question let's check it out i guess it would be in here somewhere it's an actual character see that yeah yeah pretty neat there's actually a lot of um surprising characters that you can use i think it's from unicode but there's arrows there's little old dots emojis of course you could put emojis in here and it should work nice okay so the the axes the labels are animated as well with the same pattern very nice cool let's take a look at what some other folks did this is pretty cool so the animation pattern is it just disappears and then comes up from the bottom hello welcome perfect timing i'm not sure how to pronounce your name but but you just joined the call welcome i think this is the first time you're here you want to introduce yourself a bit uh kostav i'm not sure how to say your name but welcome kyle stuff you want to introduce yourself you're muted i'm not can't hear you welcome kathy hello i think this is the first time you're here you want to introduce yourself a little oh yes got it yeah i'm i'm experimenting with opening up the the live chat the live audio chat to everyone watching because um yeah i think there's a lot of value in people you know stopping me asking questions we can have a lively discussion all right glad you could join we have a full house today yeah no i i would suggest you close the youtube window it's a little tricky of a setup yeah because there's delayed audio coming from the youtube window and and there's the google meet window so if you're in the google me you have to close the youtube window sorry it's a little it's a little confusing oh good welcome kostov i'm so glad you could join us um i've i've seen your work recently and it's really great you want to introduce yourself a little bit excellent oh this one nice yeah this is really beautiful work yeah i've been i've been really happy to see you working here and i'm thrilled you could join us today this is amazing this is amazing so yeah this is this is sort of a dream come true for me with this series i was hoping to collect sort of a core group of people who are following along intensely with this stuff and this is actually what happened so just thank you so much for for joining me on this journey this is amazing so i was just showing your work uh costume how do you say your name again i'm sorry kostov gostive nice do you want to present this work a little bit see and explain how you did it very nice right yep oh there it is oh that's actually pretty nice that's a pretty nice technique you're actually checking the value to see if it's a number or not nice work yeah so if folks if folks haven't seen this type of operator this is a really nice operator you can you can say type of something and that operator returns a string and it could be number like the string number or the string s-t-r-i-n-g or object or anything and this tells you what type of thing it is so this is checking the first row at the certain column what type of thing is it nice so it's filtering just by the numeric columns great work i see yeah continue has to be an expression on its own and so if you wanted to do that let me just show you real quick how you could do that so this is using the four in construct which is slightly different from four of uh but this is this is working fine so the thing is the ternary operator it creates an expression that has some return value and so you know if this value is true then it returns the first thing right after the question mark if it's false it returns the thing after the colon however continue continue needs to be its own separate statement so if you wanted to use continue you would need to do it like this you would need to use an if statement and an if block right here and and this use of the ternary operator is a bit confusing but because it has a side effect it's typically not recommended to to have a side effect meaning pushing a new thing onto the array uh inside of a ternary operator it's just a little bit confusing so this is how i would suggest to do it use an if and inside of that if block do this do the thing with the side effect so it's really clear that okay this is this deserves its own line it's doing something it has a side effect it's changing this array and then in the else block then you could use continue but yeah i was about to say like but you don't really need that because it's gonna just continue and do nothing anyway so nice nice yeah i'm glad i'm glad this came up yeah continue it's a control flow thing that you only need to use if you're inside of some like deeply nested thing and then you you know inside of some deeply like if you have four like three like i don't know two or three nested if statements and you come to some case where you need to continue that's where you would want to use um continue and i can't think of an example offhand but if it's just a case like this you don't actually need to use continue at all so this is another way of doing it yeah so with the for in construct this actually works because it's block scoped so this block here so const it declares this variable called col column and you could also use let here that would work too uh you could even use var if you're old school but const works yeah yeah my pleasure and um what this what this block of code is actually doing is it's filtering the columns to have only the numeric columns and so i can't help but just also suggest another alternate way of doing it as well which is like this const numeric columns equals um there is no list comprehension but there are many useful methods on arrays that you can use and so this 4 in construct actually uses the keys of this object so you could say object dot keys of the first row this gives you an array of all of these columns and then you can say dot filter which is an array method and a lot of this stuff you could do in python with list comprehensions but there is no list comprehension in javascript it would be cool if there were but we can just use these constructs like filter and so we can pass in a function to filter and this function can just return this boolean you know if the type of the first row at this part particular column is number then return true otherwise it returns false and i'll just use prettier to format this code and this actually does the exact same thing as all of this it's just a more concise way of doing it understood yeah excellent excellent and i can see that like i i can see that you're you're learning and trying new things and this is this is a very good way of um like this i can yeah it's great i could see your learning process which is amazing and so this is a good first working version and then you can simplify it with the addition of these different constructs like filter this hop does not do linting i tried to get it to work with linting but it was causing all sorts of instabilities it started crashing uh that's something on the roadmap for vishub it would be amazing to do linting and vis up that's something i really would like to see but unfortunately not right now but the closest thing we have is prettier this little p which which formats the code for you i find it super useful and along these go ahead sure it's an array of strings and it just for some example if we were to test against string it should return just species and it does yeah species is actually a something that sort of throws throws a wrench in the works of how our scatter plot works and this is uh this is going to be related to the exercise for today and we'll get more into it later but yeah this is an alternate way to do that filtering and let's see what time is it it's 11 21. let's just see a couple more exercise submissions here's another one from cost of um i don't know which one i clicked actually hold on this is the one i wanted to click data source dozen d3 scatter plot oh this is amazing the data source so good so good nice so this excellent yeah great work this this is awesome the data source data set by the way it's it's got a lot of history to it um i can go into it at another time but it's a great data set because it it has this picture of a dinosaur that you can see here and the point of it is that if you take all sorts of statistical summaries of this data set they're all like the same for all the different columns but if you visualize it you get totally different things like that data source and dots and the star and the point of it and the circle here and the point of this data set is to show that statistical summaries lose a lot of information and when you visualize the data you can see these patterns and information that you cannot see with just the statistical summaries very nice and here's another one with labels this one blew my mind when i saw it it actually does the animated general update pattern example within the label isn't that cool yeah really a lot of attention to detail on this one it's i was happy to see this one it made me laugh i'm like oh my god this is this is so funny yeah so really nice work really nice work here by andrea nice oh here's one from eric dusbach nice you want to talk about this a little bit oh cool animation alright right nice well this is very nice this is very nice however however i do see some telltale signs that the labels are not adhering to the general update pattern see if you could see around the edges they're like very sharp and crisp that indicates to me that there's actually a bunch of labels on top of one another so let me just go in here and see what's happening with that and how we might fix it so the y-axis label looks fine actually this one is behaving correctly nice work with the data null um oh nice oh nice that's great that's great i'm happy to see this like cross communication happening but here's where there's still a problem see with this one it's just appending a new group element every time for for axis bottom year but it's very close to what it needs to be i mean all you need to do here is selection dot select all a dot axis bottom year dot join g and now oh sorry sorry sorry i forgot the data null here now if you see the animation play out this 2020 is is looking correct it's not getting that crisp thing happening to it so yeah this is the pattern right here that you can apply to all the different text labels like this one united states and this other one here nice so yeah you're well on your way nice yeah my pleasure great work great work and while i'm in here i just kind of kind of want to see if we make this delay i times like 20 i kind of want to see it play out in its full slow beauty see this is this is really cool oh my gosh oh it's look what's happening here nice yeah that's what you got to do you just got to dial it in dial it in or alternatively you could make this a function of the number of rows in the data that's actually something i wanted to do earlier but yeah it's it's gets a little detailed but yeah excellent work excellent work all right last one from andre take it out oh is it broken oh this is this is just a bug this is a bug invis up i don't know what this is coming from i've been meaning to investigate this i think just the data set was taken a long time to load oh it's working now nice very cool so it's just plugging in a different data set to that one with the with the transitions on the labels nice very nice work oh let's check it out oh you can only hear me oh my god seriously this is a disaster oh my gosh it's been just my audio coming through this whole time can one of you say something just to check the levels ah yeah i think so yeah it's a yeah sorry i i had my youtube close said something um yeah it's it's my problem on the obs config hold on just let me try to figure this one out all right can you can one of you say something testing nice there it is okay now it's coming through oh this is a disaster so all the audio so far was was lost from everybody else but now it's coming through sorry about that oh so sorry yeah you saw it before the class start but uh the question is in the uh it's in the mid chat oh the me chat okay this is too much for me to monitor it's too many chats yeah that's why i said because it's too much places yeah i think you need to take break every half hour and check around yeah totally all right now let's get into today's episode so i'm gonna try to i'm gonna try to keep this to a half hour what we're going to try to do today is add menus to our animated scatter plot so that instead of just cycling through different columns it's going to be driven by the choice of the user you know what do i want to see right now and so you can click the a menu and select which column to use for both x and y whoops so i'm going to start from what we did last week this animated reusable scatter plot and i'll drop the link here in the chat if you'd like to follow along so i'll start by forking this one and i'll say um animated reusable d3 scatter plot or just i'll say scatter plot with menus are reusable how about animated animated scatter plot with menus okay so what i'd like to do here is add menus how do you add menus it turns out this is thing called the select tag in html and it looks something like this here's an example from w3schools this is the sort of basic built-in menu that you get from html and this is this is good for us we can use this so i'm going to copy this code as a reference example and i'm thinking we can use the same pattern that we used for our scatter plot for the menu so we're going to want to be able to say import menu from dot slash menu and we can use the same reusable chart pattern for this menu component so i'll create a new file called menu.js and in here i'm just going to paste this as a reference and comment it out and then i'm going to copy all of this scatter plot stuff paste it in here and change scatter plot to menu and and then just remove everything inside of here except the core skeleton of what we need and i'll keep one example of an accessor because we're going to want to have a bunch of these all right so this is the basic skeleton of what we want to do and then let's let's um invoke this from index.h index.js to get to a starting point for development i'm going to get rid of this set interval stuff because it's going to be replaced by uh in the interaction of selection and we have this columns thing here which can drive the menus so we want to call dot call menu on something but we don't have that thing yet and i think what that thing should be is a div that we append to the body so maybe up here i'm going to make another block called menu container where we select the body and we can append a div a div is just a container element in html and maybe let's give it a class of menu container just so that we can style it with css and then we can use this to invoke our menu component so what this is i have a question yeah go ahead so this um html elements uh it doesn't make sense to uh attach them to svg because they are basically html elements so they go to body element only correct yes um within the svg element you can only use certain certain tags that make sense within an svg like circle and line and all that stuff if you want to use a div inside of an svg there is actually a construct you can use to do this it's called foreign element svg foreign element but i don't use that very much because i find it confusing to have divs inside of your svg and it has some weird behavior so what i generally do is keep the svg graphics totally separate from the ui elements the regular old dom elements and so this is why i'm setting up a div giving it a class of menu container and then we can put stuff into there so we can instantiate our menu pass it into dot call and then inside of menu when it gets invoked the selection is this div it's the parent div so let's just try something selection.txt just as an example of something notice how it doesn't actually show up anywhere because i think it's showing up below the svg like beyond the boundary of the page so what we want to do is style it so that it appears at the top of this page so we've got this class menu dash container in our styles.css we can access that and i'm going to just position these menus on top of this svg to do that we can say position fixed top zero and left zero this will put it at the top left corner so now we can see there it is foo at the top left corner i would like to ultimately center all of this stuff and i think i'll do that now just while i'm in the css to do that i like to use flexbox which you can set up with display flex and this is a whole thing that you know i could spend a bunch of time talking about but suffice it to say that when you use display flex it opens up this whole landscape of options for you which is extremely well documented in this thing called a complete guide to flexbox which has been a really great reference for me whenever using flexbox so what i want to do is center it so we can use justify content um i think space around is what i'd like to use so that we have one menu on one side and another menu on the other side so justify content space around um it's still in the corner uh i think we need uh right zero as well which will make this div span the whole the whole space from left to right now we can see that little foo is in the middle here which is what we want all right we're going to actually want two menus one for x and one for y so let's scaffold that out now while we're here i will put these as children of menu containers so i'll call it maybe x menu container or how about i'll just call it x menu and we can do the same we can append a div give it a class of x menu container um but you know i don't think we actually need different classes for this so i'll just append a div the simpler the better so we've got x menu and y menu and down here we can say xmenu.call and then ymenu dot call and see now we have two different labels one on the left and one on the right this is looking good this is what i wanted to ultimately ultimately end up as one menu on the left one menu on the right now that we have our positioning down let's develop this menu component using this this example code as a reference so i think the menu should be comprised of roughly this structure where there's a label and then there's a select element that has a bunch of options inside of it let's begin by creating this label we can say selection dot select all label dot data null i'm just going to start by using this this item potent pattern from the beginning so we don't end up with any bugs later if we invoke it multiple times dot join label like this and the label is for this select and that has some implications for the ui like if you i think if you click on the label it gives focus to the select or something like this i'm just using this as a as a template because i think it's all correct so let's begin by setting this four attribute i can say dot attr four and i'll use something called id which is something that should be configurable so let id equals nothing to start and we can we can set up an accessor for id like this uh what is where is label what do you mean where is label what is this variable this is just an element here select all label yeah the idea is we're going to create this structure ins inside the dom and so there's no variable called label it's just the tag name label and it's going to appear as some text next to the menu that says what the menu is about yeah but in this case you okay i got it you're selecting all the labels but there is none label right right now correct and then you will create but what what if we have a label in our in our page right if there's already a label there as a child of this selection then it will it will select that and use it instead of creating a new one this is what this this whole pattern is all about this idempotent rendering pattern the first time it's invoked it'll create a new label but subsequent times it's going to use the existing label and then change the change its attributes okay so we are using this fake data for now so what is the real label in our well that's where we're gonna have to configure it so i'm beginning by by by setting up this id and in this dummy example the id would be cars so four equals cars here name equals cars and id equals cars over here but we have not set it up yet and what i'm doing is i'm working on i'm working on the the accessor so that we can set this up so i'm creating an accessor called id and over in index.js when we set up the menu for x we can we can call dot id and pass in the particular id i'll call it x dash menu for example and the key is that the id for the y menu needs to be different so now this will work because we just set up this accessor so we can call dot id pass in the id that invokes this function here which sets the variable called id to the value oh we need to get rid of this plus because that will that will parse the string to number which we don't want here and then once that is set uh when it gets invoked it'll set for that id now we need to put the the text of the label which i think i'll call label or how about label text just so it's not confusing we want the text inside of this label to be label text so in our in our rendering code here we can say dot text which sets the inner text of the element to be label text and again we need to set up an accessor where we just change id to label text like this and then over in index.js we can call dot label text for these two different menus and pass in different things so for x it would be x colon i think is what i want it to be and then for y it would be y colon all right and then it shows up like that x is here and y is here excellent so far so good now let's begin working on this this the actual menu part of it which is sort of what all of this has been building up to the general update pattern here or yeah this item potent rendering pattern will be the same but instead of a label element it's going to be a select element and here we want to set name and id to be id which is very similar to this line here where we we're setting four on the label so i'm going to use that same pattern but instead of four it's going to be name and id like this now notice that we have sort of a stub of a menu that doesn't have anything in it so we're getting there now we need to populate these options hi karen i uh so when we're doing this select tag uh we are passing two attributes name and id and in the example as well they are both set to the same value so is this intentional or is this just specific to this particular example yeah this is intentional and to be honest i haven't dug too deep into each of those things i just sort of blindly copied it from the example that i found but here's another example of an html select element from mdn where they do the same thing where the label is 4 and that has to match up with the id but i see here that name is different and i do i do not actually fully understand the role of the name attribute on a select so let's see if we can find that name it's used to specify the name of the control i mean this is one of those things where i'm just going to sort of blindly follow the example what about id yeah i'm not really sure but the thing is when you when you click on when you click on the label it gives that menu focus that's why i think it's important that these match but apparently only the id needs to match and not the name so could it be like the this name is sort of like a class to apply say css styling or something like that could be could be but then i mean if you want to use css you may as well just give it a class and be sort of standard about it right i mean maybe it would work to just leave out the name honestly i'm not sure okay yeah but that far should match the id that's the main thing correct yeah four should match id um i think i think the id should be unique to the whole html document right yeah generally id needs to be unique in the whole document and to get to the bottom of this we can do some experiments like if i click on x see how the menu gets focused i'm curious if i if i leave out both of these name and id and i click on that label it does not get focus so we know that one of these is important let me try just setting name and see what happens if i just set name and i click on it it does not get focus it does not get focused at all however if i leave out name and i just set id and then i click on the label it does get focus this is the behavior that i'm after this is why this is the whole reason why i'm setting this up so you know maybe i'll just be a little cowboy about it and leave out name because like i like to have this philosophy of like if i don't understand why it's there i'm not gonna put it there you know if it doesn't do anything for me there's no need to put it so thanks for asking that question i have always wondered about this actually and now with this little experiment we got to the bottom of it so i'm just going to set id and be done with it yeah but id generally yeah it does need to be unique on the whole page that's why it's important that the id is different for x and y all right great let's continue let's add these options to our menu inside the select we want a bunch of options which is where we can continue this expression here so we're inside of the select now in here we can say dot select all option dot data options which we have not defined yet i'm going to define that dot join option and then each of these options needs to have a value attribute and also some text and the text inside the option element is what you see on the screen the value is more like an internal id that the code uses so let us let us assume that each element of this options array which we're going to define in a minute will have a couple things namely a value property which we can use here to set the value attribute like this and also a text attribute so i'm going to say dot text and here we can also pass in a function that takes as input one row and we can return text like that yeah this should be the complete code required to render our set of options now we just need to define options and options is something we want to define from the outside so i'm going to set up an accessor for options so we define the variable at the top i'll use this this template here to create a new accessor for options i'll just replace id with options everywhere here all right and then in index.js we need to pass in are options to both of these and columns is pretty close to options however it only has the actual columns it doesn't have the labels that we want to use i mean we could use the same for both but my preference would be to set up objects for each of these that have labels as well so value will be the original value here and then from here we can say text will be some string and for petal width that should be uppercase petal space width i'll just type these out these are the labels that we're going to see on the screen so they should be nice human readable stuff not this lowercase underscored limited thing which is kind of like nerdy you know it's not really not really presentable so petal length and sepal length all right these are actually our options so i'll just rename that variable to options which we can pass into the options accessor for both of these different menus all right now we have options in our menu look at that it worked amazing amazing all right now is the fun part where we get to wire it up and make it all work make it all happen this is where things get a little a little tricky what we want to do um i want to be able to call dot on on this thing here which is generally how we add event listeners to things typically the first argument is the the name of the event on change and then the second argument is some callback where it accepts a value and it does something so for now i'll just say console.log value and later on we'll have that actually interact with the plot to change to change x and y but for now let's just put it like this to see if it works and this is where it's kind of a challenging thing to to iterate on this pattern this reusable charts pattern to handle events luckily there are a couple d3 packages that do this one of them is d3 brush and i like to study the source code of d3 itself to see how to do some of this stuff you'll see that the implementation of d3 brush uses this other package for events called d3 dispatch which is what we can use as well this is this is part of d3 this is how you can set up components with event listeners so the way that brush does it is first it imports dispatch from d3 dispatch which we're going to have to do as well so i'll just do that now import dispatch from in our case d3 um and let's see where it's used listeners equals dispatch passing in various types of events that could potentially happen let's do that as well i'll say const listeners equals dispatch we're only going to want one type of event which is change so i'm going to put that like that here this is the conduit by which we can emit events and we can event we can listen to these events externally and let's see where is listeners used ah to emit an event we need to use dot call but first we need to expose dot on to the external world and this is the pattern that d3 brush uses it calls listeners.on dot apply listeners and the arguments to this function and if that value is the same as listeners then it returns the the brush otherwise it returns the thing that was returned by those listeners now i'm going to be honest with you i have not fully dissected and grocked everything that's happening here i just know that it works and mike bostock the author of this module must have really thought this through so i'm gonna do something a little uncharacteristic and just copy paste this whole thing without fully understanding it and of course i'll we have to change brush to my and this effectively exposes the dot on method so that you can add an event listener to this menu so now our code should work it's going to add the event listener the next thing we need to do is actually emit that event from our event listener every time that the menu changes this is where we need to iterate our rendering logic to add an event listener to the select element itself which we can do with dot on change i'm pretty sure and this will take as input an event which is the dom event that that's provided to you from from the dom environment now let's console.log event here just to see if this is working at all i'll open up the console and then if i select something from this menu we get this event it worked all right i just know from experience that you can use event.target and then unpack the value from this value is in here somewhere among all this stuff so event.target.value is how you extract the actual thing that you clicked on from this so now if i click on pedal width oops sepal width rather it's it prints out the name of the column sequel underscore width like this and if i click uh sepal length it outputs sepal length this is the value that we want to dispatch to our outer event listeners and let me again refer to d3 dispatch there is a method here called um dot call this is the method that you need to use to dispatch events to tell all of the event listeners like hey this event actually happened so what we need to do is call type and then the the context object which will resolve to dot this i'm not really a big fan of using this like we don't need to use this necessarily but the third argument is important it's the arguments that get passed so let's see how to how to actually set this up our instance of dispatch is called listeners here so in here we can say listeners.call the first argument will be the type which is the name of the event in our case it's going to be change the second argument is going to be the the context that resolves to this and i'm not i'm not a fan of using that so i'm just going to pass in null to say like this is not this is not a thing that we're doing it's not a thing that we're using but the third argument is important which is going to be event.target.value this will make it so that the name the column that you click on is passed to the outer event listener that we've defined in index.js so now let's just say console.log in index.js to be sure this is where we are now let's see did it work if i click on this thing it worked boom so i clicked on it the event sort of got forwarded through this component to the outer index.html and now in index.html we get notified when we when we change this so this is this is the pattern that you can use to introduce events to your components and let me just give another overview of how this is working we import dispatch from d3 which gives us this event emitter construct from d3 we instantiate it once when we instantiate the menu it's an instance of dispatch that only has one type of event which i'm calling change we could call it anything but i'm calling it change because that's sort of a standard name for menus we're calling that listeners in here when we render our select element we're adding a change event listener to that element which is a it's a standard um thing that emits events from the dom when we get that event we are extracting the value that was clicked on and then we're using listeners.call to essentially forward that event through our d3 dispatch construct so what this is doing it's essentially emitting a change event and it's it's just passing in uh the value which is the the name of the column that was clicked on so you know we could just pass in the event but i my preference is to to eliminate all that complexity for the external listener so that all you need to do is is use the value that was passed in to this callback here right so i i realized this is a lot this was actually pretty difficult to figure out how to do but i think it's the right pattern i want to pause now and ask you know are there any questions so far yeah the the the null that you did there that's supposed to be this and that what what's that yeah we can dig into that because i it's it's a little sort of a mysterious thing i'll pass in foo here just to demonstrate what this is in our index.js if we use the old school function syntax not the fat arrow notation to define this function then we can say console.log this and i'll get rid of all that other stuff so we can just isolate that yeah i think there's a typo in function oh whoops function now if i select something from that menu fool gets output to the console it's um it goes to like the history of javascript and object-oriented programming you know there's a bunch of patterns throughout history of javascript where people try to make it object oriented and use the keyword this extensively but i think like to me that's sort of a thing of the past like there's no need to use this at all um and it's just it's essentially another way of passing another thing into this callback in addition to the value but i personally just don't see i just don't see the the usefulness in it but if if you wanted to do it if you wanted to use this then you could um but it seems like uh we have like two combo boxes um does does it somehow chew i don't know identify which combo box are you using could be use it like this or not i mean one thing i could imagine is passing in my here so that it would resolve to the instance of our menu component in the external listener so you could say like i don't know so you could manipulate the menu or or something like that but like i said i don't really get it i don't really get the point of it it's just sort of an inherited thing from from patterns of the past that we've sort of moved away from in minor times um so that's why i don't really like to use it it's just a confusing thing um like in d3 a lot of the time this is referred is is the is the dom node but it just goes to show you in javascript the keyword this could resolve to literally anything it depends on how you invoke the function that's why i just find it confusing to use the keyword this when you're developing software um but this is it this is how it's how it could be used you could pass something in as the second argument could be anything and then in the callback if you use the old school function notation then you can use the this keyword and it will resolve to whatever you pass in as the second argument here okay um i'm not familiar with this i'm familiar with that you would listen to an event using the on and natasha a function that will that will be operated on when that event is fired and i think i missed the point why we're doing all this while we're using the d3 dispatch oh we're using d3 dispatch so that we can essentially define our own set of events in this component so we can call dot on change and pass a callback which is sort of the ideal api that i would envision for for adding an event listener and it's it's a way of decoupling the dom like what we're doing when we actually render the thing from the component itself it means we can add this event listener to our menu component and then internally that menu component can choose to fire that event anytime inside so i mean we could we could fire this event anytime it just so happens that we're listening to the change event on our select element and then essentially forwarding that event i see so for example suppose you're changing one of the selects but you want to change both of the axes you will be able to fire two events based on a selection and one of your selects if you need to well i mean if you wanted to do that then you could just change what the body of the listener does you could like set one axis and then set another you don't need necessarily two different events for that but let me revert this change because using this is confusing and i prefer the the arrow the fat arrow syntax for functions and then in our menu dot js we just pass null as the second argument so so yeah this is this is just generally the pattern that you you can use if you want to introduce events into your reusable components that you generate with this with this towards reusable charts pattern the reason why we're using d3 dispatch is so that we can control the set of events it's a generalized pattern um to be clear where you can you can set it up like this you can set up dot on like this and then you could add any sort of interaction like let's say for example you wanted to make it so that your scatter plot could listen to events when you click on the circles you could use the same pattern to accomplish that so the pattern can be the same it's just that the things that trigger those events could be different depending on whatever your component is i wanted to introduce this general pattern because it's useful in a number of different contexts whenever you want to add interaction to your to your components this just so happens to be a menu component where to know when to trigger the event we need to attach an event listener to the select dom element and then unpack it like this and then we pass it into our our change listeners like this all right now let's make it so that when we select something it actually changes the scatter plot this is the moment we've all been waiting for right we've got all this wiring set up that it you know it dispatches the event and everything this is the this is the moment of truth where we sort of connect these two things together let's look at this code that we had earlier it uses plot.x value to set the accessor and then it uses svg.callplot value in this case is actually the column so i'm going to rename it to column just because that makes more sense and then in this event listener we can say svg.call plot this will cause our scatter plot to re-render but just before we render that i'm going to call dot x value and set that x value accessor to be a brand new function that takes as input one of these rows and it returns d at column column being whatever column we just selected from the menu now if i select something it actually changes yeah this is the this is the moment where it all comes together and we can actually use a menu to select what is being displayed on the x-axis and it ends up pretty small and concise but we're getting the column from the event dispatcher and we're setting the x value accessor of our plot to be a function that accesses that particular column for x and then we're invoking our plot with svg.call and to complete this we can do the same for y but instead of saying x value we set the y value and this is it it's done we can set x and we can say y so now we can explore the data and one beautiful thing about the s the the select elements is you can actually use the arrow keys to quickly navigate between the different options so any questions does the event change on the select element files when you first render the page to make sure that you've got the first selections correct it does not that's actually a really good point when we set up our scatter plot it's defaulting to this x value is pedal width and y value is simple length but when we initialize the menus they're just getting i think the first the first option is what they're defaulting to so that's a good call out that when it loads it's actually not correct it says pedal width and it says pedal width for both x and y yep yep so that's a bug that's a bug ideally we would have something like uh initial option or what have you but just to fix the bug i'm going to initialize x value and y value both to be pedal width now at least it's it's correct and accurate when it loads but yeah good catch good catch there are a number of things we could do here to to like make it so that initially there is some some selection of the menus and the accessors that's initialized correctly but i think they'll i'll leave that as an exercise for the reader but actually here here's what i want to leave you with as an exercise for today handle species this is going to be kind of challenging the value here would be species and the text here would be species this would be the ideal situation where you could select species and it would work but right now it does not work because we're using linear scales we're using linear scales with with a thing that is is not numbers it's different strings and so if you wanted to visualize species you would need to use scale point instead and have the domain be data.map x value like this and so the challenge is set up x and y scales conditionally based on the type of attribute you've selected and and the overall goal here would be to make it so that if you select species for x the x scale would change to be a point scale not a linear scale and the axis should render correctly so that's the challenge for this week all right i think we'll wrap it up any other last questions just say thank you this is great my pleasure yeah this was um i was i was a little nervous going into this because i know it's a lot of stuff to digest um but thank you all for asking questions along the way when things were not clear and uh it's yeah it's not clear to me uh what we should see if it's if i get this passing because uh i i can imagine like uh using different icons for different species oh if i if i get like the x's as a specie um especially i don't get it because i will have like two spaces or three something like this let me just show you real quick it should be scale point which will distribute those three values across x and then the domain would be data.map x value like this so it just gets all the unique values and now if i oh scale point we need to import that from d3 and if it runs now and if i set x to species it looks like this this is what it should look like okay i got it um oh but yeah actually let's add a little bit of padding because it's all up against the edge there we can say dot padding of like 0.2 maybe and now if we select species it looks like this so this is what it should look like when you select species as x because we're using scale point all the time if we go back to one of these numeric columns it's using a point scale what it's doing is it's it's taking all the unique values that it sees and giving them a location along x which is totally not right it's totally incorrect a point scale should only be used if you have a bunch of discrete values for example three species not if you have quantities so what i envision could be the solution uh is like you have some ternary operator here like if x type is a categoric is if x type is categorical and you can create an accessor for x type then use scale point otherwise use scale linear so there's sort of a sketch of what the solution should be and i'll leave it to you to implement it and i might even implement it uh next episode if yeah the other way could be implemented is a third menu which is then a stratification variable which is says overall and then by the species i think then you would see subgroups for each of those xy plots oh yeah you mean like you'd you'd see like three scatter plots side by side you could do that or if someone wants to dive in and you'd have a menu which would be let's say z it says overall and then each of the species and so then you could select each of each species or overall so right now we're looking at overall yeah and so that would be another way that way you're not confounding that categorical variable with the actual intent of the scatter plot true yeah good call you could do it a number of ways you could use color or you could fast it into like three different plots that have the the different subsets highlighted or filtered to just show them yeah yeah totally there's a number of ways to do it yep good call and we'll be getting into those i hope to add color to the scatter plot in the future um and also do all sorts of different like aggregations like you could you could do a box plot all sorts of options many things many things to do is there a time for a very quick question on selections and join sure yeah thank you if you go back please to where you select for the label for example this one yes thank you there seems to be a pattern where you select all for a special value and then you join the same value is there a case where you would do it two different things or is it always the same you would select all for one thing and then you're showing for exact that same thing that's a great question this is the case where we're selecting on the tag name that appears here label and this string is a selector you could select by class as well if you want to but this case is simple they're the same because we know for sure that inside of any one of these given divs this is our parent that we're just going to have one label element if we know that there's only going to be one label element in here then then we can use the tag name in the select all however if there's going to be different instances of the same tag name as children of the same parent then we want to have something different which we have here in our scatter plot because we have one group element as a container for the y-axis and we have another group element as the container for the x-axis in this case then we need to somehow differentiate between the two and i think the best way to do that is with classes and this is the case where what we pass into select all will be different than what we pass into dot join what we pass into select all is a selector string that uses dot at the beginning to signify that it's going to look for an element that has that class attribute y-axis so if if there's no y-axis then it's going to create a new group element and the thing you need to pass into dot join is always going to be a tag name not a class you're not allowed to pass a class into dot join so this is a case where they could be different yeah and you need to do this like if you pass g into here and into here then this block is going to res it's going to find the group element that was left over for the y axis and it's going to use it for the x axis and you're going to get rid of your y-axis it's going to be a bug and so that this is the case where you need to differentiate between two things that are the same tag name namely a group element in for in this case with classes perfect thank you very much my pleasure and um just before we go i think um i think you're new here and and you haven't introduced yourself you want to just give a quick intro for yourself excellent and what was your name again huh great to meet you and welcome i'm so glad you could join uh thank you very much and you're welcome to join future sessions the the more the merrier i love the questions and it's just great so yeah thanks for joining very much i'll definitely will thank you all right i think i have to wrap it up for today but uh thanks everyone for joining and good luck adding thank you adding the uh you know good luck making the species work thank you thank you all right all right take care everyone bye thanks thank you bye
Info
Channel: Curran Kelleher
Views: 517
Rating: 5 out of 5
Keywords:
Id: hfSiXlTN6g4
Channel Id: undefined
Length: 90min 30sec (5430 seconds)
Published: Sat May 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.