Custom Y axis label and tick in d3

I am working with d3 to create and svg as following

// 1 DATA 

const data = [
    { "x": 50, "y": 0.10 },
    { "x": 100, "y": 0.15 },
    { "x": 150, "y": 0.25 },
    { "x": 200, "y": 0.35 },
    { "x": 250, "y": 0.45 },
    { "x": 300, "y": 0.55 },
    { "x": 350, "y": 0.65 },
    { "x": 400, "y": 0.75 },
    { "x": 450, "y": 0.85 },
    { "x": 500, "y": 0.87 },
    { "x": 550, "y": 0.92 },
    { "x": 600, "y": 0.98 }
]

height = 400,
  width = 720;

padding = {
  top: 70,
  bottom: 50,
  left: 70,
  right: 70
}


const boundHeight = height - padding.top - padding.bottom;
const boundWidth = width - padding.right - padding.left;

// 2 CREATE SCALE 
const scaleY = d3.scaleLinear()
  .range([boundHeight, 0])
  .domain(d3.extent(data, d => d.y))

// 3 SVG

const svgns = 'http://www.w3.org/2000/svg'
const svg = d3.select('svg')

svg
  .attr('xmlns', svgns)
  .attr('viewBox', `0 0 ${width} ${height}`)

//create bound element
bound = svg.append('g')
  .attr('class', 'bound')
  .style('transform', `translate(${padding.left}px,${padding.top}px)`)


bound.append('g').attr('class', 'yAxis1')
  .append('g').attr('class', 'yAxisLeft')
  .call(d3.axisLeft(scaleY).tickSizeInner([(-(boundWidth))])
    .tickFormat(d3.format(",.0%")))

console.log(d3.mean(data.map(d => d.y)))
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<svg></svg>
<div id="container" class="svg-container"></div>
<script src="next.js"></script>

The mean of data.y=0.5724999999999999. How can I pass on this value to the axis generator to create a label and tick for this, apart from the auto-generated y-axis tick and labels.

>Solution :

Get the scale’s auto-generated ticks array (scaleY.ticks()), add the mean value to that array and pass it to axis.tickValues:

.tickValues(scaleY.ticks().concat(mean))

Here is your code with that change:

////////////////////////////////////////////////////////////
//////////////////////// 1 DATA ///////////////////////////
////////////////////////////////////////////////////////////

const data = [{
    "x": 50,
    "y": 0.10
  },
  {
    "x": 100,
    "y": 0.15
  },
  {
    "x": 150,
    "y": 0.25
  },
  {
    "x": 200,
    "y": 0.35
  },
  {
    "x": 250,
    "y": 0.45
  },
  {
    "x": 300,
    "y": 0.55
  },
  {
    "x": 350,
    "y": 0.65
  },
  {
    "x": 400,
    "y": 0.75
  },
  {
    "x": 450,
    "y": 0.85
  },
  {
    "x": 500,
    "y": 0.87
  },
  {
    "x": 550,
    "y": 0.92
  },
  {
    "x": 600,
    "y": 0.98
  }


]
height = 400,
  width = 720;

padding = {
  top: 70,
  bottom: 50,
  left: 70,
  right: 70
}


const boundHeight = height - padding.top - padding.bottom;
const boundWidth = width - padding.right - padding.left;

////////////////////////////////////////////////////////////
//////////////////////// 2 CREATE SCALE ////////////////////
////////////////////////////////////////////////////////////

const scaleY = d3.scaleLinear()
  .range([boundHeight, 0])
  .domain(d3.extent(data, d => d.y))

////////////////////////////////////////////////////////////
//////////////////////// 3 SVG// ///////////////////////////
////////////////////////////////////////////////////////////

const svgns = 'http://www.w3.org/2000/svg'
const svg = d3.select('svg')

svg
  .attr('xmlns', svgns)
  .attr('viewBox', `0 0 ${width} ${height}`)

//create bound element
bound = svg.append('g')
  .attr('class', 'bound')
  .style('transform', `translate(${padding.left}px,${padding.top}px)`)

const mean = d3.mean(data.map(d => d.y));

bound.append('g').attr('class', 'yAxis1')
  .append('g').attr('class', 'yAxisLeft')
  .call(d3.axisLeft(scaleY)
    .tickValues(scaleY.ticks().concat(mean))
    .tickSizeInner([(-(boundWidth))])
    .tickFormat(d3.format(",.0%")))
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>
  <svg>
</svg>
  <div id="container" class="svg-container"></div>
  <script src="next.js"></script>
</body>

</html>

Leave a Reply