Sorting a bar chart via button

Hi all,
I am trying to add some transitions to the sample bar chart example.
It somehow works with the text portion of the chart, but not with the bars itself. Though after playing for it too long, now also the text part seems to do something else :sweat_smile:

edit2: I was able to do it, however I think itā€™s probably not a good way. If someone can still have some tips on how I can do this in a better and smarter way, please let me know it is much appreciated as I am still learning and this feedback is valuable.

This is my fork

the click registers and the chart gets sorted.

edit1: playing around with it more, I remember in one of the tutorials it was mentioned what we need to keep an index when joining data so d3 knows the ordering.
Unfortunately I couldnā€™t find this tutorial anymore and I donā€™t remember the exact syntax.
The update pattern does work though with transitions as intended (if comment out sorted to be filtered you can see it).

I am grateful for any help and tips on what I am doing wrong and why.
Thanks in advance!

Hey Oliver,

Happy to help! Iā€™ve forked a version of this and shared with you the notebook. (Hereā€™s the link as well.)

You were very close to getting the update to work correctly, you just needed to specify the id for joining data. (As you noted the index, which can work in some cases, but since here you are sorting the data, you want a better identifying, given the index changes after sort!) I added ā€œflavorā€ as the id, which now gets the sort to work correctly. Also, I added a conditional to your click function so you can sort and unsort the data. Hope this helps! Let me know if you have any more questions.

Best,
Paul

2 Likes

thanks a lot Paul! :heart:
With added ā€œflavorā€ as id you mean this line:
.data(data, d => d.flavors)
I think this is what I was trying to recall from some long ago tutorial here on observable that I couldnā€™t find again.

So this lets me set the id of the data so that d3 remembers the items, do I recall that correctly?

Yup, just like if you were joining two tables in SQL, you need to provide a unique ID for doing so, this works the exact same way!

@pstuffa Thatā€™s pretty nice! Iā€™m curious, though: Your code accesses the button via a call to d3.select, which is generally discouraged in Observable. I guess the point is to avoid circular references but there are other approaches as well. I know that @mootari is a strong advocate of dispatching events, as described in his viewof notebook. Personally, I simply attach a function directly to the button that acts on the image I want to transition. Hereā€™s and example that I was working on for another project:

Since Iā€™ve been summoned, I might as well share my perspective :sweat_smile:

d3.select() with a selector string is indeed an anti pattern. But attaching the listener in the cell is sensible if it also gets removed on invalidation - which is currently not the case.

So a better approach would be:

d3.select(viewof button).on('click.animation', click);
invalidation.then(() => d3.select(viewof button).on('click.animation', null));

Note that we namespace the event here, because otherwise all click handlers get removed - something that we might not want or expect.

I also want to point out that button can be declared without viewof since only the DOM element is referenced.

Another strategy I like to use (if I only observe a single viewof cell) is Generators.input. This becomes especially powerful in combination with Inputs.form() which lets you combine multiple inputs in a single viewof cell. We can create an update loop that only runs when we receive new inputs:

for await(const value of Generators.input(viewof button)) {
  // do animating stuff.
}
1 Like

Yup, lots of great ways to go about it, and I was just leaving Oliverā€™s code for that section, since he was primarily asking about the update pattern.

Personally, I like this approach for simplicity. Lots of great ways go about it though, and I think it does depend on what your goals are. If youā€™re learning D3 and wanting to trigger a change, I think the simpler the better :smile:

2 Likes

Thanks all! Yes, this is leftover from my code and I appreciate that Paul only changed it minimally so I was able to understand it better. Please donā€™t blame him for my newbie mistakes :sweat_smile: .

1 Like