change the range of yAxis ticks D3

790 Views Asked by At

I need to change the range for yAxis ticks in my d3 chart. Currently, it has a range of 2M and looks like this: enter image description here

The majority of data is spread between 0 and 4M. I would like to have a smaller range for ticks up until 4M and then a bigger range. So I would have ticks for 1M, 2M, 3M, 4M and then 8M, 12M, 16M. Here is the code:

const width = 1000;
const height = 700;
const padding = 120; // between title and svg borders
const marginTop = 120;

// Min and max for y axis for Revenue values
const maxRevenue = d3.max(dataset, (d) => d[1]);
const minRevenue = d3.min(dataset, (d) => d[1]);

const yScale = d3
  .scaleLinear()
  .domain([minRevenue, maxRevenue])
  .range([height - padding, marginTop]);

const yAxis = d3.axisLeft(yScale);

svg
  .append("g")
  .attr("transform", `translate(${padding}, 0)`)
  .call(yAxis); // if need to move the chart to the right (for yaxis)
1

There are 1 best solutions below

0
On

My recommendation is to use a "split" y-axis. Something like this:

<html>
  <meta charset="utf-8" />
  <style>
    /* set the CSS */

    .bar {
      fill: steelblue;
    }
  </style>
  <body>
    <!-- load the d3.js library -->
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <script>
      // set the dimensions and margins of the graph
      var margin = { top: 20, right: 20, bottom: 30, left: 100 },
        width = 500 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom,
        pbottomsize = 0.66,
        ptopsize = 0.25;

      // set the ranges
      var xd = ['A', 'B', 'C', 'D'];
      var x = d3.scaleBand().range([0, width]).padding(0.1).domain(xd);
      var y = d3.scaleLinear().range([height * pbottomsize, 0]).domain([0, 20]);
      var y1 = d3.scaleLinear().range([height * ptopsize, 0]).domain([1000000, 2000000]);

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

      var g1 = svg
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + (margin.top + height * 0.33) + ')');

      var g2 = svg
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      var data = d3.range(1, 100).map(function (d, i) {
        return {
          x: xd[Math.floor(Math.random() * xd.length)],
          y: Math.random() < 0.75 ? Math.random() * 20 : (Math.random() + 1) * 1000000,
        };
      });

      var data0 = data.filter(function(d){
        return d.y < 1000000;
      });

      var data1 = data.filter(function(d){
        return d.y > 1000000;
      })

      // append the rectangles for the bar chart
      g1
        .selectAll('.circle')
        .data(data0)
        .enter()
        .append('circle')
        .attr('cx', function (d) {
          return x(d.x) + (x.bandwidth() / 2);
        })
        .attr('r', 10)
        .attr('cy', function (d) {
          return y(d.y);
        })
        .style('fill', 'steelblue');

      g2
        .selectAll('.circle')
        .data(data1)
        .enter()
        .append('circle')
        .attr('cx', function (d) {
          return x(d.x) + (x.bandwidth() / 2);
        })
        .attr('r', 10)
        .attr('cy', function (d) {
          return y1(d.y);
        })
        .style('fill', 'red');

      // add the x Axis
      g1
        .append('g')
        .attr('transform', 'translate(0,' + (height * pbottomsize) + ')')
        .call(d3.axisBottom(x));

      // add the y Axis
      g1.append('g').call(d3.axisLeft(y));

      g2.append('g').call(d3.axisLeft(y1).ticks(3));

      var g3 = svg.append('g')
        .attr('transform', 'translate(' + 70.5 + ',' + 136 + ')')

      g3.append('path')
        .attr('d', 'M 10 10 Q 20 0, 30 10 T 50 10 M 30 10 L 30 -2')
        .attr('stroke', 'black')
        .attr('fill', 'none');

      g3.append('path')
        .attr('d', 'M 10 20 Q 20 10, 30 20 T 50 20 M 30 20 L 30 32')
        .attr('stroke', 'black')
        .attr('fill', 'none');
        
    </script>
  </body>
</html>