【问题标题】:D3.JS Y-axis label issueD3.JS Y轴标签问题
【发布时间】:2017-11-14 07:19:27
【问题描述】:

首先,我对 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]);

条形图如下所示:

正如我们所看到的,Y 图表从顶部的 0 和底部的 20 开始——起初我认为这是一个简单的解决方法,可以将域中的值翻转为:

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

我得到这张图片:

在第二张图片中,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 或 height 值中,并且花了很多时间在那里乱七八糟地没有结果。

【问题讨论】:

  • 您需要从比例尺的高度中减去边距吗?
  • 我已经尝试过了,但我不相信是这样——第一张图片中的图表实际上正是他们想象的样子,y 轴只是颠倒了。但是确实尝试过这样做: .domain([maxPound - margin.top, 0]) 或 .range([0, h - margin.top]);如果这就是你的意思

标签: javascript html css d3.js svg


【解决方案1】:

这不是 D3 问题,而是 SVG 特性:在 SVG 中,原点 (0,0) 在 左上角 角,而不是在普通笛卡尔坐标系中的左下角飞机。这就是为什么使用[0, h] 作为范围使轴看起来是倒置...实际上,它没有倒置:这是 SVG 中的正确方向。顺便说一句,HTML5 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>

【讨论】:

    猜你喜欢
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 2022-01-03
    • 2016-02-01
    • 2012-08-16
    • 1970-01-01
    相关资源
    最近更新 更多