Excellent video Curran! I came for Object Constancy, but was re-educated on Enter, Update, Exit and introduced to Merge as well. I think PBS should offer you a show.
Great video! Also, it's worth using `.classed('fruit', true)` after the `append`, and selecting on the class with `svg.selectAll('.fruit')` instead of selecting on `circle`. The reason is manifold. The SVG element may change to some other SVG tag, often, a `g` element which groups other things, eg. the shape of the apple, annotation, tooltip... There's also the risk that `svg` will have another children which are also circles, confusing the updates, D3 doesn't know which is which. (For this reason, it's good to attach the fruits not to the `svg` but a `g` underneath `svg`). Sure the class can be added later, as the scenegraph grows, but it's error prone. So, as a matter of principle, I always select on and assign a class that has some meaning. Similarly, I always use the second argument of `.data()` ie. the key function, even if I have no immediate plans for updates - again, no need to think about it if new requirements emerge.
I'm intentionally following the YAGNI principle (You Ain't Gonna Need It) for these teaching videos, but you make a great point and I do plan to cover this case - but using a "Just in time" approach (meaning, when it's actually required and things would break without it) rather than a "Just in case" approach (as you suggest). To me it feels a bit like premature optimization to use classes when they are not necessary.
Thanks Curran! Your work on emphasizing the GUP is important; without its use, most folks are still able to do most of the updating functions, though in non-idiomatic, hard to maintain ways. Saw a lot of code that used D3 as if it were jQuery - making separate render and destroy functions etc. We could argue that, as long as such imperative approaches do the job, there's no need for the GUP. And it's technically true. But somehow, despite often ignoring it, the GUP feels fundamental to D3 (unless maybe for content that'll be static forever), one only need to reread the original D3 research papers by Bostock et al. So it's great you have a video on it, will help a ton of folks, even if it can be a YAGNI for some. I also feel (maybe just my experience long ago) that folks run into a scalability issue with the tag-based approach. Build anything nested, or refactor your own code using a different choice of tags and there's a steep threshold. I feel it's little extra to use classes (one selects on something anyway; so it's just the `.classed('fruit', true)`. Good to ingrain habits that lead to scalable code early on - classes are useful for other things, eg. attaching CSS styles to it, or making scenegraphs easier to decipher in the Dev Tools. Some folks use the GUP for single-layer rendering but balk at it when the scenegraph becomes hierarchical, which usually happens. On the key functions, the GUP bl.ocks trilogy (bl.ocks.org/mbostock/3808221) also mentions why the second arg to `.data(whatevs, keyAccessorFunction)` is needed. Haha looks like it boils down to the question of how granular the videos are :-) Here's an example with pretty boring (therefore, easy to code in autopilot mode, preserving brainpower for other things) patterns that yield some nested views, though not all lifecycle events are covered: codepen.io/monfera/pen/dppavk?editors=0010#0 Sometimes I used a small utility (dubbed `bind`) that extracts out the repeated structures, variable and class names, going even more overboard than the similar facility in `d3-jetpack`. An example is here: github.com/monfera/sf-student-dashboard/blob/master/bandline.js#L68-L72 - similar to your reactive stuff in that the chosen name - used as the classname as well - will be the property name on a global object that holds all the D3 selections. Not suggesting this particular `bind` style to anyone, just mentioning that D3 is a more low-level library than maybe how most people expect it, and patterns (proactive class selections, key functions etc.) or their encapsulating utilities can help folks avoid tripping up. I wonder what the benefits of _not_ using class names are, as this practice is common and I may be the one missing something. I also often find that a lot of D3 code works for a particular use - eg. static render, or with the assumption that only very specific data can change. So each selection/update block is highly individual. It saves some code bytes, but I don't know how people can work with it efficiently, as even small extensions may require significant code shape shifts. Glad to be pointed to articles etc. about the "boring, repeatable, just in case" data binding pattern vs. the "YAGNI, code no more than what's needed" custom, diverse binding structures. Your own use of `.data([null])` is an example for the former. You could've done away with the singleton altogether (by directly binding the data to the DOM nodes one level below), I think it's neat that you kept it, it's a bit in the spirit of "Just in case; use this regular pattern, folks" :-)
It's an interesting space of tradeoffs, for sure. As we move forward into interactions, I'm going to start using the General Update Pattern _all the time_, even though it is "just in case" in a way, because I know for a fact we'll need to handle all the cases. It's true the singleton here was a bit contrived - you're right I could have avoided it, but I wanted to show how to handle this case with the GUP so you can have a tree of "components" that are responsible for managing certain parts of the DOM. I'm a huge fan of your student dashboard by the way. In fact just yesterday I dug into it a bit, and also read Stephen Few's commentary on the work. This might be a great example to reproduce again, with the component pattern from this video and the modern niceties of ES6!
I've been trying to wrap my head around enter and exit functions for a while.thanks for the video. The way you explain is crystal clear. If you accept crypto as donations. please share the address in the description. I would like to send you some.
The benefit of thinking in terms of sets, even if you have a single occurrence, is that 1. you're using the same mechanism as for multi-element sets, ie. no need to learn one more API thingie; 2. you're doing something to avoid the problem of singletons - often, a new requirement comes, "can we build a small multiples chart from this single chart, splitting by some dimension". Then, all you need to do is, use multiple elements in the array, and translate the charts (using the index `i`) so they aren't rendered overlapping one another. So, as a habit, I use `{key: 0}` and `.data([{key: 0}], d => d.key)` for singletons, instead of using `.data([null])` or the shorter `.data([0])`. In short, I see it more of a feature than as a hack, and prefer that there's no API covering this edge case (as there's no API for covering the edge case of zero elements, just use `[]` eg. in an update). The analogy is that in SQL, some config etc. data live as a single row in some table, yet there's no call for turning such tables into some special singleton thing (afaik).
thanks curran this is a nicely done tutorial that i’ll review before my next d3 project. neat es6 stuff too
Great tutorial! I struggled a bit to understand the concepts behind d3 and your video helped a lot! Thanks a lot!
Finally a proper explanation of the update pattern. Thank you!
Thanks! Although TBH it's a dated pattern at this point. Look into the newer .join API. The core concepts remain the same, but API is different.
@@currankelleher thanks again!
@@80amnesia My pleasure! Join the VizHub Discord if you're interested in joining a community of learning around this stuff
Excellent explanation of d3 core concepts. Thanks a lot Curran.
Great video that finally got me over the hump understanding these basic concepts of D3. Thank you.
The way you explain things is just phenomenal! Keep it up!
Excellent explanation. Great work. Thank you Curran
This is a really good explanation and understanding these makes working with D3 easier.
I'm just starting my d3.js journey and didn't understand a word you said.
I'll come back to this video in a few weeks.
Try coding along with it too and experiment as you go. Repetition helps as well. Good luck!
Excellent video Curran! I came for Object Constancy, but was re-educated on Enter, Update, Exit and introduced to Merge as well. I think PBS should offer you a show.
Thanks Curran. Very appreciated.
@8:41 the udpate part is when there are data elements and DOM elements that correspond to those data elements
@8:48 and exit is for when there are elements--DOM elements--on the page that don't have any corresponding data elements
@8:35 the enter part is where there are data elements but no corresponding DOM elements
Awesome tutorial! Thank you!
Really good video Curran!
thank you!
Thanks for this tut I am going to use this knowledge to build something great!
So clear! So clean!
Thanks, great tutorial!
Wow! What an excellent tutorial!!! Thank u very much!
Great explanation!
Great video! Also, it's worth using `.classed('fruit', true)` after the `append`, and selecting on the class with `svg.selectAll('.fruit')` instead of selecting on `circle`. The reason is manifold. The SVG element may change to some other SVG tag, often, a `g` element which groups other things, eg. the shape of the apple, annotation, tooltip... There's also the risk that `svg` will have another children which are also circles, confusing the updates, D3 doesn't know which is which. (For this reason, it's good to attach the fruits not to the `svg` but a `g` underneath `svg`). Sure the class can be added later, as the scenegraph grows, but it's error prone. So, as a matter of principle, I always select on and assign a class that has some meaning. Similarly, I always use the second argument of `.data()` ie. the key function, even if I have no immediate plans for updates - again, no need to think about it if new requirements emerge.
I'm intentionally following the YAGNI principle (You Ain't Gonna Need It) for these teaching videos, but you make a great point and I do plan to cover this case - but using a "Just in time" approach (meaning, when it's actually required and things would break without it) rather than a "Just in case" approach (as you suggest). To me it feels a bit like premature optimization to use classes when they are not necessary.
Thanks Curran! Your work on emphasizing the GUP is important; without its use, most folks are still able to do most of the updating functions, though in non-idiomatic, hard to maintain ways. Saw a lot of code that used D3 as if it were jQuery - making separate render and destroy functions etc. We could argue that, as long as such imperative approaches do the job, there's no need for the GUP. And it's technically true. But somehow, despite often ignoring it, the GUP feels fundamental to D3 (unless maybe for content that'll be static forever), one only need to reread the original D3 research papers by Bostock et al. So it's great you have a video on it, will help a ton of folks, even if it can be a YAGNI for some. I also feel (maybe just my experience long ago) that folks run into a scalability issue with the tag-based approach.
Build anything nested, or refactor your own code using a different choice of tags and there's a steep threshold. I feel it's little extra to use classes (one selects on something anyway; so it's just the `.classed('fruit', true)`. Good to ingrain habits that lead to scalable code early on - classes are useful for other things, eg. attaching CSS styles to it, or making scenegraphs easier to decipher in the Dev Tools. Some folks use the GUP for single-layer rendering but balk at it when the scenegraph becomes hierarchical, which usually happens.
On the key functions, the GUP bl.ocks trilogy (bl.ocks.org/mbostock/3808221) also mentions why the second arg to `.data(whatevs, keyAccessorFunction)` is needed. Haha looks like it boils down to the question of how granular the videos are :-)
Here's an example with pretty boring (therefore, easy to code in autopilot mode, preserving brainpower for other things) patterns that yield some nested views, though not all lifecycle events are covered: codepen.io/monfera/pen/dppavk?editors=0010#0
Sometimes I used a small utility (dubbed `bind`) that extracts out the repeated structures, variable and class names, going even more overboard than the similar facility in `d3-jetpack`. An example is here: github.com/monfera/sf-student-dashboard/blob/master/bandline.js#L68-L72 - similar to your reactive stuff in that the chosen name - used as the classname as well - will be the property name on a global object that holds all the D3 selections.
Not suggesting this particular `bind` style to anyone, just mentioning that D3 is a more low-level library than maybe how most people expect it, and patterns (proactive class selections, key functions etc.) or their encapsulating utilities can help folks avoid tripping up.
I wonder what the benefits of _not_ using class names are, as this practice is common and I may be the one missing something. I also often find that a lot of D3 code works for a particular use - eg. static render, or with the assumption that only very specific data can change. So each selection/update block is highly individual. It saves some code bytes, but I don't know how people can work with it efficiently, as even small extensions may require significant code shape shifts. Glad to be pointed to articles etc. about the "boring, repeatable, just in case" data binding pattern vs. the "YAGNI, code no more than what's needed" custom, diverse binding structures. Your own use of `.data([null])` is an example for the former. You could've done away with the singleton altogether (by directly binding the data to the DOM nodes one level below), I think it's neat that you kept it, it's a bit in the spirit of "Just in case; use this regular pattern, folks" :-)
It's an interesting space of tradeoffs, for sure. As we move forward into interactions, I'm going to start using the General Update Pattern _all the time_, even though it is "just in case" in a way, because I know for a fact we'll need to handle all the cases.
It's true the singleton here was a bit contrived - you're right I could have avoided it, but I wanted to show how to handle this case with the GUP so you can have a tree of "components" that are responsible for managing certain parts of the DOM.
I'm a huge fan of your student dashboard by the way. In fact just yesterday I dug into it a bit, and also read Stephen Few's commentary on the work. This might be a great example to reproduce again, with the component pattern from this video and the modern niceties of ES6!
You are a real super start my friend
Wow, really nice video! Thanks!
I've been trying to wrap my head around enter and exit functions for a while.thanks for the video. The way you explain is crystal clear. If you accept crypto as donations. please share the address in the description. I would like to send you some.
that single element thing looks like a hack and not a feature, doesn't it? that "data([null])" thing, like a knack
Agreed it feels like a bit of a hack. This is IMO a weak point of D3.
great tutorial by the way!!!
The benefit of thinking in terms of sets, even if you have a single occurrence, is that 1. you're using the same mechanism as for multi-element sets, ie. no need to learn one more API thingie; 2. you're doing something to avoid the problem of singletons - often, a new requirement comes, "can we build a small multiples chart from this single chart, splitting by some dimension". Then, all you need to do is, use multiple elements in the array, and translate the charts (using the index `i`) so they aren't rendered overlapping one another. So, as a habit, I use `{key: 0}` and `.data([{key: 0}], d => d.key)` for singletons, instead of using `.data([null])` or the shorter `.data([0])`. In short, I see it more of a feature than as a hack, and prefer that there's no API covering this edge case (as there's no API for covering the edge case of zero elements, just use `[]` eg. in an update). The analogy is that in SQL, some config etc. data live as a single row in some table, yet there's no call for turning such tables into some special singleton thing (afaik).
Robert Monfera Thank you
@@monfera when are you going to shoot your 1st tutorial?
Great explanation - thanks!