grindarius
grindarius

Reputation: 119

How to make grid lines when axes are aligned at the middle?

I am working on creating a 4 quadrant line chart with gridlines. However, the grid does not seem to work properly. It does not go on both sides when I translate the axes. I have provided a fiddle here too.

const f = (x) => {
  return Math.sin(x)
}

const data = d3.ticks(-5, 5, 100).map((x) => {
  const container = {
    x: x,
    y: f(x)
  }
  return container
})

const margins = { top: 20, right: 20, bottom: 30, left: 30 }
const width = 750 - margins.left - margins.right
const height = 750 - margins.top - margins.bottom

const svg = d3.select('#graph')
  .append('svg')
  .attr('width', width + margins.left + margins.right)
  .attr('height', height + margins.top + margins.bottom)
  .append('g')
  .attr('transform', `translate(${margins.left}, ${margins.top})`)

const x = d3.scaleLinear([-5, 5], [0, width])
const y = d3.scaleLinear([-5, 5], [height, 0])

const xAxis = svg.append('g')
  .attr('transform', `translate(0, ${y(0)})`)
  .attr('class', 'x-axis')

const yAxis = svg.append('g')
  .attr('transform', `translate(${x(0)}, 0)`)
  .attr('class', 'y-axis')

xAxis.call(d3.axisBottom(x))
yAxis.call(d3.axisLeft(y))

d3.selectAll('g.x-axis g.tick')
  .append('line')
  .attr('class', 'gridline')
  .attr('x1', 0)
  .attr('y1', -height)
  .attr('x2', 0)
  .attr('y2', 0)

d3.selectAll('g.y-axis g.tick')
  .append('line')
  .attr('class', 'gridline')
  .attr('x1', 0)
  .attr('y1', 0)
  .attr('x2', width)
  .attr('y2', 0)

svg.append('path')
  .datum(data)
  .attr('fill', 'none')
  .attr('stroke', 'steelblue')
  .attr('stroke-width', 1.5)
  .attr('d', d3.line(d => x(d.x), d => y(d.y)))
#graph {
  text-align: center;
}

.gridline{
  stroke: black;
  shape-rendering: crispEdges;
  stroke-opacity: 0.5;
}
<div id="graph"></div>
<script src="https://d3js.org/d3.v6.min.js"></script>

I use this method for creating the gridline.

I want the grid to expand to the side that I translate from. Thank you.

Upvotes: 3

Views: 361

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

I'm the author of the answer you linked. The problem with that approach, which I don't make clear in the answer, is that all the lines are created at the same position of the axis. Therefore, you have to translate them.

For the x axis:

.attr("transform", `translate(0, ${y.range()[0] - y(0)})`)

And for the y axis:

.attr("transform", `translate(${x.range()[0] - x(0)})`, 0)

Here is your code with those changes:

const f = (x) => {
  return Math.sin(x)
}

const data = d3.ticks(-5, 5, 100).map((x) => {
  const container = {
    x: x,
    y: f(x)
  }
  return container
})

const margins = {
  top: 20,
  right: 20,
  bottom: 30,
  left: 30
}
const width = 750 - margins.left - margins.right
const height = 750 - margins.top - margins.bottom

const svg = d3.select('#graph')
  .append('svg')
  .attr('width', width + margins.left + margins.right)
  .attr('height', height + margins.top + margins.bottom)
  .append('g')
  .attr('transform', `translate(${margins.left}, ${margins.top})`)

const x = d3.scaleLinear([-5, 5], [0, width])
const y = d3.scaleLinear([-5, 5], [height, 0])

const xAxis = svg.append('g')
  .attr('transform', `translate(0, ${y(0)})`)
  .attr('class', 'x-axis')

const yAxis = svg.append('g')
  .attr('transform', `translate(${x(0)}, 0)`)
  .attr('class', 'y-axis')

xAxis.call(d3.axisBottom(x))
yAxis.call(d3.axisLeft(y))

d3.selectAll('g.x-axis g.tick')
  .append('line')
  .attr('class', 'gridline')
  .attr('x1', 0)
  .attr('y1', -height)
  .attr('x2', 0)
  .attr('y2', 0)
  .attr("transform", `translate(0, ${y.range()[0] - y(0)})`)

d3.selectAll('g.y-axis g.tick')
  .append('line')
  .attr('class', 'gridline')
  .attr('x1', 0)
  .attr('y1', 0)
  .attr('x2', width)
  .attr('y2', 0)
  .attr("transform", `translate(${x.range()[0] - x(0)})`, 0)

svg.append('path')
  .datum(data)
  .attr('fill', 'none')
  .attr('stroke', 'steelblue')
  .attr('stroke-width', 1.5)
  .attr('d', d3.line(d => x(d.x), d => y(d.y)))
#graph {
  text-align: center;
}

.gridline {
  stroke: black;
  shape-rendering: crispEdges;
  stroke-opacity: 0.5;
}
<div id="graph"></div>
<script src="https://d3js.org/d3.v6.min.js"></script>

Upvotes: 3

Related Questions