Reputation: 119
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
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