'How to change Y axis of a barchart using D3.js after filtering data?
I was able to plot a barchart with D3.js that each second filters the data by status and shows the bars anew. The x axis bars (=user.id) are the same, as you can see in the data bellow ("OneA", "TwoB", etc). What changes are the points to each user accordinly to the different status.
The bars changes their sizes, but I'm unable to change the Y axis and can't figure out why. Below the most important part of the file where I think the changes should work:
//FILTER data
const filteredData = data.filter((d) => d.status)
//JOIN new data with old elements.
const rects = g.selectAll("rect")
.data(filteredData)
//EXIT old elements not present in new data.
rects.exit().remove()
//UPDATE old elements present in new data.
// IT SHOULD CHANGE THE VALUES OF Y AXIS, shouldn't it?
rects
.attr("x", (d) => x(d.user_id))
.attr("y", d => y(d.points))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.points))
//ENTER new elements present in new data.
// IT TOO SHOULD CHANGE THE VALUES OF Y AXIS, shouldn't it?
rects.enter().append("rect")
.attr("x", (d) => x(d.user_id))
.attr("y", d => y(d.points))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.points))
.attr("fill", "steelblue")
Here the entire file:
let flag = true
//set margins, width and right
const MARGIN = { LEFT: 100, RIGHT: 10, TOP: 10, BOTTOM: 100 }
const WIDTH = 600 - MARGIN.LEFT - MARGIN.RIGHT
const HEIGHT = 400 - MARGIN.TOP - MARGIN.BOTTOM
//set svg
const svg = d3.select("#chart-area").append("svg")
.attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
.attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)
//set group
const g = svg.append("g")
.attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)
// X label
g.append("text")
.attr("class", "x axis-label")
.attr("x", WIDTH / 2)
.attr("y", HEIGHT + 60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("Users")
// Y label
g.append("text")
.attr("class", "y axis-label")
.attr("x", - (HEIGHT / 2))
.attr("y", -60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.text("Points")
//set x axis scale
const x = d3.scaleBand()
.range([0, WIDTH]) //output from zero to max width
.padding(0.1) //distance between bars
//set y axis scale
const y = d3.scaleLinear()
.range([HEIGHT, 0]) //output from max height to zero
//set x axis / x label group
const xAxisGroup = g.append("g") //append g group specifically to plot the x label
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`)
//set y axis / x label group
const yAxisGroup = g.append("g") //append g group specifically to plot the y label
.attr("class", "y axis")
//import data
d3.json("data/data.json").then(data => {
//parse data
data.forEach(d => {
d.points = Number(d.points)
})
//update funtion is called every one second
d3.interval(() => {
flag = !flag
update(data)
}, 1000)
//immediately plot all elements when page firts load
update(data)
})
//update function
function update(data) {
const value = flag ? "AB" : "YZ"
x.domain(data.map(d => d.user_id)) //set x axis domain
y.domain([0, d3.max(data, d => d.points)]) //input y axis domain from zero to points max value
const xAxisCall = d3.axisBottom(x)
xAxisGroup.call(xAxisCall)
.selectAll("text")
.attr("y", "10")
.attr("x", "-5")
.attr("text-anchor", "end")
.attr("transform", "rotate(-45)")
const yAxisCall = d3.axisLeft(y)
.ticks(5)
.tickFormat(d => d + "m")
yAxisGroup.call(yAxisCall)
//FILTER data
const filteredData = data.filter((d) => d.status)
//JOIN new data with old elements.
const rects = g.selectAll("rect")
.data(filteredData)
//EXIT old elements not present in new data.
rects.exit().remove()
//UPDATE old elements present in new data.
rects
.attr("x", (d) => x(d.user_id))
.attr("y", d => y(d.points))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.points))
//ENTER new elements present in new data.
rects.enter().append("rect")
.attr("x", (d) => x(d.user_id))
.attr("y", d => y(d.points))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.points))
.attr("fill", "steelblue")
}
And here the json file with the data:
[
{
"user_id": "OneA",
"points": "49279",
"status": "YZ"
},
{
"user_id": "TwoB",
"points": "31342",
"status": "YZ"
},
{
"user_id": "ThreeC",
"points": "13344",
"status": "YZ"
},
{
"user_id": "FourD",
"points": "5096",
"status": "YZ"
},
{
"user_id": "FiveE",
"points": "2679",
"status": "YZ"
},
{
"user_id": "SixF",
"points": "1348",
"status": "YZ"
},
{
"user_id": "SevenG",
"points": "1288",
"status": "YZ"
},
{
"user_id": "OneA",
"points": "492799",
"status": "AB"
},
{
"user_id": "TwoB",
"points": "313420",
"status": "AB"
},
{
"user_id": "ThreeC",
"points": "133443",
"status": "AB"
},
{
"user_id": "FourD",
"points": "50963",
"status": "AB"
},
{
"user_id": "FiveE",
"points": "26797",
"status": "AB"
},
{
"user_id": "SixF",
"points": "13483",
"status": "AB"
},
{
"user_id": "SevenG",
"points": "12889",
"status": "AB"
}
]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
