【问题标题】:Add custom text below each X-axis date label in d3.js在 d3.js 中的每个 X 轴日期标签下方添加自定义文本
【发布时间】:2020-08-02 19:50:21
【问题描述】:

我在 d3.js 中有一个折线图。

X 轴有日期,定义如下:

g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b/%d/%Y")).ticks(d3.timeYear))
    .selectAll("text")
    .style("text-anchor", "end")
    .attr("dy", ".25em")
    .attr("transform", "rotate(-45)");

我想在每个日期旁边显示更多信息。具体来说,是基于该日期的行值的计算。为简单起见,假设我只想显示该点的线值,乘以 3。因此,如果在 2020 年 4 月 19 日,线的值为 150,则 X 轴应为:

04/19/2020
450

如果我尝试使用轴转换将文本直接插入轴标签,我会收到错误消息,可能是因为它不再是有效的日期/时间格式。所以我认为我必须将文本添加为​​一个单独的元素,但我不明白如何迭代图表上的每个点并计算要显示的正确文本。对于每种情况,计算正确的 Y 位置应该很容易(y 是图形的全高加上一些固定的偏移量),所以问题是迭代并为每个点设置正确的 X 和值。

Fiddle

【问题讨论】:

  • 想要从实际日期的值进行插值以匹配轴刻度是不寻常的,而且我认为这不是一个好的做法 - 因为你正在混合我应该在哪里寻找信息类型 -​​ 通过包括在 x 轴上插值 y 值。另一种选择可能是使用三角测量计算 x 刻度线处的 y 值,并将“伪”数据点引入数据集/第二个数据系列,并绘制它们(可能对它们进行不同的着色以表明它们是计算值)
  • 嗨,乔万。我为您添加了另外两种在每个 x 轴日期下方添加自定义文本的方法。我希望它能回答你的问题。

标签: javascript d3.js


【解决方案1】:

您可以定义创建自定义tickFormat 方法。例如:

function customFormat(e) {
    // do whatever calculation you like with e here
    return d3.timeFormat("%b/%d/%Y")(e) + "-" + e.getDay();
}

然后你可以像这样将它传递给tickFormat

d3.axisBottom(x).tickFormat(customFormat).ticks(d3.timeYear)

这就是它的样子:

如果自定义文本需要低于现有轴,您可以添加另一个 x 轴。您还可以为其使用自定义tickFormat 并使其线条不可见。例如:

function customFormat(e) {
  return e.getDay();
}

let anotheraxis = g.append("g")
  .attr("transform", "translate(0," + (height + 60) + ")")
  .call(d3.axisBottom(x).tickFormat(customFormat).ticks(d3.timeYear));

// Hide the new axis' lines
anotheraxis
  .selectAll("line")
  .style('opacity', 0);

anotheraxis
  .selectAll("path")
  .style('opacity', 0);

这看起来像:

您提到“基于该日期行的值的计算”。当然,如果您的数据是由某种函数生成的,您可以将自定义格式的刻度值传递给该函数。但是,如果您有一组数据点,就像在您的 JSFiddle 示例中一样,您将不得不使用插值来计算曲线在该刻度值处的值。 D3 似乎没有提供一种简单的方法来做到这一点,但 these questions 可能是您的起点。

也可以使用tickValues 方法来设置轴应具有的特定刻度。如果将其设置为数据的 x 值,则无需进行任何插值,因为您已经有了 y 值。

例如,您可以创建一个仅包含数据日期的数组:

let dates = data.map((x) => x.date);

然后构造一个包含日期数据值的对象:

let date_values = data.reduce((o, x) => { o[x.date] = x.value; return o;}, {});

然后您可以创建一个自定义格式,该格式使用date_values 对象来获取日期的值并将其乘以 3:

function customFormat(e) {
   return d3.timeFormat("%b/%d/%Y")(e) + "-" + (3 * date_values[e]);
}

最后,使用自定义格式和dates 数组作为轴:

.call(d3.axisBottom(x).tickFormat(customFormat).tickValues(dates))

我创建了一个演示 here。这是它的样子:

另一种向轴底部添加值的方法是选择所有.tick 元素并为每个元素添加一个新的text 元素。例如:

let axis_bottom = g.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b/%d/%Y")).ticks(d3.timeYear).ticks(5));

axis_bottom
  .selectAll("text")
  .attr("dy", ".5em");

axis_bottom
  .selectAll('.tick')
  .append('text')
  .attr("dy", "2.5em")
  .attr("fill", "currentColor")
  .text((e) => {
      // Do whatever calculation on e here.
      return 'abcd';
  });

这就是它的样子:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-20
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 2021-05-01
    • 1970-01-01
    • 2021-08-02
    相关资源
    最近更新 更多