wlavell
wlavell

Reputation: 51

How to invert d3 color ramps d3-scale-chromatic d3.interpolateViridis

I am trying to invert the color ramp for this sunburst visualization. It is using the sunburst zoomable chart with labels etc.. Normally, you would just invert the values in the range that they are using but I don't quite understand how it is getting the values in how this is set up.

This is the color schemes I am using https://github.com/d3/d3-scale-chromatic

d3.interpolateViridis

Currently it is going from dark purple to bright yellow and I need to invert the colors to go from bright yellow to dark purple. So I need to change the range value starting point. But I am not understanding how he does it below.

The suggested approaches have been to change the range and start with the highest value first for the range. But it does not seem to work.

require()('@observablehq/flare').then(data => {
const root = partition(data);
const color = 
d3.scaleOrdinal().range(d3.quantize(d3.interpolateViridis, 
data.children.length +1));

console.log(data.children.length)
root.each(d => d.current = d);

const svg = d3.select('#partitionSVG')
        .style("width", "50%")
        .style("height", "80%")
        .style("font", "10px sans-serif")

const g = svg.append("g")
        .attr('transform', 'translate(' + width/2 +  ',' + height/2 +')');

const path = g.append("g")
        .selectAll("path")
        .data(root.descendants().slice(1))
        .join("path")
        .attr("fill", d => {
            while (d.depth > 1)
                d = d.parent;
            return color(d.data.name);
        })
        .attr("fill-opacity", d => arcVisible(d.current) ? (d.children ? 0.6 : 0.4) : 0)
        .attr("d", d => arc(d.current));

Upvotes: 4

Views: 1741

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

The interpolator simply gets a number going from 0 to 1 to return the colours. For instance:

.style("background-color", function(_, i, n) {
    return d3.interpolateViridis(i / n.length)
})

const body = d3.select("body");
const data = d3.range(100);
const divs = body.selectAll(null)
  .data(data)
  .enter()
  .append("div")
  .style("background-color", function(_, i, n) {
    return d3.interpolateViridis(i / n.length)
  })
div {
  width: 5px;
  height: 100px;
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Therefore, the only thing you need you need is passing the number in the opposite range. For my example above, that would be:

.style("background-color", function(_, i, n) {
    return d3.interpolateViridis((n.length - i)/n.length)
})

const body = d3.select("body");
const data = d3.range(100);
const divs = body.selectAll(null)
  .data(data)
  .enter()
  .append("div")
  .style("background-color", function(_, i, n) {
    return d3.interpolateViridis((n.length - i)/n.length)
  })
div {
  width: 5px;
  height: 100px;
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

However, your case is even easier: you're using d3.quantize to generate the array for the ordinal scale. Like this:

const values = d3.quantize(d3.interpolateViridis, data.length);

const data = d3.range(100);
const values = d3.quantize(d3.interpolateViridis, data.length);
console.log(values)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Therefore, all you need is to reverse that array:

const values = d3.quantize(d3.interpolateViridis, data.length).reverse();

And here is the result:

const body = d3.select("body");
const data = d3.range(100);
const values = d3.quantize(d3.interpolateViridis,
  data.length).reverse();
const divs = body.selectAll(null)
  .data(data)
  .enter()
  .append("div")
  .style("background-color", function(_, i) {
    return values[i];
  })
div {
  width: 5px;
  height: 100px;
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Upvotes: 4

Related Questions