Display layers with d3js without rewriting the whole map?

Small question about d3.js… I made a small example of a notebook that allows you to display a map and to choose the layers to display.

But by doing so, I rewrite the entire map each time. What would be a good way to display/hide layers without redrawing the whole map each time?


The general idea is to attach an update function to the SVG and then add a cell that calls that update function in response to a change in the input. That reaction cell refers to the button but the map does not. As a bonus, it’s not now easy to fade the layers in and out using a transition.

Here’s your map using this approach:


If you want to avoid using side effect cells, you can instead invert control by listening for input events from within your chart. Here is an adaptation of Mark’s example. Place this code at the end of your map cell.

  // ...
  function fade(group, opacity, duration = 500) {
    group.transition().duration(duration).attr("opacity", opacity);
  for await(const layers of Generators.input(viewof layers)) {
    for(const name of ["aus", "ports", "roads"]) {
      const group = svg.select(`g.${name}`).interrupt();
      const opacity = group.attr("opacity");
      const selected = layers.includes(name);
      if(selected && opacity < 1) fade(group, 1);
      else if(!selected && opacity > 0) fade(group, 0);
    yield svg.node();

A little bit late but I usually reuse the cell’s this object to avoid having side effect cells. I find mootari’s solution more “the observable way”. but here is an example of what i’m talking about (solution 4):

1 Like

@stardisblue It’s pretty cool the way that you’ve gathered several of these approaches into one notebook! I’ve just sent you a suggestion that includes yet another approach, which might seem natural to anyone who started with D3 nearly 10 years ago.

1 Like

You give me too much credit, I simply forked the notebook :smiley:.
I still merged your contribution for completness.