为什么条形图的前两个文本标签没有显示? [英] Why are the first two text labels of my bar chart not shown?

查看:87
本文介绍了为什么条形图的前两个文本标签没有显示?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实施了一个条形图,该条形图基本上可以正常工作.但是,在将标签放在条形图上时,我注意到前两个条形图的标签未显示在其各自的矩形上方.为了附加<text>元素,我绑定了与<rect>元素相同的数据集.

I have implemented a bar chart which is basically working fine. However, when putting labels on the bars I noticed that the labels for the first two bars are not shown above their respective rectangles. To append the <text> elements I bind the same dataset as for the <rect> elements.

g.selectAll("text")       
      .data(dataset)  // same dataset for the texts as for the bars     
      .enter()       
      .append("text")  
        // ...more styling...

但是,尽管显示了所有条形,但前两个矩形的标签丢失了.看一下下面的演示,它显示了问题:

However, while all bars are shown the labels for the first two rectangles are missing. Have a look at the following demo, which shows the problem:

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("text")       
      .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("rect")       
		.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)");

  

<script src="https://d3js.org/d3.v5.js"></script>

<div class="div1" ></div>

推荐答案

以下将标签附加到条上的部分不起作用,如您所期望的那样:

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")  

实际上,您先前已经将<text>元素附加到g元素,即轴的标签.上面的选择将选择这些文本作为前两个元素.绑定数据时,这些元素已经存在,因此不属于enter选择的一部分.实际上,如果您使用浏览器的开发者工具进行检查,例如在 Month 标签上,您会在该元素上找到一个__data__属性,该属性指示数据已绑定到现有文本元素,而这显然不是您想要的.

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:

  1. 将轴的标签附加到另一个组.这将为轴,条和标签创建不同的DOM子树,就分隔而言,这可能是一件好事.在一个子树中选择文本将找到包含在另一子树中的文本.

  1. 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.

在创建数据联接的选择时使用更具体的选择器字符串.另外,由于栏上还没有标签,请使用g.selectAll(null).看看 选择空:D3.js中'selectAll(null)'背后的原因是什么? 解释为什么这是首选方式.

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.

每种方法都能独立解决您的问题.但是,您可能要考虑使用结合了这两种方法的组合解决方案,因为这将为您的SVG创建更清晰的代码,这将使您的生活更轻松.

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.

侧面说明:这对于表示条形图的<rect>元素非常有效,因为在进行选择之前不存在任何矩形.仍然,选择您确定不存在的元素的首选且最惯用的方法是使用d3.selectAll(null).

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).

以下演示显示了如何实现2.使其工作:

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)");

 

<script src="https://d3js.org/d3.v5.js"></script>

<div class="div1" ></div>

这篇关于为什么条形图的前两个文本标签没有显示?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆