【问题标题】:D3 calculate x position from datesD3根据日期计算x位置
【发布时间】:2020-12-11 15:11:54
【问题描述】:

我有一个 D3 图,我在 x 上绘制时间 (hh:mm) 与 y 轴上的一些值。

对于 x 比例,我使用这个逻辑

    const currentData : string[] = ['06:00', '12:00', '18:00'];

    this.x = d3Scale.scalePoint(
      [0, this.width - this.margin.right - this.margin.left])
      .domain(
        currentData.map(
          (d: PlotData) => d.time))
      .round(true);
   

这很好地绘制了我的所有数据。现在我想使用this.x 来返回当前不在我的原始数据中的时间点的值。但是当我运行它时

this.x('14:00')

它返回 NAN ,这似乎是因为输入不在 currentData 数组中并且仅对数组​​中的值起作用。

我需要自己插入这个值还是有一个 D3 函数来获取 this.x 并在内部计算 this.x('14:00')

谢谢, 艾尔

【问题讨论】:

    标签: javascript typescript d3.js


    【解决方案1】:

    另一个答案建议使用 d3-scaleTime 的正确方法。我想深入了解您看到问题的原因,然后使用 d3-scaleTime 提供解决方案的详细信息。

    序数音阶

    d3.scalePoint 是一个序数比例。域表示一组离散和不连续的值。域到范围的映射基于指定域值的顺序。域中的第一个值映射到范围中的第一个值(使用 d3.scalePoint),无论其值与域中的其他值相比如何。

    因此,只有存在于域中的值才能映射到范围:域中的值之间没有语义/数量关系,允许在值之间进行插值。因为您使用的是定量数据而不是定性或有序数据,所以您希望使用将域视为连续的尺度。

    在某些情况下,您可能希望将 d3.scalePoint/Band 比例与基于时间的数据一起使用,但在这些情况下,您需要能够构建一个包含所有需要的值的完整域被绘制。

    您的比例一开始似乎将您的数据绘制为连​​续的,这是巧合,如果您的中间域值是“07:00”、“六月”或“昨天”,它会出现在您范围的中间.您选择“12:00”隐藏了这样一个事实,即刻度不是根据它的值定位它,而是仅仅根据它的索引来定位它。

    连续音阶

    d3.scaleTime 是 d3 的连续刻度之一

    连续尺度将连续的定量输入域映射到连续的输出范围。 (docs)

    域和范围

    对于 d3 的连续尺度,domain 和 range 必须包含相同数量的元素 - 如果每个元素中有两个以上,则 domain 和 range 被拆分为段:

     .domain([a,b,c]) // where a,b,c are quantitative
     .range([1,2,3])
    

    a 和 b 之间的值将在 1 和 2 之间进行插值,同样,b 和 c 之间的值将在 2 和 3 之间进行插值。如果 domain 和 range 具有不同数量的元素,D3 将跳过一个多余的值还有更多。

    在您的情况下,似乎只有两个域值就足够了,即您想要传递给秤的最小值和最大值。

    使用日期

    d3.scaleTime 的域需要设置日期对象而不是字符串,例如 '12:00',此外,在将值传递给比例 (scale(x)) 时,我们需要传递一个日期对象。我们可以创建一个基本的 d3 日期解析器:

     d3.parseTime("%H:%M")
    

    这给了我们:

    const currentData = ['06:00', '12:00', '18:00'];
    
    const parse = d3.timeParse("%H:%M")
    
    const x = d3.scaleTime()
            .range([0,100])
          .domain(d3.extent(currentData, (time) => parse(time)))
          
    console.log("15:00 scales to: ", x(parse('15:00')))
    console.log("06:00 scales to: ", x(parse('06:00')))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    这应该像以前一样映射您的域,但也允许您绘制不在初始数据集中的值,并根据它们的值将它们正确映射到范围。

    【讨论】:

      【解决方案2】:

      改用scaleTime 可能更容易

      const currentData : string[] = ['06:00', '12:00', '18:00'];
      
      this.x = d3.scaleTime()
        .domain((d: PlotData) => d.time))
        .range([0, this.width - this.margin.right - this.margin.left]);
      
      this.x(new DateTime('xyz:abc'))
      

      【讨论】:

        猜你喜欢
        • 2020-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多