score:1

Accepted answer

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"
}];

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");

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>


Related Query