Skip to content Skip to sidebar Skip to footer

How To Implement D3 Scales To Have Children Inherit Colour From Parent With Graduations?

I have a D3.js tree that have different colours applied to nodes and links. The colouring is hardcoded: nodeUpdate.select('circle') .attr('r', 10) .style('fill', func

Solution 1:

The scale you need is an ordinal scale, like this:

var colourScale = d3.scale.ordinal()
    .domain(["Top Level","Second A", "Second B", "Second C", "Second D"])
    .range(["blue","red", "green", "purple", "gold"]);

Then, you can change this whole thing...

.style("fill", function(d) {
    if (d.name == "Top Level") {
        return d._children ? "blue" : "#fff";
    }
    if (d.name == "Second A") {
        return d._children ? "red" : "#fff";
    }
    if (d.name == "Second B") {
        return d._children ? "green" : "#fff";
    }
    if (d.name == "Second C") {
        return d._children ? "purple" : "#fff";
    }
    if (d.name == "Second D") {
        return d._children ? "gold" : "#fff";
    }
})

...into just:

.style("fill", function(d) {
    returncolourScale(d.name)
})

And also get rid of that linkColor function.

Pay attention to the fact that, despite you have linked D3 v5 documentation, you're using D3 v3.

Here is your code with that change:

var treeData = [{
  "name": "Top Level",
  "children": [{
    "name": "Second A",
    "children": [{
      "name": "Third A"
    }, {
      "name": "Third B"
    }]
  }, {
    "name": "Second B",
    "children": [{
      "name": "Third C"
    }, {
      "name": "Third D"
    }]
  }, {
    "name": "Second C",
    "children": [{
      "name": "Third E"
    }, {
      "name": "Third F"
    }]
  }, {
    "name": "Second D",
    "children": [{
      "name": "Third G"
    }, {
      "name": "Third H"
    }, ]
  }, ]
}];

var colourScale = d3.scale.ordinal()
  .domain(["Top Level", "Second A", "Second B", "Second C", "Second D"])
  .range(["blue", "red", "green", "purple", "gold"]);


// ************** Generate the tree diagram	 *****************var margin = {
    top: 20,
    right: 120,
    bottom: 20,
    left: 120
  },
  width = 960 - margin.right - margin.left,
  height = 500 - margin.top - margin.bottom;

var i = 0,
  duration = 750,
  root;

var tree = d3.layout.tree()
  .size([height, width]);

var diagonal = d3.svg.diagonal()
  .projection(function(d) {
    return [d.y, d.x];
  });

var svg = d3.select("body").append("svg")
  .attr("width", width + margin.right + margin.left)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;

update(root);

d3.select(self.frameElement).style("height", "500px");


// Collapse after the second level
root.children.forEach(collapse);

update(root);

// Collapse the node and all it's childrenfunctioncollapse(d) {
  if (d.children) {
    d._children = d.children
    d._children.forEach(collapse)
    d.children = null
  }
}

functionupdate(source) {



  // Compute the new tree layout.var nodes = tree.nodes(root).reverse(),
    links = tree.links(nodes);

  // Normalize for fixed-depth.
  nodes.forEach(function(d) {
    d.y = d.depth * 180;
  });

  // Update the nodes…var node = svg.selectAll("g.node")
    .data(nodes, function(d) {
      return d.id || (d.id = ++i);
    });

  // Enter any new nodes at the parent's previous position.var nodeEnter = node.enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) {
      return"translate(" + source.y0 + "," + source.x0 + ")";
    })
    .on("click", click);

  nodeEnter.append("circle")
    .attr("r", 1e-6)
    .style("fill", function(d) {
      return d._children ? "#C0C0C0" : "#fff";
    });

  nodeEnter.append("text")
    .attr("x", function(d) {
      return d.children || d._children ? -13 : 13;
    })
    .attr("dy", ".35em")
    .attr("text-anchor", function(d) {
      return d.children || d._children ? "end" : "start";
    })
    .text(function(d) {
      return d.name;
    })
    .style("fill-opacity", 1e-6);

  // Transition nodes to their new position.var nodeUpdate = node.transition()
    .duration(duration)
    .attr("transform", function(d) {
      return"translate(" + d.y + "," + d.x + ")";
    });

  nodeUpdate.select("circle")
    .attr("r", 10)
    .style("fill", function(d) {
      return d.depth === 2 ? colourScale(d.parent.name) : colourScale(d.name);
    })
    .style("stroke", function(d) {
      return d.depth === 2 ? colourScale(d.parent.name) : colourScale(d.name);
    });

  nodeUpdate.select("text")
    .style("fill-opacity", 1);

  // Transition exiting nodes to the parent's new position.var nodeExit = node.exit().transition()
    .duration(duration)
    .attr("transform", function(d) {
      return"translate(" + source.y + "," + source.x + ")";
    })
    .remove();

  nodeExit.select("circle")
    .attr("r", 1e-6);

  nodeExit.select("text")
    .style("fill-opacity", 1e-6);

  // Update the links…var link = svg.selectAll("path.link")
    .data(links, function(d) {
      return d.target.id;
    });

  // Enter any new links at the parent's previous position.
  link.enter().insert("path", "g")
    .attr("class", "link")
    .attr("stroke-width", function(d) {
      return1;
    })
    .attr("d", function(d) {
      var o = {
        x: source.x0,
        y: source.y0
      };
      returndiagonal({
        source: o,
        target: o
      });
    })
    .style("stroke", function(d) {
      return d.target.depth === 2 ? colourScale(d.target.parent.name) : colourScale(d.target.name);
    });

  // Transition links to their new position.
  link.transition()
    .duration(duration)
    .attr("d", diagonal);

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
    .duration(duration)
    .attr("d", function(d) {
      var o = {
        x: source.x,
        y: source.y
      };
      returndiagonal({
        source: o,
        target: o
      });
    })
    .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });
}


// Toggle children on click.functionclick(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  update(d);
}
.node {
  cursor: pointer;
}

.node circle {
  fill: #fff;
  stroke: #C0C0C0;
  stroke-width: 1.5px;
}

.node text {
  font: 10px sans-serif;
}

.link {
  fill: none;
  stroke: #C0C0C0;
  stroke-width: 1.5px;
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>

Post a Comment for "How To Implement D3 Scales To Have Children Inherit Colour From Parent With Graduations?"