Coloring Custom Tree Graph nodes based on Datapoint's String Date

I am trying to implement a custom tree visualization using Tree, Tidy / D3 | Observable Tree source as a base. I am having trouble implementing colors based on dates. Most new documentation used the new Plot API’s color schemes, which I don’t believe I can use as-is, or can I?

I am trying to fill in the circle nodes to be colored based on dates. So I thought I would try out d3.scaleTime(). I have scaled it down as much as possible to just get the colors to display, but I am unable to do even that.

My understanding is that thed3.scaleTime() will return a function. I am calling that fill_color for now. I am setting the domain to be from 2021-11-24 until today, and I am mapping that to a range that I hope will interprolate between green and red. I am taking that fill_color function and passing it a parsed Date from that datapoint’s date reference.

This results in the fill being black.

In the future, I want to map week numbers to colors (maybe using a diverging color scheme). See what that looks like I do want to create another visualization that only modifies the most recent week number datapoint node’s circle, radius, and text attributes. But I can’t even get this simple example working yet.

Calling Code

Tree(lineages, { label: (d) => d.lineage.pango, width: 1000 })

Snippet of Tree(...)

const node = svg
    .append("g")
    .selectAll("a")
    .data(root.descendants())
    .join("a")
    .attr("xlink:href", link == null ? null : (d) => link(d.data, d))
    .attr("target", link == null ? null : linkTarget)
    .attr("transform", (d) => `translate(${d.y},${d.x})`);

  let fill_color = d3
    .scaleTime()
    .domain([Date.parse("2021-11-24"), Date.now()])
    .range(["green", "red"]);

  node
    .append("circle")
    .attr(
      "fill",
      fill_color((d) => Date.parse(d.lineage.designation_date))
    )
    .attr("r", r);

My data is set up as followed. Children objects are the same format

lineages = Object {
  children: Array(5) [Object, Object, Object, Object, Object]
  height: 0
  id: "B.1.1.529"
  lineage: Object {
    designation_date: "2021-11-24"
    pango: "B.1.1.529"
    partial: "BA"
    unaliased: "B.1.1.529"
  }
  parent_ids: null
  parents: Array(0) []
}

This syntax isn’t quite right; you are passing your scale function a function, rather than the data value you intend to scale. Also, the node data d here represents a node in the hierarchy; if you want to access your input data, it’s doing to be d.data. See node.data.

So, try this:

  node.append("circle").attr("fill", (d) => fill_color(Date.parse(d.data.lineage.designation_date))).attr("r", r);

If you want to use a named color scheme in D3, you can use a sequential scale:

  let fill_color = d3
    .scaleSequential()
    .domain([Date.parse("2021-11-24"), Date.now()])
    .interpolator(d3.interpolateTurbo);
1 Like

Glad that I was at least somewhat on the right path. Thanks for explaining the fill_color mistake. Now I have something that I can build off of