【问题标题】:Line Chart d3 js-- x axis months折线图d3 js--x轴月
【发布时间】:2013-12-27 16:10:41
【问题描述】:

我正在尝试制作一个简单的折线图,其中 x 轴为 1 月 - 12 月,y 为我公司网站上发布的作业数量。我在映射 y 域时遇到了一些麻烦......并且基本上理解了这个 api 应该如何工作。我找到了很多解析日期或数值 x 轴的示例,但我似乎无法在几个月内正确理解。

我已经用这段代码调整了很长时间,我什至不确定我在看什么。

对于一个年轻的菜鸟,我们非常感谢任何帮助。

这里是要点:https://gist.github.com/wiredsister/8148974

我的样式如下:

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.axis text {
  font: 10px sans-serif;
}

.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}

【问题讨论】:

  • CSS 代码并没有增加太多的问题。如果您复制 (a) 定义轴的代码部分和 (b) 示例数据文件,这将更有用。
  • @AmeliaBR,你是对的,它没有。这就是为什么我链接到我的要点,其中包含所有相关材料。很抱歉造成混乱。

标签: javascript css svg d3.js linechart


【解决方案1】:

日期/时间轴函数不适合您的原因是您的月份数据实际上并未存储为日期/时间值:它只是一个简单的整数。有两种方法可以使用它。

第一个选项,如果您只想一次绘制一年(因此 2013 年 1 月与 2014 年 1 月没有重复)并且不需要进行任何基于时间的数学运算,您可以使用 ordinal scale将月份数字映射到月份名称,根本不用担心时间尺度。

第二个选项,如果你想将月份数据存储为日期,你需要将parse你的输入数据放入一个日期对象中。之后,您的其余代码应该可以按预期工作。

目前,您的数据读取方法的第一个语句是一个数据转换例程,但它只是将所有内容存储为数字:

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

+d.month 告诉程序获取它读入的数字字符串(“0”或“7”或“11”)并将其替换为相应的数字。相反,您希望它读取该数字字符串并将其解释为月份。

为此,您需要创建一个时间格式化对象,该对象期望看到一个数字并将其读取为一个月,然后对读入的值使用该格式化对象的parse() 方法。这有点复杂因为您的月份数字在 0-11 范围内给出,而日期的预期数字格式在 1-12 范围内。 (如果您可以更改数据格式而不会使代码的其他部分复杂化,那会更简单)。

var monthNumber = d3.time.format("%-m"); 
   //m is month number, '-' indicates no padding

data.forEach(function(d) {
    d.month = monthNumber("" + (+d.month + 1) );
      //convert the month to an integer and add one, 
      //then convert back to a string and parse
    d.work = +d.work;
  });

在此处查看此方法的实际应用:http://fiddle.jshell.net/eGTnB/

请注意,由于您的数据没有任何关于指定年份的信息,因此浏览器将插入一个“零”年份,例如 1900。如果您想硬编码一个有效年份,您可以像这样改变格式:

var year = 2013;
var yearPlusMonthNumber = d3.time.format("%Y %-m"); 
    //Y is four digit year, m is month number, '-' indicates no padding

data.forEach(function(d) {
    d.month = yearPlusMonthNumber("" + year + " " + (+d.month + 1) );
      //convert the month to an integer, add one,  
      //then combine with year (and space) as a string and parse
    d.work = +d.work;
  });

【讨论】:

  • P.S.这是更新为包含年份变量的小提琴:fiddle.jshell.net/eGTnB/2
  • 感谢您的精彩回答。现在我只需要了解序数尺度在域中的作用。
  • 这可能是更简单的方法。对于初学者,只需在程序顶部创建一个月份名称数组,然后您就可以使用monthNames[d.month] 获得正确的标签。当然,您仍然需要一个序数刻度(使用.rangeRoundBands.rangePoints())来在图表中分隔数据;有很多条形图示例展示了这些方法的实际应用。
【解决方案2】:

我想展示我最终是如何实现这个图表的: 根据 AmeliaBR 的建议和 Mike Bostock 的月轴示例,我决定制作我的折线图,其中 x 和 y 是线性刻度,以及一个名为 xLabels 的变量,作为 xAxis 的格式化时间刻度。像这样,

var xLabels = d3.time.scale().domain([new Date(2013, 0, 1), new Date(2013, 11, 31)]).range([0, w]);
    var x = d3.scale.linear().domain([0, data.length]).range([0, w]);
    var y = d3.scale.linear().domain([0, d3.max(data)]).range([h, 0]);

我像绘制正常的线性比例一样绘制我的线,但对于 xAxis:

var xAxis = d3.svg.axis().scale(xLabels).ticks(d3.time.months).tickFormat(d3.time.format("%B")).tickSize(-h).tickSubdivide(true);
    graph.append("svg:g")
          .attr("class", "x axis") 
          .attr("transform", "translate(0," + h + ")")
          .call(xAxis);

我传递了我的 xLabels 作为刻度,并将我的刻度格式化为月。

这是 jsfidde 上的工作示例: http://jsfiddle.net/vB5eW/

【讨论】:

  • 明智的做法。您可以从刻度上的所有 d3 日期/时间格式化功能中受益,而无需将数据中的简单月份数字转换为日期本身。我唯一建议的是将 x 刻度中的 data.length 更改为硬编码的 12,这样如果您的某个月份丢失,与标签刻度的对齐就不会混乱。但是,如果您使用可以提前检查错误的静态数据,则不太可能导致问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-12
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2017-06-16
相关资源
最近更新 更多