Why Are The First Two Text Labels Of My Bar Chart Not Shown?
Solution 1:
The following section appending the labels to the bars is not working as you might have expected:
g.selectAll("text")
.data(dataset)
.enter()
.append("text")
In fact, you have previously appended <text>
elements to the g
element, namely, the labels for your axes. Above selection will select those texts as the first two elements. When binding your data those elements are already existing and are thus not part of the enter selection. In fact, if you use your browser's developer tools to inspect e.g. the Month label you will find a __data__
property on that element indicating that the data was bound to the existing text element which is clearly not what you want.
There are basically two ways around that:
Append the labels of the axes to another group. This creates distinct DOM subtrees for the axes and the bars and labels which might be a good thing in terms of separation. Selecting texts in one subtree will find texts contained in another subtree.
Use a more specific selector string when creating the selection for the data join. Alternatively, use
g.selectAll(null)
as there are no labels on the bars, yet. Have a look at Selecting null: what is the reason behind 'selectAll(null)' in D3.js? for an explanation why this is the preferred way.
Each approach is capable of solving your problem on its own. Nonetheless, you might want to consider using a combined solution incorporating both approaches as this will make your life easier since it creates much cleaner Code for your SVG.
Side note: This works well for the <rect>
elements representing the bars as there do not exist any rectangles before doing that selection. Still, the preferrable and most idiomatic way to select elements you are sure are not existing will be to use d3.selectAll(null)
.
The following demo shows how to implement 2. to make it work:
const dataset=[
{
"Month": "2013_09",
"Count": 1
},
{
"Month": "2013_10",
"Count": 291
},
{
"Month": "2013_11",
"Count": 763
},
{
"Month": "2013_12",
"Count": 853
}
];
dataset.forEach(d=>d.Count=+d.Count);
let margin={top:10,right:10,bottom:90,left:40};
let width= 600-margin.left-margin.right;
let height= 400-margin.top-margin.bottom;
const svg = d3.select(".div1")
.append("svg")
.attr("width", width+margin.left+margin.right)
.attr("height", height+margin.top+margin.bottom)
.attr("style", "outline: thin solid red;")
let g=svg.append("g")
.attr("transform","translate(" +margin.left+ ", " +margin.top+ ")");
g.append("text")
.attr("class","x label")
.attr("x", width/2)
.attr("y", height+76)
.attr("font-size","20px")
.attr("text-anchor","middle")
.text("Month")
g.append("text")
.attr("class","y label")
.attr("x", -height/2+50)
.attr("y", -40)
.attr("font-size","20px")
.attr("text-anchor","end")
.text("")
.attr("transform","rotate(-90)")
let x = d3.scaleBand()
.domain(dataset.map(d=>d.Month))
.range([0, width])
.paddingInner(0.3)
.paddingOuter(1)
let y = d3.scaleLinear()
.domain([0, d3.max(dataset,d=>d.Count)+80])
.range([height, 0]);
g.selectAll(null)
.data(dataset)
.enter()
.append("text")
.attr("font-size","11px")
.attr("text-anchor","middle")
.text((d) => d.Count)
.attr("y",d=>y(d.Count)-3)
.attr("x",(d)=>x(d.Month)+4);
let leftAxis=d3.axisLeft(y)
.ticks(8)
.tickFormat(d=>d);
g.append("g")
.attr("class","left axis")
.attr("transform","translate(0,0)")
.call(leftAxis)
let rects=g.selectAll(null)
.data(dataset)
.enter()
.append("rect")
.attr("y",d=>y(d.Count))
.attr("x",d=>x(d.Month))
.attr("width",x.bandwidth)
.attr("height",d=>height-y(d.Count))
.attr("fill","blue")
let bottomAxis=d3.axisBottom(x);
g.append("g")
.attr("class", "x axis")
.attr("transform","translate(0,"+height+")")
.call(bottomAxis)
.selectAll("text")
.attr("y","10")
.attr("x","-5")
.attr("text-anchor","end")
.attr("transform","rotate(-40)");
<scriptsrc="https://d3js.org/d3.v5.js"></script><divclass="div1" ></div>
Post a Comment for "Why Are The First Two Text Labels Of My Bar Chart Not Shown?"