javascript - D3.JS Y轴标签问题

标签 javascript html css d3.js svg

首先,我是 D3.Js 的新手。在过去一周左右的时间里,我一直在处理一个 D3.JS 问题——特别是制作一个带有 Y 轴标签的图表。但是,我不能完全按照我想要的方式得到图表。它几乎就在那里,但倒置了,或者我的数据出错了。现在我将在展示所有代码之前简要展示我的一些代码和主要问题的图像。我花了一些时间查看其他有类似问题的 Stack Overflow 帖子,我做了那些帖子上的操作,但仍然有同样的问题。

例如,我认为这篇文章会有解决方案:reversed Y-axis D3

数据如下:

[0,20,3,8](它实际上是一个对象数组,但我认为这可能是所需要的全部。

所以,首先,当 yScale 是这样的时候:

  var yScale = d3.scaleLinear() 
             .domain([0, maxPound]) //Value of maxpound is 20
             .range([0, 350]);

条形图如下所示: Figure  1

正如人们所见,Y 图表从顶部的 0 和底部的 20 开始 - 起初我认为这是将域中的值翻转为此的简单解决方案:

     var yScale = d3.scaleLinear() 
             .domain([0, maxPound]) //Value of maxpound is 20
             .range([0, 350]);

我得到这张图片:

enter image description here

在第二张图片中,y 轴在右边 - 20 在上面 - 耶!但是图表是错误的。 0 现在返回 350 像素的值——SVG 元素的高度。这就是 20 应该返回的值!如果我尝试切换图像范围值,我会遇到同样的问题!

现在是代码:

  var w = 350;
  var h = 350;
  var barPadding = 1;
  var margin = {top: 5, right: 200, bottom: 70, left: 25}

  var maxPound = d3.max(poundDataArray, 
     function(d) {return parseInt(d.Pounds)}
  );

  //Y-Axis Code
  var yScale = d3.scaleLinear()
                 .domain([maxPound, 0])
                 .range([0, h]);

  var yAxis = d3.axisLeft()
                .scale(yScale)
                .ticks(5);


  //Creating SVG element 
  var svg = d3.select(".pounds")
              .append('svg')
              .attr("width", w)
              .attr('height', h)
              .append("g")
                 .attr("transform", "translate(" + margin.left + "," + 
     margin.top + ")");

    svg.selectAll("rect")
       .data(poundDataArray)
       .enter()
       .append("rect")
       .attr('x',  function(d, i){
            return i * (w / poundDataArray.length);
         })
       .attr('y', function(d) {
            return 350 - yScale(d.Pounds);
        })
       .attr('width', (w / 4) - 25)
       .attr('height', function(d){
           return yScale(d.Pounds);
        })
       .attr('fill', 'steelblue');



   //Create Y axis
   svg.append("g")
      .attr("class", "axis")
      .call(yAxis);

感谢您的帮助!我相信错误可能出在 y 或高度值中,并且花了一些时间在那里乱搞,但没有结果。

最佳答案

这不是 D3 问题,而是 SVG 特性:在 SVG 中,原点 (0,0) 位于左上角,而不是左下角,就像在常见的笛卡尔坐标中一样飞机。这就是为什么使用 [0, h] 作为范围使轴看起来倒转的原因……实际上,它没有倒转:这是 SVG 中的正确方向。顺便说一句,HTML5 Canvas 具有相同的坐标系,使用 Canvas 时您会遇到同样的问题。

因此,您必须翻转范围,而不是域:

var yScale = d3.scaleLinear()
    .domain([0, maxPound])
    .range([h, 0]);//the range goes from the bottom to the top now

或者,在您的情况下,使用边距:

var yScale = d3.scaleLinear()
    .domain([0, maxPound])
    .range([h - margin.bottom, margin.top]);

除此之外,y 位置和高度的数学运算是错误的。应该是:

.attr('y', function(d) {
    return yScale(d.Pounds);
})
.attr('height', function(d) {
    return h - margin.bottom - yScale(d.Pounds);
})

此外,作为奖励提示,不要对 x 位置和宽度进行硬编码。请改用带秤。

这是您的代码,其中包含这些更改:

var poundDataArray = [{
  Pounds: 10
}, {
  Pounds: 20
}, {
  Pounds: 5
}, {
  Pounds: 8
}, {
  Pounds: 14
}, {
  Pounds: 1
}, {
  Pounds: 12
}];

var w = 350;
var h = 350;
var barPadding = 1;
var margin = {
  top: 5,
  right: 20,
  bottom: 70,
  left: 25
}

var maxPound = d3.max(poundDataArray,
  function(d) {
    return parseInt(d.Pounds)
  }
);

//Y-Axis Code
var yScale = d3.scaleLinear()
  .domain([0, maxPound])
  .range([h - margin.bottom, margin.top]);

var xScale = d3.scaleBand()
  .domain(d3.range(poundDataArray.length))
  .range([margin.left, w - margin.right])
  .padding(.2);

var yAxis = d3.axisLeft()
  .scale(yScale)
  .ticks(5);

//Creating SVG element 
var svg = d3.select("body")
  .append('svg')
  .attr("width", w)
  .attr('height', h)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," +
    margin.top + ")");

svg.selectAll("rect")
  .data(poundDataArray)
  .enter()
  .append("rect")
  .attr('x', function(d, i) {
    return xScale(i);
  })
  .attr('y', function(d) {
    return yScale(d.Pounds);
  })
  .attr('width', xScale.bandwidth())
  .attr('height', function(d) {
    return h - margin.bottom - yScale(d.Pounds);
  })
  .attr('fill', 'steelblue');

//Create Y axis
svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(" + margin.left + ",0)")
  .call(yAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>

关于javascript - D3.JS Y轴标签问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47274701/

相关文章:

javascript - 从 nodejs 到 mongodb 或 mongoose 的动态数据库连接

javascript - 如何通过多个名称选择来检查所选元素的值

html - 从网站缩放功能中抓取大图像

html - CSS - 将列表项堆叠在彼此下方

html - CSS固定div,左右浮动定位

javascript - 绘制数据过多的 amCharts 图形的有效方法

javascript - 根据客户组显示文本

html - 如何固定段落的位置

php - 在php-mysql中保存并迭代数组

html - 拉伸(stretch)右浮动 div 宽度?