【问题标题】:how to show ordinal axis in d3如何在d3中显示序数轴
【发布时间】:2018-03-18 15:09:00
【问题描述】:

我是 d3 新手,在显示序数轴标签时遇到问题:

<!DOCTYPE html>
<html lang="en">
	<head>
      <script src="https://d3js.org/d3.v4.min.js"></script>
		<meta charset="utf-8">
		<title>D3: Loading data from a CSV file</title>
  </head>
	<body>
		<script type="text/javascript">

      var margin = {top: 20, right: 20, bottom: 30, left: 40},
    		w = 600 - margin.left - margin.right,
    		h = 300 - margin.top - margin.bottom;
      var padding = 40;
      
      var data = [
        { "Food": "Apples", "Deliciousness": 9 },
        { "Food": "Green Beans", "Deliciousness": 5 },
        { "Food": "Egg Salad Sandwich", "Deliciousness": 4 },
        { "Food": "Cookies", "Deliciousness": 10 },
        { "Food": "Liver", "Deliciousness": 2 },
        { "Food": "Burrito", "Deliciousness": 7 },
      ];

      data.forEach(function(d) {
        d.Deliciousness = +d.Deliciousness;
      });

      var svg = d3.select("body")
						.append("svg")
						.attr("width", w + margin.left + margin.right)
						.attr("height", h + margin.top + margin.bottom)
      			.append("g")
      			.attr("transform", "translate(" + margin.left+"," +
                 margin.top+")");
        
      var xScale = d3.scaleBand()
      	.domain(d=>d.Food)
      	.range([0,w])
      	.paddingInner(0.2);
     xScale.domain(data.map(function(d) { return d.Food; }));
        
      var xAxis = d3.axisBottom()
      	.scale(xScale)
      	.ticks(5);
      
      var yScale = d3.scaleLinear()
      	.domain([0, d3.max(data, d=>d.Deliciousness)])
      	.rangeRound([h,0]);
        
      var yAxis = d3.axisLeft()
      	.scale(yScale)
      	.ticks(5);
      
      svg.selectAll('rect')
        .data(data)
        .enter()
        .append('rect')
        .attr('x',(d,i) => margin.left + i*w/data.length)
        .attr('y',d=>yScale(d.Deliciousness))
        .attr('width', xScale.bandwidth())
        .attr('height',d =>h-yScale(d.Deliciousness))
        .attr('fill',function(d){
          if (d===30) return "red";
          return "rgb(0,0,"+d.Deliciousness*10+")" ;});
       
      svg.selectAll("text")
      	.data(data)
      	.enter()
      	.append("text")
      	.text(d=>d.Deliciousness)
      	.attr("x", (d,i)=>(padding + i*w/data.length))
        .attr("y", d=>yScale(d.Deliciousness)+15)
      	.attr("fill","white");
      
      svg.append("g")
      	.attr("class", "axis")
	   		.attr("transform", "translate(" + padding + ",0)")
      	.call(yAxis);
        
			svg.append("g")
      	.attr("class", "axis")
	   		.attr("transform", "translate(0," + (h-margin.bottom) + ")")
      	.call(xAxis);
        
		</script>
	</body>
</html>

x轴不知何故与图表重叠,如何正确使用margin?

就序轴而言,除了在 .domain() 中手动列出所有类别之外,在 .domain().range() 调用中特殊 xScale 的其他方法是什么?谢谢

【问题讨论】:

    标签: d3.js scale axis


    【解决方案1】:

    来自x轴的位置定义。

    你可以改变:

    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + (h-margin.bottom) + ")")
      .call(xAxis);
    

    与:

    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(" + margin.left + "," + h + ")")
      .call(xAxis);
    

    这里是演示:

    <!DOCTYPE html>
    <html lang="en">
    	<head>
          <script src="https://d3js.org/d3.v4.min.js"></script>
    		<meta charset="utf-8">
    		<title>D3: Loading data from a CSV file</title>
      </head>
    	<body>
    		<script type="text/javascript">
    
          var margin = {top: 20, right: 20, bottom: 30, left: 40},
        		w = 600 - margin.left - margin.right,
        		h = 300 - margin.top - margin.bottom;
          var padding = 40;
          
          var data = [
            { "Food": "Apples", "Deliciousness": 9 },
            { "Food": "Green Beans", "Deliciousness": 5 },
            { "Food": "Egg Salad Sandwich", "Deliciousness": 4 },
            { "Food": "Cookies", "Deliciousness": 10 },
            { "Food": "Liver", "Deliciousness": 2 },
            { "Food": "Burrito", "Deliciousness": 7 },
          ];
    
          data.forEach(function(d) {
            d.Deliciousness = +d.Deliciousness;
          });
    
          var svg = d3.select("body")
    						.append("svg")
    						.attr("width", w + margin.left + margin.right + padding)
    						.attr("height", h + margin.top + margin.bottom)
          			.append("g")
          			.attr("transform", "translate(" + margin.left+"," +
                     margin.top+")");
            
          var xScale = d3.scaleBand()
          	.domain(d=>d.Food)
          	.range([0,w])
          	.paddingInner(0.2);
         xScale.domain(data.map(function(d) { return d.Food; }));
            
          var xAxis = d3.axisBottom()
          	.scale(xScale)
          	.ticks(5);
          
          var yScale = d3.scaleLinear()
          	.domain([0, d3.max(data, d=>d.Deliciousness)])
          	.rangeRound([h,0]);
            
          var yAxis = d3.axisLeft()
          	.scale(yScale)
          	.ticks(5);
          
          svg.selectAll('rect')
            .data(data)
            .enter()
            .append('rect')
            .attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length))
            .attr('y',d=>yScale(d.Deliciousness))
            .attr('width', xScale.bandwidth())
            .attr('height',d =>h-yScale(d.Deliciousness))
            .attr('fill',function(d){
              if (d===30) return "red";
              return "rgb(0,0,"+d.Deliciousness*10+")" ;});
           
          svg.selectAll("text")
          	.data(data)
          	.enter()
          	.append("text")
          	.text(d=>d.Deliciousness)
          	.attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length))
            .attr("y", d=>yScale(d.Deliciousness)+15)
          	.attr("fill","white");
          
          svg.append("g")
          	.attr("class", "axis")
    	   		.attr("transform", "translate(" + padding + ",0)")
          	.call(yAxis);
            
    			svg.append("g")
          	.attr("class", "axis")
    	   		.attr("transform", "translate(" + margin.left + "," + h + ")")
          	.call(xAxis);
            
    		</script>
    	</body>
    </html>

    x-axis 与其容器(此处为svg)相比的位置由transform 属性定义。在这种情况下是翻译。为了定义一个翻译,我们给 transform 属性这个值:translate(dx,dy)

    dx:由于rects 的x 偏移量为margin.left (.attr('x',(d,i) =&gt; margin.left + i*w/data.length)),我们还需要将x 轴水平平移margin.left

    dy:由于rects 的基数从h (.rangeRound([h, 0]);) 开始,我们还需要将x 轴垂直平移h


    我还使用以下方法修改了条形和标签的 x 位置:

    .attr('x',(d,i) => margin.left + i * ((w + margin.right ) / data.length))
    

    代替:

    .attr('x',(d,i) => margin.left + i*w/data.length)
    

    最后,由于最后一根柱子在图表​​之外的一半,您可以通过替换来增加 svg 容器的宽度:

    .attr("width", w + margin.left + margin.right)
    

    与:

    .attr("width", w + margin.left + margin.right + padding)
    

    关于您的最后一个问题,https://github.com/d3/d3-axis 可能会为您提供有关如何使用 d3 轴的更多详细信息。

    【讨论】:

    • 非常感谢您的回复,泽维尔。我现在可以显示轴标签了,但图表还是有点奇怪:blockbuilder.org/anonymous/a86e5ffe4faf764b08ca0cb7b9246907 一方面,标签不在条的中间,而且条也不是从 0 开始的。
    • 您在两者之间修改了.attr("transform", "translate(" + margin.left + ",0)")。你问的时候是.attr("transform", "translate(" + padding + ",0)")
    • 我摆脱了填充,因为我使用的是 paddingInner(0.2)。
    • 您可以尝试使用初始代码和两行更改并检查它对您有好处吗?
    • 刚刚更新了答案。您可以增加svg 容器的宽度以正确显示一半显示的右栏。
    猜你喜欢
    • 2020-08-21
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多