【问题标题】:How to change line color in d3js according to axis value?如何根据轴值更改d3js中的线条颜色?
【发布时间】:2025-12-13 05:50:02
【问题描述】:

如果 X > 100,我想更改此折线图的颜色,我希望它变成“红色”

有没有一种方法可以根据 X 的值在笔触颜色样式中使用条件?

http://jsfiddle.net/iamjeannie/b445svob/1/enter link description here

var lineData = [ { "x": 1,   "y": 5},  { "x": 20,  "y": 20},
                  { "x": 40,  "y": 10}, { "x": 60,  "y": 40},
                  { "x": 80,  "y": 5},  { "x": 100, "y": 60},
                { "x": 120,  "y": 15},  { "x": 140, "y": 40},
                { "x": 160,  "y": 25},  { "x": 180, "y": 20},
                { "x": 200,  "y": 15},  { "x": 220, "y": 80},
                { "x": 240,  "y": 35},  { "x": 260, "y": 60}
               ];

 //This is the accessor function we talked about above
var lineFunction = d3.svg.line()
                          .x(function(d) { return d.x; })
                          .y(function(d) { return d.y; })
                         .interpolate("linear");

//The SVG Container
var svgContainer = d3.select("body").append("svg")
                                    .attr("width", 200)
                                    .attr("height", 200);

//The line SVG Path we draw
var lineGraph = svgContainer.append("path")
                            .attr("d", lineFunction(lineData))
                            .attr("stroke", "blue")
                            .attr("stroke-width", 2)
                            .attr("fill", "none");

【问题讨论】:

  • 你想让你的一半路径有不同的颜色吗?据我所知,这在当前版本的 SVG 中是不可能的。您是否考虑过绘制多条路径而不是一条?
  • 我猜问题是您一次提供整个数据集(而不是单个段),因此很难在这种方法中找到相关的子段。想到两个快速的想法:(1)单独绘制段并在stroke属性中构建条件或(2)对数据应用过滤器并绘制两次(如上面@Oleg的评论)
  • 你可以用渐变来做。使用userSpaceOnUse 坐标定义渐变(实际上颜色会发生急剧变化),根据您要更改颜色的轴上的值,然后设置路径的描边以使用该渐变。请参阅this answer 了解类似情况,但使用一种模式,并提供进一步的解释和工作示例的链接。

标签: javascript jquery css d3.js


【解决方案1】:

我认为您可以通过为线条定义渐变而不是对其进行造型来实现这一点。 在此处查看此解决方案。 change color of line graph based on data (red for above threshold of say 0 , and blue for below 0)

我昨天问了一个非常相似的问题,并且通过阅读 D3 文档并查看了一些类似这样的示例,我能够让它工作 https://bl.ocks.org/mbostock/3970883

svg.append("linearGradient")
               .attr("id", "line-gradient")
               .attr("gradientUnits", "userSpaceOnUse")
               .attr("x1", 0).attr("y1", y(0))
               .attr("x2", 0).attr("y2", y(2))
               .selectAll("stop")
               .data(
                      [
                       {offset: "100%", color: "blue"},
                       {offset: "100%", color: "red"},
                      ]
                    )
                .enter().append("stop")
                        .attr("offset", function(d) { return d.offset; })
                        .attr("stop-color", function(d) { return d.color; });

【讨论】:

  • 如果您想像我一样将颜色保留在 CSS/SCSS 中,这是最好的答案,因为您可以将数据数组更改为“类”而不是“颜色”/“停止颜色” d3 代码。它也不会像接受的答案那样隔离数据行。
【解决方案2】:

这是我想出的一个简单示例:

让我们使用多行而不是单个路径。

我们需要将数据转换为具有以下属性:

[
  {
    x1: currentX,
    y1: currentY,
    x2: nextX,
    y2: nextY
  },
  ...
]

然后我们可以根据数据用一个有条件的stroke属性来绘制它们:

var lines = svgContainer.selectAll('line')
    .data(lineData)
    .enter()
    .append('line')
    .attr('x1', function(d) { return d.x1; })
    .attr('y1', function(d) { return d.y1; })
    .attr('x2', function(d) { return d.x2; })
    .attr('y2', function(d) { return d.y2; })
    .attr("stroke", function (d) {
        return (d.x > 50) ? 'red' : 'blue';
    })
    .attr("fill", "none")
    .attr("stroke-width", 2);

这是一个演示:

var lineData = [
        {"x": 1, "y": 5},
        {"x": 20, "y": 20},
                  { "x": 40,  "y": 10}, { "x": 60,  "y": 40},
                  { "x": 80,  "y": 5},  { "x": 100, "y": 60},
                { "x": 120,  "y": 15},  { "x": 140, "y": 40},
                { "x": 160,  "y": 25},  { "x": 180, "y": 20},
                { "x": 200,  "y": 15},  { "x": 220, "y": 80},
                { "x": 240,  "y": 35},  { "x": 260, "y": 60}
               ];
 
 //This is the accessor function we talked about above
var lineFunction = d3.svg.line()
                          .x(function(d) { return d.x; })
                          .y(function(d) { return d.y; })
                         .interpolate("linear");

//The SVG Container
var svgContainer = d3.select("body").append("svg")
                                    .attr("width", 200)
                                    .attr("height", 200);

lineData = lineData.map(function (point, index, arr) {
    var next = arr[index + 1],
        prev = arr[index - 1];
    return {
        x: point.x,
        y: point.y,
        x1: point.x,
        y1: point.y,
        x2: (next) ? next.x : prev.x,
        y2: (next) ? next.y : prev.y
    };
});

var lines = svgContainer.selectAll('line')
        .data(lineData)
        .enter()
        .append('line')
        .attr('x1', function(d) { return d.x1; })
        .attr('y1', function(d) { return d.y1; })
        .attr('x2', function(d) { return d.x2; })
        .attr('y2', function(d) { return d.y2; })
        .attr("stroke", function (d) {
            return (d.x > 50) ? 'red' : 'blue';
        })
        .attr("fill", "none")
        .attr("stroke-width", 2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

【讨论】:

  • 我想用不同的颜色突出一个陡峭的渐变 - 我认为你的代码给了我一个开始 - 这是我的小提琴上的 mod:jsfiddle.net/q744d5bd/8 ...谢谢!
【解决方案3】:

这是另一种方式,在某些情况下可能会有所帮助:

我所做的只是使用filter 拆分数据:

var lineGraph1 = svgContainer.append("path")
        .attr("d", lineFunction(lineData.filter(function(d) {
            return d.x <= 100;
        })))
        .attr("stroke", "blue")
        .attr("stroke-width", 2)
        .attr("fill", "none");
var lineGraph2 = svgContainer.append("path")
        .attr("d", lineFunction(lineData.filter(function(d) {
            return d.x >= 100;
        })))
        .attr("stroke", "red")
        .attr("stroke-width", 2)
        .attr("fill", "none");

【讨论】:

  • 看起来d.x时,它同时在lineGraph1和lineGraph2上。这是故意的吗? (例如,我推荐d.x &lt; 100d.x &gt;= 100)。
  • 当然,你可以稍微调整一下,你是对的。鉴于stroke-width,在许多情况下会有重叠,所以如果您关心“叠加层”的颜色(因为顺序在 svg 中很重要),我建议您考虑线条的顺序。感谢@ryanm 的输入!