【问题标题】:Fill / Shade a chart above a specific Y value in PlotlyJS在 PlotlyJS 中填充/着色特定 Y 值上方的图表
【发布时间】:2017-12-30 01:59:46
【问题描述】:

我想在 PlotlyJS 中填充一个特定的 Y 值。这是我从 PlotlyJS 文档中得到的:Fiddle

{
  "x": [
    "2016-01-31T00:03:57.000Z",
    "2016-02-12T04:35:26.000Z"
  ],
  "y": [
    100,
    100
  ],
  "fill": "tonexty",
  "fillcolor": "#8adcb3"
}

在文档中,似乎有两个选项:

  1. tonexty - 填充如下。问题是“tonexty”有点限制 - 用例是“填充直到行”,因此仅在 110 以上着色。示例:

  1. tozeroy - 填充到零:

另外,您是否需要引入新的跟踪才能创建填充?

这意味着if I have a chart as follows (with only one trace but a threshold line as a shape):我需要引入另一个跟踪只是为了创建一个填充。也许我在文档中遗漏了一些东西,或者这完全是错误的方法。

那么,如何在 PlotlyJS 中填充特定 Y 值上方的轨迹区域?

【问题讨论】:

    标签: javascript plotly stacked-area-chart


    【解决方案1】:

    一种解决方案是使用多个跟踪。
    在大于 0 和不大于 0 之间拆分所有痕迹。
    完成后,您可以用“tozeroy”值填充(或不填充)。

    following jsfiddle 显示了一个工作示例。

    代码如下:

    HTML:

    <div id="myDiv" style="width:600px;height:250px;"></div>
    

    JS:

    var data = [
      {
        x: ['A', 'B', 'C', 'D'],
        y: [1, 3, 6, 0],
        fill: 'tozeroy',
        fillcolor: '#8adcb3'
      },
      {
        x: ['D', 'F', 'G', 'I'],
        y: [0, -3, -2, 0],
        fill: 'toself'
      },
       {
        x: ['I', 'J', 'K'],
        y: [0, 5, 7],
        fill: 'tozeroy',
        fillcolor: '#0adcb3'
      }
    ];
    
    Plotly.newPlot('myDiv', data);
    

    结果如下:

    【讨论】:

    • Don't cross the streams 更严重的是,实际上因为我只是在玩 plotly lib,所以我无法为您提供更好的解决方案。我很好奇如何通过更优雅的解决方案来实现这一点。
    • 这是一个很好的解决方案。我也没有想出一些更优雅的。您可以使用 legendgroup 使图例更漂亮,仅此而已。
    • 但更关键的是:问题是“高于特定的 Y 值”。我认为这不适用于您的解决方案,还是我遗漏了什么?
    【解决方案2】:

    这是另一个利用 Plotly 的 fill: "toself" 的解决方案。这个想法是创建一个封闭的线迹,将阈值以上的区域和主线的标记包围起来。适用于高于零的阈值和数字 x 值。

    辅助迹线隐藏了它们的图例并与主迹线组合在一起,从而防止在切换图例时出现丑陋的伪影。

    该函数检查每个 x-y 对是否 y 值高于阈值,如果是则

    • 检查是否已经有一个段高于阈值并使用此段或创建一个新段
    • 分段从阈值的 y 值开始,中间的 x 值从阈值上方的点和之前的点开始。
    • 每个段都以一个等于阈值的 y 值和该段中最后一个点与下一个点的平均值的 x 值终止

    函数本身当然可以用更好的方式编写,但这只是一个概念验证。

    function dataToTraces(data, threshold) {
    
      var fillers = [];
    
      var emptyFiller = {
        x: [],
        y: [],
        fill: "toself",
        mode: "lines",
        line: {
          width: 0
        },
        opacity: 0.5,
        fillcolor: "#8adcb3",
        showlegend: false,
        legendgroup: "main"
      }
      
      fillers.push(emptyFiller);
    
      for (var i = 0; i < data.y.length; i += 1) {
        if (data.y[i] >= threshold) {
          if (i !== 0 && data.y[i - 1] < threshold) {
            fillers[fillers.length - 1].x.push(data.x[i - 1] + (threshold - data.y[i - 1]) / (data.y[i] - data.y[i - 1]));
            fillers[fillers.length - 1].y.push(threshold);
          }
          fillers[fillers.length - 1].x.push(data.x[i]);
          fillers[fillers.length - 1].y.push(data.y[i]);
        } else if (fillers[fillers.length - 1].x.length > 0) {
          if (i !== 0 && data.y[i - 1] !== threshold) {
            fillers[fillers.length - 1].x.push(data.x[i - 1] + (threshold - data.y[i - 1]) / (data.y[i] - data.y[i - 1]));
            fillers[fillers.length - 1].y.push(threshold);
          }
          fillers.push(emptyFiller);
        }
      }
      return fillers;
    }
    
    var data = [{
      x: [0, 1, 2, 3, 4, 5, 6, 7, 8],
      y: [1, 3, 6, 2, -1, 5, 1, 3, 0],
      name: "main",
      legendgroup: "main"
    }];
    var fillers = dataToTraces(data[0], 2);
    
    Plotly.newPlot("myDiv", data.concat(fillers));
    <div id="myDiv"></div>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

    【讨论】:

    • 这是一个很好的解决方案,但你能更详细地解释一下你在做什么吗?
    • @user3886058 我添加了一些解释,希望现在更清楚
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 2013-01-30
    相关资源
    最近更新 更多