【问题标题】:How to fill area with a vertical line chart?如何用垂直折线图填充区域?
【发布时间】:2019-09-09 18:48:32
【问题描述】:

我正在尝试使用 D3.js 制作一个垂直图表,并用线条和 y 轴之间的颜色来感受该区域,但它根本没有填充。它只填充了一部分。

这是我想要得到的正确图表的图像:

这是我现在的错误图表的图像:

wrong-filled-chart

用标准图表来填充区域很简单。可以使用 y0 参数并将其设置为零以填充 x 轴和 y 的顶部值之间的所有区域。

垂直图表填充区域对我来说不是那么简单,因为我无法使用 y0 来解决问题。我让它工作的唯一方法是在输入数组的末尾添加行值,另一个元素具有此值 (x,y)=>(0, min-depth)。所以对于 x 值,我总是至少有一个元素为零。

var allArray = [{
    "parameter": 0.32,
    "depth": -0.02
  },
  {
    "parameter": 0.32,
    "depth": -0.04
  },
  {
    "parameter": 0.325,
    "depth": -0.06
  },
  {
    "parameter": 0.33,
    "depth": -0.08
  },
  {
    "parameter": 0.335,
    "depth": -0.1
  },
  {
    "parameter": 0.33,
    "depth": -0.12
  },
  {
    "parameter": 0.315,
    "depth": -0.14
  },
  {
    "parameter": 0.325,
    "depth": -0.16
  },
  {
    "parameter": 0.33,
    "depth": -0.18
  },
  {
    "parameter": 0.335,
    "depth": -0.2
  },
  {
    "parameter": 0.335,
    "depth": -0.22
  },
  {
    "parameter": 0.315,
    "depth": -0.24
  },
  {
    "parameter": 0.32,
    "depth": -0.26
  },
  {
    "parameter": 0.33,
    "depth": -0.28
  },
  {
    "parameter": 0.34,
    "depth": -0.3
  },
  {
    "parameter": 0.345,
    "depth": -0.32
  },
  {
    "parameter": 0.355,
    "depth": -0.34
  },
  {
    "parameter": 0.37,
    "depth": -0.36
  },
  {
    "parameter": 0.365,
    "depth": -0.38
  },
  {
    "parameter": 0.335,
    "depth": -0.4
  },
  {
    "parameter": 0.32,
    "depth": -0.42
  },
  {
    "parameter": 0.3,
    "depth": -0.44
  },
  {
    "parameter": 0.29,
    "depth": -0.46
  },
  {
    "parameter": 0.235,
    "depth": -0.48
  },
  {
    "parameter": 0.22,
    "depth": -0.5
  }
];

draw2("#svg4a", allArray);

function draw2(selector2, allArray) {

  var data = allArray;

  var startElement = { depth: 0, parameter: 0.3 };

  data.unshift(startElement);

  var margin = {
    top: 20,
    right: 20,
    bottom: 0,
    left: 35
  };
  var width = 150 - margin.left,
    height = 580 - margin.top;

  var svg = d3.select(selector2)
    .append("svg")
    .attr("class", "SVGcontent")
    .attr("width", width + margin.left)
    .attr("height", height + margin.top);

  // Pattern definition
  const defs = svg.append('defs')
    .append('pattern')
    .attr('id', 'whitecarbon2')
    .attr('patternUnits', 'userSpaceOnUse')
    .attr('width', 4)
    .attr('height', 4)
    .append('path')
    .attr('stroke', '#010101')
    .attr('stroke-width', 1)
    .attr("opacity", 0.5)
    .attr('d', 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2');

  data.forEach(function(d) {
    d.parameter = parseFloat(d.parameter);
  });
  var xScale = d3.scaleLinear()
    .domain([
      d3.max(data, function(d) {
        return d.parameter
      }) + 0.4, 0
    ])
    .range([0, width]);

  var yScale = d3.scaleLinear()
    .domain([
      0,
      d3.min(data, function(d) {
        return d.depth
      })
    ])
    .range([0, height - 20]);

  var line = d3.line()
    .x(function(d) {
      return xScale(d.parameter)
    })
    .y(function(d) {
      return yScale(d.depth)
    });

  var artboard = svg.append("g")
    .attr("transform", "translate(35," + margin.top + ")");

  var area = d3.area()
  .x1(function(d) {
      return xScale(d.parameter)
  })
  .x0(xScale(0))
  .y(function(d) {
      return yScale(d.depth)
  });

  // add the area
  artboard.append("path")
    .datum(data)
    .attr("class", "areaColore1")
    .attr("d", area)
    .attr("fill", "#fefefe");

  // add the pattern
  artboard.append("path")
    .datum(data)
    .attr("class", "area")
    .attr("d", area)
    .style('stroke', '#777777')
    .attr("fill", "url(#whitecarbon2)");

  artboard.append("path")
    .attr("d", line(data))
    .attr("stroke-width", "2")
    .attr("fill", "none");

  var xAxis = d3.axisTop(xScale);

  ticks = xScale.ticks(1);
  ticks.push(0);
  ticks.push(0.3);
  xAxis.tickValues(ticks);
  var yAxis = d3.axisLeft(yScale);

  artboard.append("g")
    .attr("class", "xAxis")
    .call(xAxis)
    .selectAll("text")
    .attr("y", -15)
    .attr("x", 0)
    .attr("dy", ".35em")
    .attr("transform", "rotate(none)")
    .style("text-anchor", "middle");

  artboard.append("g")
    .attr("transform", "translate(0,0)")
    .attr("class", "yAxis")
    .call(yAxis);
  // Adding title label to axis Y
  artboard.append("text")
    .attr("transform", "rotate(90)")
    .attr("y", 30)
    .attr("x", 6)
    // .attr("dy", "1em")
    .style('fill', '#777777')
    .style("text-anchor", "start")
    .text("Depth [m]");


  function make_x_gridlines() {
    return xAxis.ticks(1);
  }

  function make_y_gridlines() {
    return yAxis.ticks(11);
  }


  artboard.append("g")
    .attr("class", "grid gridX")
    .call(make_x_gridlines()
      .tickSize(-height + margin.top - 50)
      .tickFormat("")
    )

  artboard.append("g")
    .attr("class", "grid gridY2")
    .attr("transform", "translate(0,0)")
    .call(make_y_gridlines()
      .tickSize(-200)
      .tickFormat("")
    )
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="svg4a"></div>

预期:用颜色填充从垂直值线到 y 轴的所有区域。

实际:填充区域仅用于线的第一个点值和最后一个点值之间的连接线。

这里是一个活生生的例子:Live chart

注意: 我还尝试添加此代码以使参数字段中始终为 0,因此图表已正确填充。

我添加的代码是这个:

  var startElement = { depth: 0, parameter: 0.3 };

  data.unshift(startElement);

而且这个也可以正常工作而无需设置 .x0 (即使设置它是正确的)。 但我的目标是找到一个配置,我不必在输入数组值中插入假值。我认为插入 .x0 应该足以使图表填充整个,就像 y0 如果图表处于水平模式,则从零填充到参数值。 有没有办法在不插入假值的情况下做到这一点?

【问题讨论】:

    标签: javascript d3.js axis area


    【解决方案1】:

    如果您想要一个垂直面积图,则不应使用xy0y1。您应该改用yx0x1

    var area = d3.area()
        .x1(function(d) {
            return xScale(d.parameter)
        })
        .x0(xScale(0))
        .y(function(d) {
            return yScale(d.depth)
        });
    

    这是您的更改代码:

    var allArray = [{
        "parameter": 0.32,
        "depth": 0
      }, {
        "parameter": 0.32,
        "depth": -0.02
      },
      {
        "parameter": 0.32,
        "depth": -0.04
      },
      {
        "parameter": 0.325,
        "depth": -0.06
      },
      {
        "parameter": 0.33,
        "depth": -0.08
      },
      {
        "parameter": 0.335,
        "depth": -0.1
      },
      {
        "parameter": 0.33,
        "depth": -0.12
      },
      {
        "parameter": 0.315,
        "depth": -0.14
      },
      {
        "parameter": 0.325,
        "depth": -0.16
      },
      {
        "parameter": 0.33,
        "depth": -0.18
      },
      {
        "parameter": 0.335,
        "depth": -0.2
      },
      {
        "parameter": 0.335,
        "depth": -0.22
      },
      {
        "parameter": 0.315,
        "depth": -0.24
      },
      {
        "parameter": 0.32,
        "depth": -0.26
      },
      {
        "parameter": 0.33,
        "depth": -0.28
      },
      {
        "parameter": 0.34,
        "depth": -0.3
      },
      {
        "parameter": 0.345,
        "depth": -0.32
      },
      {
        "parameter": 0.355,
        "depth": -0.34
      },
      {
        "parameter": 0.37,
        "depth": -0.36
      },
      {
        "parameter": 0.365,
        "depth": -0.38
      },
      {
        "parameter": 0.335,
        "depth": -0.4
      },
      {
        "parameter": 0.32,
        "depth": -0.42
      },
      {
        "parameter": 0.3,
        "depth": -0.44
      },
      {
        "parameter": 0.29,
        "depth": -0.46
      },
      {
        "parameter": 0.235,
        "depth": -0.48
      },
      {
        "parameter": 0.22,
        "depth": -0.5
      }
    ];
    
    draw2("#svg4a", allArray);
    
    function draw2(selector2, allArray) {
    
      var data = allArray;
    
      var margin = {
        top: 20,
        right: 20,
        bottom: 0,
        left: 35
      };
      var width = 150 - margin.left,
        height = 580 - margin.top;
    
      var svg = d3.select(selector2)
        .append("svg")
        .attr("class", "SVGcontent")
        .attr("width", width + margin.left)
        .attr("height", height + margin.top);
    
      // Pattern definition
      const defs = svg.append('defs')
        .append('pattern')
        .attr('id', 'whitecarbon2')
        .attr('patternUnits', 'userSpaceOnUse')
        .attr('width', 4)
        .attr('height', 4)
        .append('path')
        .attr('stroke', '#010101')
        .attr('stroke-width', 1)
        .attr("opacity", 0.5)
        .attr('d', 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2');
    
      data.forEach(function(d) {
        d.parameter = parseFloat(d.parameter);
      });
      var xScale = d3.scaleLinear()
        .domain([
          d3.max(data, function(d) {
            return d.parameter
          }) + 0.4, 0
        ])
        .range([0, width]);
    
      var yScale = d3.scaleLinear()
        .domain([
          0,
          d3.min(data, function(d) {
            return d.depth
          })
        ])
        .range([0, height - 20]);
    
      var line = d3.line()
        .x(function(d) {
          return xScale(d.parameter)
        })
        .y(function(d) {
          return yScale(d.depth)
        });
    
      var artboard = svg.append("g")
        .attr("transform", "translate(35," + margin.top + ")");
    
      var area = d3.area()
        .x1(function(d) {
          return xScale(d.parameter)
        })
        .x0(xScale(0))
        .y(function(d) {
          return yScale(d.depth)
        });
    
      // add the area
      artboard.append("path")
        .datum(data)
        .attr("class", "areaColore1")
        .attr("d", area)
        .attr("fill", "#fefefe");
    
      // add the pattern
      artboard.append("path")
        .datum(data)
        .attr("class", "area")
        .attr("d", area)
        .style('stroke', '#777777')
        .attr("fill", "url(#whitecarbon2)");
    
      artboard.append("path")
        .attr("d", line(data))
        .attr("stroke-width", "2")
        .attr("fill", "none");
    
      var xAxis = d3.axisTop(xScale);
    
      ticks = xScale.ticks(1);
      ticks.push(0);
      ticks.push(0.3);
      xAxis.tickValues(ticks);
      var yAxis = d3.axisLeft(yScale);
    
      artboard.append("g")
        .attr("class", "xAxis")
        .call(xAxis)
        .selectAll("text")
        .attr("y", -15)
        .attr("x", 0)
        .attr("dy", ".35em")
        .attr("transform", "rotate(none)")
        .style("text-anchor", "middle");
    
      artboard.append("g")
        .attr("transform", "translate(0,0)")
        .attr("class", "yAxis")
        .call(yAxis);
      // Adding title label to axis Y
      artboard.append("text")
        .attr("transform", "rotate(90)")
        .attr("y", 30)
        .attr("x", 6)
        // .attr("dy", "1em")
        .style('fill', '#777777')
        .style("text-anchor", "start")
        .text("Depth [m]");
    
    
      function make_x_gridlines() {
        return xAxis.ticks(1);
      }
    
      function make_y_gridlines() {
        return yAxis.ticks(11);
      }
    
    
      artboard.append("g")
        .attr("class", "grid gridX")
        .call(make_x_gridlines()
          .tickSize(-height + margin.top - 50)
          .tickFormat("")
        )
    
      artboard.append("g")
        .attr("class", "grid gridY2")
        .attr("transform", "translate(0,0)")
        .call(make_y_gridlines()
          .tickSize(-200)
          .tickFormat("")
        )
    }
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <div id="svg4a"></div>

    PS:要获得与图像中类似的面积图,您需要第一个深度为 0 的数据点。

    【讨论】:

    • 我在第一篇文章的末尾添加了一个点。谢谢回复!我想要一个配置值来使图表始终从零填充,就像我设置 y0 值时水平图表一样。我被问到为什么 .x0 无法做到这一点,但我必须添加一个假值才能使其成为可能.. 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多