D3 Reactangle Bar with color gradient depending on value

Viewed 189

I am trying to build something as attached below but not able to figure out how to get it done using d3. I tried using x-axis for scale band and placing a rectangle on it but that doesn't seems to work as the axis and rectangle do not sync with the values. Can someone help me with the approach on how to get this done or some relevant examples maybe can be of good help.

The graph shows the revenue and the more good the numbers are the gradient of colors increases accordingly.

enter image description here

1 Answers

Here is a D3 example with x-axis and linear gradients:

const data = [2.3, 2.5, 3.4, 8.7, 7.8, 2.8, 2.2, 1.7];
        
// Create scale
const scale = d3.scaleLinear().domain([17, 20.5]).range([0, 400]);
                      
const tickFormat = val => {
  const year = Math.floor(val);
  const quarter = val - year  === 0.5 ? 4 : 2;
  return `${quarter}Q ${year}`;
}


// Add scales to axis
const x_axis = d3.axisBottom().scale(scale).tickFormat(tickFormat);

const svg = d3.select('svg');
    
//Insert axis
svg.append("g").attr('transform', 'translate(50,100)').call(x_axis);


const step = 400 / (data.length - 1);  

const valuesContainer = svg.append('g').attr('transform', 'translate(50,50)')

valuesContainer.selectAll('text.value')
  .data(data, (d, i) => i)
  .enter()
  .append('text')
  .classed('value', true)
  .text(d => `${d}%`)
  .attr('x', (d, i) => i * step)
  .attr('text-anchor', 'middle')
  .style('font-family', 'sans-serif')
  .style('font-size', '12px');
      
const ranges = data.slice(0, data.length - 1)
  .map((v, i) => ({from: v, to: data[i + 1]}));
      
      
const rangesContainer = svg.append('g')
  .attr('transform', 'translate(50,60)')
    
const gradients = svg.selectAll('linearGradient')
  .data(ranges, (d, i) => i)
  .enter()
  .append('linearGradient')
  .attr('id', (d, i) => `grad-${i}`)
  .attr('x1', '0%')
  .attr('x2', '100%')
      
gradients.append('stop')
  .attr('offset', '0%')
  .attr('stop-color', '#008')
  .attr('stop-opacity', d => d.from / 10);
    
gradients.append('stop')
  .attr('offset', '100%')
  .attr('stop-color', '#008')
  .attr('stop-opacity', d => d.to / 10);
      
rangesContainer.selectAll('rect.range')
  .data(ranges, (d, i) => i)
  .enter()
  .append('rect')
  .classed('range', true)
  .style('fill',(d, i) => `url(#grad-${i})`)
  .attr('x', (d, i) => i * step)
  .attr('width', step)
  .attr('height', 30)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="150">
  
</svg>

Related