如何将值传递给D3中的行生成函数 [英] How to pass a value to line generation function in D3

查看:45
本文介绍了如何将值传递给D3中的行生成函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码用于在D3中生成行:

Following code is used to generate lines in D3:

    var lineFn = d3.line()
        .x((d) => this.base.xAxis.scale(d.x))
        .y((d) => this.base.yAxes[0].scale(d.y));

    // series is a collection of lines I want to plot
    series = [
         {
             data: [{x: 10, y: 20}, {x: 20, y: 30}],
             yAxis: 0,   // this indicates which y-axis to use
             color: red
         },
         ...
    ];

    _.forEach(series, (line) => {
        this.base.chart.append("path")
            .datum(line.data)
            .attr("class", "line")
            .attr("d", lineFn)
            .style("stroke", line.color)
    });

我的图表使用d3.axisLeft()d3.axisRight()使用双y轴.

My chart uses dual y-axes using d3.axisLeft() and d3.axisRight().

现在,我正在硬编码要在lineFn中使用的y-axis的值.

Right now, I am hardcoding the value of which y-axis to use in the lineFn.

.y((d) => this.base.yAxes[0].scale(d.y)); // 0-left axis, 1-right axis

我想做的就是在调用line函数时传递该值,例如:

What I would like to do is pass that value when I call the line function, something like:

.attr("d", lineFn(line.yAxis))

有什么办法可以做到这一点?

Is there any way to achieve this?

谢谢.

推荐答案

最简单的方法是创建两个不同的行生成器.

The easiest way to achieve what you want is simply creating two different line generators.

但是,由于您问(不是逐字)在调用行生成器时是否可以动态定义比例尺?" ,答案是:是的,有可能.让我们看看如何做到这一点.

However, since you asked (not verbatim) "is it possible to define the scale dynamically when calling the line generator?", the answer is: yes, it is possible. Let's see how to do it.

在此示例中,我使用一个对象来存储不同的比例尺:

In this example, I'm using an object to store the different scales:

var scales = {
    yScaleLeft: d3.scaleLinear()
        .domain([0, 100])
        .range([170, 30]),
    yScaleRight: d3.scaleLinear()
        .domain([0, 200])
        .range([170, 30])
};

然后,在数据集中,定义每行应使用的比例尺和颜色,就像您做的一样:

And, in the dataset, defining which scale and color should be used for each line, just as you did:

var data = [{
    data: [{
        x: 1,
        y: 20
    }, {
        ...
    }, {
        x: 8,
        y: 50
    }],
    yAxis: "yScaleLeft",
    color: "red"
}, {
    data: [{
        x: 3,
        y: 120
    }, {
        ...
    }, {
        x: 9,
        y: 180
    }],
    yAxis: "yScaleRight",
    color: "blue"
}];

然后,当调用行生成器时,我们设置一个变量(在本例中为thisScale)来指定比例尺:

Then, when calling the line generator, we set a variable (in this case, thisScale) to specify the scale:

var thisScale;

paths.attr("stroke", d => d.color)
    .attr("d", d => {
        thisScale = scales[d.yAxis]
        return line(d.data);
    })
    .attr("fill", "none");

这里是演示,红线使用从0到100的比例尺,蓝线使用从0到200的比例尺.

Here is the demo, the red line uses a scale going from 0 to 100, the blue line uses a scale going from 0 to 200:

var svg = d3.select("body").append("svg")
  .attr("width", 500)
  .attr("height", 200);
  
var thisScale;

var line = d3.line()
  .x(d => xScale(d.x))
  .y(d => thisScale(d.y))
  .curve(d3.curveMonotoneX);

var data = [{
  data: [{
    x: 1,
    y: 20
  }, {
    x: 2,
    y: 30
  }, {
    x: 3,
    y: 10
  }, {
    x: 4,
    y: 60
  }, {
    x: 5,
    y: 70
  }, {
    x: 6,
    y: 80
  }, {
    x: 7,
    y: 40
  }, {
    x: 8,
    y: 50
  }],
  yAxis: "yScaleLeft",
  color: "red"
}, {
  data: [{
    x: 3,
    y: 120
  }, {
    x: 4,
    y: 130
  }, {
    x: 5,
    y: 10
  }, {
    x: 6,
    y: 120
  }, {
    x: 7,
    y: 40
  }, {
    x: 8,
    y: 130
  }, {
    x: 9,
    y: 180
  }],
  yAxis: "yScaleRight",
  color: "blue"
}];

var scales = {
  yScaleLeft: d3.scaleLinear()
    .domain([0, 100])
    .range([170, 30]),
  yScaleRight: d3.scaleLinear()
    .domain([0, 200])
    .range([170, 30])
};

var xScale = d3.scalePoint()
  .domain(d3.range(11))
  .range([30, 470])

var paths = svg.selectAll("foo")
  .data(data)
  .enter()
  .append("path");

paths.attr("stroke", d => d.color)
  .attr("d", d => {
    thisScale = scales[d.yAxis]
    return line(d.data);
  })
  .attr("fill", "none");

var xAxis = d3.axisBottom(xScale);

var yAxisLeft = d3.axisLeft(scales.yScaleLeft);

var yAxisRight = d3.axisRight(scales.yScaleRight);

var gX = svg.append("g").attr("transform", "translate(0,170)").call(xAxis);

var gY = svg.append("g").attr("transform", "translate(30,0)").call(yAxisLeft);

var gY2 = svg.append("g").attr("transform", "translate(470,0)").call(yAxisRight);

<script src="https://d3js.org/d3.v4.min.js"></script>

这里是相同的解决方案,只是使用数组(而不是对象)来存储比例,如您在问题中所问的那样:

And here the same solution, but using an array (instead of an object) to store the scales, as you asked in your question:

yAxis: 0//indicates the left axis
yAxis: 1//indicates the right axis

var svg = d3.select("body").append("svg")
  .attr("width", 500)
  .attr("height", 200);
  
var thisScale;

var line = d3.line()
  .x(d => xScale(d.x))
  .y(d => thisScale(d.y))
  .curve(d3.curveMonotoneX);

var data = [{
  data: [{
    x: 1,
    y: 20
  }, {
    x: 2,
    y: 30
  }, {
    x: 3,
    y: 10
  }, {
    x: 4,
    y: 60
  }, {
    x: 5,
    y: 70
  }, {
    x: 6,
    y: 80
  }, {
    x: 7,
    y: 40
  }, {
    x: 8,
    y: 50
  }],
  yAxis: 0,
  color: "red"
}, {
  data: [{
    x: 3,
    y: 120
  }, {
    x: 4,
    y: 130
  }, {
    x: 5,
    y: 10
  }, {
    x: 6,
    y: 120
  }, {
    x: 7,
    y: 40
  }, {
    x: 8,
    y: 130
  }, {
    x: 9,
    y: 180
  }],
  yAxis: 1,
  color: "blue"
}];

var scales = [d3.scaleLinear()
  .domain([0, 100])
  .range([170, 30]), d3.scaleLinear()
  .domain([0, 200])
  .range([170, 30])
];

var xScale = d3.scalePoint()
  .domain(d3.range(11))
  .range([30, 470])

var paths = svg.selectAll("foo")
  .data(data)
  .enter()
  .append("path");

paths.attr("stroke", d => d.color)
  .attr("d", d => {
    thisScale = scales[d.yAxis]
    return line(d.data);
  })
  .attr("fill", "none");

var xAxis = d3.axisBottom(xScale);

var yAxisLeft = d3.axisLeft(scales[0]);

var yAxisRight = d3.axisRight(scales[1]);

var gX = svg.append("g").attr("transform", "translate(0,170)").call(xAxis);

var gY = svg.append("g").attr("transform", "translate(30,0)").call(yAxisLeft);

var gY2 = svg.append("g").attr("transform", "translate(470,0)").call(yAxisRight);

<script src="https://d3js.org/d3.v4.min.js"></script>

这篇关于如何将值传递给D3中的行生成函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆