複数のy軸を持つ複数の折れ線グラフにデータポイントをプロットする方法

Chew Kah Meng

複数のy軸を持つ折れ線グラフにデータポイントを追加しようとしています。クリックしてここに私のバイオリンのための。

    //after restructuring dataset array
    var data = [{
      data: [{
        x: 0,
        y: 0
      }, {
        x: 10,
        y: 10
      }, {
        x: 20,
        y: 20
      }, {
        x: 30,
        y: 30
      }, {
        x: 40,
        y: 40
      }],
      yAxis: 0,
    }, {
      data: [{
        x: 0,
        y: 0
      }, {
        x: 10,
        y: 200
      }, {
        x: 20,
        y: 300
      }, {
        x: 30,
        y: 400
      }, {
        x: 40,
        y: 500
      }],
      yAxis: 1,
    }];

    const margin = {
      left: 20,
      right: 20,
      top: 20,
      bottom: 80
    };

    const svg = d3.select('svg');
    svg.selectAll("*").remove();

    const width = 200 - margin.left - margin.right;
    const height = 200 - margin.top - margin.bottom;
    const g = svg.append('g').attr('transform', `translate(${80},${margin.top})`);

    //************* Axes and Gridlines ***************
    const xAxisG = g.append('g');
    const yAxisG = g.append('g');

    xAxisG.append('text')
      .attr('class', 'axis-label')
      .attr('x', width / 3)
      .attr('y', -10)
      .style('fill', 'black')
      .text(function(d) {
      return "X Axis";
    });

    yAxisG.append('text')
      .attr('class', 'axis-label')
      .attr('id', 'yAxisLabel0')
      .attr('x', -height / 2)
      .attr('y', -15)
      .attr('transform', `rotate(-90)`)
      .style('text-anchor', 'middle')
      .style('fill', 'black')
      .text(function(d) {
      return "Y Axis 1";
    });

    // interpolator for X axis -- inner plot region
    var x = d3.scaleLinear()
    .domain([0, d3.max(xValueArray)])
    .range([0, width])
    .nice();

    var yScale = new Array();
    for (var i = 0; i < 2; i++) {
      // interpolator for Y axis -- inner plot region
      var y = d3.scaleLinear()
      .domain([0, d3.max(arr[i])])
      .range([0, height])
      .nice();
      yScale.push(y);
    }

    const xAxis = d3.axisTop()
    .scale(x)
    .ticks(5)
    .tickPadding(2)
    .tickSize(-height)

    const yAxis = d3.axisLeft()
    .scale(yScale[0])
    .ticks(5)
    .tickPadding(2)
    .tickSize(-width);

    yAxisArray = new Array();
    yAxisArray.push(yAxis);
    for (var i = 1; i < 2; i++) {
      var yAxisSecondary = d3.axisLeft()
      .scale(yScale[i])
      .ticks(5)
      yAxisArray.push(yAxisSecondary);
    }

    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", `translate(80,${height-80})`)
      .call(xAxis);

    svg.append("g")
      .attr("class", "y axis")
      .attr("id", "ySecAxis0")
      .attr("transform", "translate(80,20)")
      .call(yAxis);

    var translation = 50;
    var textTranslation = 0;
    var yLabelArray = ["Y Axis 1", "Y Axis 2"];

    //loop starts from 1 as primary y axis is already plotted
    for (var i = 1; i < 2; i++) {
      svg.append("g")
        .attr("transform", "translate(" + translation + "," + 20 + ")")
        .attr("id", "ySecAxis" + i)
        .call(yAxisArray[i]);

      yAxisG.append('text')
        .attr('x', -height / 2)
        .attr('y', -60)
        .attr('transform', `rotate(-90)`)
        .attr("id", "yAxisLabel" + i)
        .style('text-anchor', 'middle')
        .style('fill', 'black')
        .text(yLabelArray[i]);

      translation -= 40;
      textTranslation += 40;
    }

    //************* Lines and Data Points ***************
    var colors = ["blue", "red"];

    var thisScale;

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

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

    paths.attr("stroke", function (d,i){return colors[i]})
      .attr("d", d => {
        thisScale = yScale[d.yAxis]
        return line(d.data);
      })
      .attr("stroke-width", 2)
      .attr("id", function (d,i){return "line" + i})
      .attr("fill", "none");

    var points = g.selectAll("dot")
      .data(data)
      .enter()
      .append("circle");

    points.attr("cx", function(d) { return x(d.x)} )
      .attr("cy", function(d,i) { return yScale[i](d.y); } )
      .attr("r", 3)
      .attr("class", function (d,i){return "blackDot" + i})
      .attr("clip-path", "url(#clip)")

現在、コンソールログに次のエラーが表示されています。エラー:属性cx:予想される長さ "NaN"。エラー:属性cy:予想される長さ「NaN」。正しいcxとcyをポイントに帰属させていないようですが、間違っていることを理解できません。どんな助けでも大歓迎です!

ジェラルド・フルタド

データ構造はオブジェクトの配列であり、各オブジェクトには円の実際の座標を持つ内部配列が含まれています。したがって、その単一入力の選択は機能しません。

最小限のリファクタリングで、ここでの私の解決策は、オブジェクトに従ってグループを追加し、次に、それぞれについて、内部配列に従って円を追加することです。その面倒なyScale作業では、円のインデックスに依存できなくなったため、ここではローカル変数を使用しています。

var pointsGroup = g.selectAll(null)
  .data(data)
  .enter()
  .append("g")
  .attr("fill", function(d, i) {
    local.set(this, yScale[i])
    return colors[i];
  });

var points = pointsGroup.selectAll(null)
  .data(function(d) {
    return d.data
  })
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return x(d.x)
  })
  .attr("cy", function(d, i) {
    return local.get(this)(d.y);
  })
  //etc...

これらの変更を加えたコードは次のとおりです。

var local = d3.local();
var xValueArray = [0, 10, 20, 30, 40];
var arr = [
  [0, 10, 20, 30, 40],
  [0, 200, 300, 400, 500]
];
var dataset = [
  [{
    x: 0,
    y: 0
  }, {
    x: 10,
    y: 10
  }, {
    x: 20,
    y: 20
  }, {
    x: 30,
    y: 30
  }, {
    x: 40,
    y: 40
  }],
  [{
    x: 0,
    y: 0
  }, {
    x: 10,
    y: 200
  }, {
    x: 20,
    y: 300
  }, {
    x: 30,
    y: 400
  }, {
    x: 40,
    y: 500
  }]
];

var data = [];
for (var i = 0; i < 2; i++) {
  data.push({
    "data": dataset[i],
    "yAxis": i
  })
}
console.log(data);

//after restructuring dataset array
var data = [{
  data: [{
    x: 0,
    y: 0
  }, {
    x: 10,
    y: 10
  }, {
    x: 20,
    y: 20
  }, {
    x: 30,
    y: 30
  }, {
    x: 40,
    y: 40
  }],
  yAxis: 0,
}, {
  data: [{
    x: 0,
    y: 0
  }, {
    x: 10,
    y: 200
  }, {
    x: 20,
    y: 300
  }, {
    x: 30,
    y: 400
  }, {
    x: 40,
    y: 500
  }],
  yAxis: 1,
}];

const margin = {
  left: 20,
  right: 20,
  top: 20,
  bottom: 80
};

const svg = d3.select('svg');
svg.selectAll("*").remove();

const width = 200 - margin.left - margin.right;
const height = 200 - margin.top - margin.bottom;
const g = svg.append('g').attr('transform', `translate(${80},${margin.top})`);

//************* Axes and Gridlines ***************
const xAxisG = g.append('g');
const yAxisG = g.append('g');

xAxisG.append('text')
  .attr('class', 'axis-label')
  .attr('x', width / 3)
  .attr('y', -10)
  .style('fill', 'black')
  .text(function(d) {
    return "X Axis";
  });

yAxisG.append('text')
  .attr('class', 'axis-label')
  .attr('id', 'yAxisLabel0')
  .attr('x', -height / 2)
  .attr('y', -15)
  .attr('transform', `rotate(-90)`)
  .style('text-anchor', 'middle')
  .style('fill', 'black')
  .text(function(d) {
    return "Y Axis 1";
  });

// interpolator for X axis -- inner plot region
var x = d3.scaleLinear()
  .domain([0, d3.max(xValueArray)])
  .range([0, width])
  .nice();

var yScale = new Array();
for (var i = 0; i < 2; i++) {
  // interpolator for Y axis -- inner plot region
  var y = d3.scaleLinear()
    .domain([0, d3.max(arr[i])])
    .range([0, height])
    .nice();
  yScale.push(y);
}

const xAxis = d3.axisTop()
  .scale(x)
  .ticks(5)
  .tickPadding(2)
  .tickSize(-height)

const yAxis = d3.axisLeft()
  .scale(yScale[0])
  .ticks(5)
  .tickPadding(2)
  .tickSize(-width);

yAxisArray = new Array();
yAxisArray.push(yAxis);
for (var i = 1; i < 2; i++) {
  var yAxisSecondary = d3.axisLeft()
    .scale(yScale[i])
    .ticks(5)
  yAxisArray.push(yAxisSecondary);
}

svg.append("g")
  .attr("class", "x axis")
  .attr("transform", `translate(80,${height-80})`)
  .call(xAxis);

svg.append("g")
  .attr("class", "y axis")
  .attr("id", "ySecAxis0")
  .attr("transform", "translate(80,20)")
  .call(yAxis);

var translation = 50;
var textTranslation = 0;
var yLabelArray = ["Y Axis 1", "Y Axis 2"];

//loop starts from 1 as primary y axis is already plotted
for (var i = 1; i < 2; i++) {
  svg.append("g")
    .attr("transform", "translate(" + translation + "," + 20 + ")")
    .attr("id", "ySecAxis" + i)
    .call(yAxisArray[i]);

  yAxisG.append('text')
    .attr('x', -height / 2)
    .attr('y', -60)
    .attr('transform', `rotate(-90)`)
    .attr("id", "yAxisLabel" + i)
    .style('text-anchor', 'middle')
    .style('fill', 'black')
    .text(yLabelArray[i]);

  translation -= 40;
  textTranslation += 40;
}

//************* Mouseover ***************
var tooltip = d3.select("body")
  .append("div")
  .style("opacity", 0)
  .attr("class", "tooltip")
  .style("background-color", "white")
  .style("border", "solid")
  .style("border-width", "1px")
  .style("border-radius", "5px")
  .style("padding", "10px")
  .style("position", "absolute")

var mouseover = function(d) {
  tooltip
    .html("x: " + d.x + "<br/>" + "y: " + d.y)
    .style("opacity", 1)
    .style("left", (d3.mouse(this)[0] + 90) + "px")
    .style("top", (d3.mouse(this)[1]) + "px")
}

// A function that change this tooltip when the leaves a point: just need to set opacity to 0 again
var mouseleave = function(d) {
  tooltip
    .transition()
    .duration(200)
    .style("opacity", 0)
}

//************* Lines and Data Points ***************
var colors = ["blue", "red"];

var thisScale;

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

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

paths.attr("stroke", function(d, i) {
    return colors[i]
  })
  .attr("d", d => {
    thisScale = yScale[d.yAxis]
    return line(d.data);
  })
  .attr("stroke-width", 2)
  .attr("id", function(d, i) {
    return "line" + i
  })
  .attr("fill", "none");

var pointsGroup = g.selectAll(null)
  .data(data)
  .enter()
  .append("g")
  .attr("fill", function(d, i) {
    local.set(this, yScale[i])
    return colors[i];
  });

var points = pointsGroup.selectAll(null)
  .data(function(d) {
    return d.data
  })
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return x(d.x)
  })
  .attr("cy", function(d, i) {
    return local.get(this)(d.y);
  })
  .attr("r", 3)
  .attr("class", function(d, i) {
    return "blackDot" + i
  })
  .attr("clip-path", "url(#clip)")
  .on("mouseover", mouseover)
  .on("mouseleave", mouseleave)

//plot lines (hard-coding)
/*var lineFunction1 = d3.line()
.x(function(d) {
  return x(d.x);
})
.y(function(d) {
  return yScale[0](d.y);
})
.curve(d3.curveLinear);

var lineFunction2 = d3.line()
.x(function(d) {
  return x(d.x);
})
.y(function(d) {
  return yScale[1](d.y);
})
.curve(d3.curveLinear);

var path1 = g.append("path")
.attr("class", "path" + 0)
.attr("id", "line" + 0)
.attr("d", lineFunction1(data[0]))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none")
.attr("clip-path", "url(#clip)");

var path2 = g.append("path")
.attr("class", "path" + 1)
.attr("id", "line" + 1)
.attr("d", lineFunction2(data[1]))
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("fill", "none")
.attr("clip-path", "url(#clip)");*/

//plot lines and points using for loop
/*for (var i = 0; i < 2; i++) {
  var lineFunction = d3.line()
  .x(function(d) {
    return x(d.x);
  })
  .y(function(d) {
    return yScale[i](d.y);
  })
  .curve(d3.curveLinear);

  var paths = g.append("path")
  .attr("class", "path" + i)
  .attr("id", "line" + i)
  .attr("d", lineFunction(data[i]))
  .attr("stroke", colors[i])
  .attr("stroke-width", 2)
  .attr("fill", "none")
  .attr("clip-path", "url(#clip)")

  //plot a circle at each data point
  g.selectAll(".dot")
    .data(data[i])
    .enter().append("circle")
    .attr("cx", function(d) { return x(d.x)} )
    .attr("cy", function(d) { return yScale[i](d.y); } )
    .attr("r", 3)
    .attr("class", "blackDot" + i)
    .attr("clip-path", "url(#clip)")
    .on("mouseover", mouseover)
    .on("mouseleave", mouseleave)
}*/

//************* Legend ***************
var legend = svg.selectAll(".legend")
  .data(data)
  .enter().append("g")

legend.append("rect")
  .attr("x", width + 65)
  .attr("y", function(d, i) {
    return 30 + i * 20;
  })
  .attr("width", 18)
  .attr("height", 4)
  .style("fill", function(d, i) {
    return colors[i];
  })

legend.append("text")
  .attr("x", width + 60)
  .attr("y", function(d, i) {
    return 30 + i * 20;
  })
  .attr("dy", ".35em")
  .style("text-anchor", "end")
  .text(function(d, i) {
    return "Value" + (i + 1);
  })
  .on("click", function(d, i) {
    // Determine if current line is visible
    let opacity = d3.select("#line" + i).style("opacity");
    let newOpacity;
    if (opacity == 0) {
      newOpacity = 1;
    } else {
      newOpacity = 0
    }
    d3.select("#line" + i).style("opacity", newOpacity);
    d3.selectAll(".blackDot" + i).style("opacity", newOpacity);
    d3.select("#ySecAxis" + i).style("opacity", newOpacity);
    d3.select("#yAxisLabel" + i).style("opacity", newOpacity);
  });

//************* Zoom & Brush***************
const margin2 = {
  left: 80,
  right: 0,
  top: 80,
  bottom: 0
};
const height2 = height - margin2.top - margin2.bottom;
var xZoom = d3.scaleLinear().range([0, width]);
var yZoom = d3.scaleLinear().range([height2, 0]);

var xAxis2 = d3.axisTop(xZoom);

var brush = d3.brushX()
  .extent([
    [0, 0],
    [width, height2]
  ])
  .on("brush end", brushed);

var zoom = d3.zoom()
  .scaleExtent([1, Infinity])
  .translateExtent([
    [0, 0],
    [width, height]
  ])
  .extent([
    [0, 0],
    [width, height]
  ])
  .on("zoom", zoomed);

var clip = svg.append("defs").append("svg:clipPath")
  .attr("id", "clip")
  .append("svg:rect")
  .attr("width", width)
  .attr("height", height)
  .attr("x", 0)
  .attr("y", 0);

xZoom.domain(x.domain());
yZoom.domain(y.domain());

var context = svg.append("g")
  .attr("class", "context")
  .attr("transform", "translate(" + margin2.left + "," + 125 + ")");

context.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", "translate(0," + height2 + ")")
  .call(xAxis2);

context.append("g")
  .attr("class", "brush")
  .call(brush)
  .call(brush.move, x.range());

function brushed() {
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return;
  var s = d3.event.selection || xZoom.range();
  x.domain(s.map(xZoom.invert, xZoom));
  svg.select(".x.axis").call(xAxis);
  //svg.select(".path0").attr("d", lineFunction1(data[0]));
  //svg.select(".path1").attr("d", lineFunction2(data[1]));
  for (var i = 0; i < 2; i++) {
    //svg.select(".path" + i).attr("d", lineFunction(data[i]));
    g.selectAll(".blackDot" + i)
      .attr("cx", function(d) {
        return x(d.x);
      })
      .attr("cy", function(d) {
        return yScale[i](d.y);
      })
      .attr("r", 3)
  }
}

function zoomed() {
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return;
  var t = d3.event.transform;
  x.domain(t.rescaleX(xZoom).domain());
  svg.select(".x.axis").transiton(t).call(xAxis);
  //svg.select(".path0").transiton(t).attr("d", lineFunction1(data[0]));
  //svg.select(".path1").transiton(t).attr("d", lineFunction2(data[1]));
  for (var i = 0; i < 2; i++) {
    //svg.select(".path" + i).attr("d", lineFunction(data[i]));
    g.selectAll(".blackDot" + i)
      .attr("cx", function(d) {
        return x(d.x);
      })
      .attr("cy", function(d) {
        return yScale[i](d.y);
      })
      .attr("r", 3)
  }
}
.xy_chart {
  position: relative;
  left: 70px;
  top: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg class="xy_chart"></svg>

円の1つに誤ったcyがあることに注意してくださいしたがって、yスケールのアプローチを変更することをお勧めします。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

折れ線グラフのy軸に複数のパンダ列をプロットする方法

分類Dev

2次y軸に複数の折れ線グラフを使用して複数の棒グラフをプロットする方法は?

分類Dev

python-同じY軸を持つ同じグラフに複数の線をプロットする

分類Dev

1つの図に複数の折れ線グラフをプロットする方法(オーバーレイ/グループ化)

分類Dev

2つのデータセットを持つ複数の折れ線グラフ

分類Dev

Billboarder.R、プロットする複数の変数を持つグループ化された折れ線グラフ

分類Dev

折れ線グラフのY軸に単一のDataFrameの2つの列をプロットする方法

分類Dev

highChartjsの折れ線グラフのY軸のタグに最後のデータポイント値を表示する方法

分類Dev

折れ線グラフの複数の線にドットをプロットする

分類Dev

通常のbarmode = 'group'の方法で、複数のy軸を持つ棒グラフをプロットします。

分類Dev

*高いy軸値*、複数の線、複数の軸を持つグラフのプロットにカーソルを合わせたときにラベルを表示する

分類Dev

チャートjsを使用して、1つのグラフに動的なx軸とy軸を持つ複数の折れ線グラフを作成するにはどうすればよいですか?

分類Dev

パンダの折れ線グラフに複数の列をプロットする

分類Dev

3つのデータセットを持つ折れ線グラフのMPAndroidChart複数のツールチップ/マーカービュー

分類Dev

Pythonで「複数線」の折れ線グラフをプロットする方法は?

分類Dev

特定の列を使用してSeabornで複数の折れ線グラフをプロットする方法は?

分類Dev

Chart.js->折れ線グラフ->同じXを持つ複数のポイント

分類Dev

複数の変数を持つグラフのExcelデータポイントを変更するにはどうすればよいですか?

分類Dev

C3グラフにロードする単一のポイントを持つ複数のX軸値がある場合のX軸スタイルの問題を克服する方法

分類Dev

データフレームとは別の軸に複数のグラフをプロットする

分類Dev

React-Nativeの折れ線グラフに2つのデータをプロットする方法

分類Dev

複数のインデックスを持つmongodbにデータをインポートする方法

分類Dev

x軸に月単位の時間、y軸に発生数を使用して、1つのグラフに複数の線をプロットします。

分類Dev

1つのグラフに複数のx、yデータのセットをプロットします

分類Dev

1つのプロットに同じx軸を持つ複数の系列(散布線)をプロットする

分類Dev

1つのグラフに複数のパンダデータフレームをプロットする

分類Dev

複数のパンダデータフレームを1つのグラフにプロットするpythonplotly

分類Dev

R光沢のあるggplot2リーフレット-折れ線グラフのX軸に複数のフィールドをプロットする方法

分類Dev

1つのx値に対して複数のy値を持つ折れ線グラフをplotlyでプロットするにはどうすればよいですか?

Related 関連記事

  1. 1

    折れ線グラフのy軸に複数のパンダ列をプロットする方法

  2. 2

    2次y軸に複数の折れ線グラフを使用して複数の棒グラフをプロットする方法は?

  3. 3

    python-同じY軸を持つ同じグラフに複数の線をプロットする

  4. 4

    1つの図に複数の折れ線グラフをプロットする方法(オーバーレイ/グループ化)

  5. 5

    2つのデータセットを持つ複数の折れ線グラフ

  6. 6

    Billboarder.R、プロットする複数の変数を持つグループ化された折れ線グラフ

  7. 7

    折れ線グラフのY軸に単一のDataFrameの2つの列をプロットする方法

  8. 8

    highChartjsの折れ線グラフのY軸のタグに最後のデータポイント値を表示する方法

  9. 9

    折れ線グラフの複数の線にドットをプロットする

  10. 10

    通常のbarmode = 'group'の方法で、複数のy軸を持つ棒グラフをプロットします。

  11. 11

    *高いy軸値*、複数の線、複数の軸を持つグラフのプロットにカーソルを合わせたときにラベルを表示する

  12. 12

    チャートjsを使用して、1つのグラフに動的なx軸とy軸を持つ複数の折れ線グラフを作成するにはどうすればよいですか?

  13. 13

    パンダの折れ線グラフに複数の列をプロットする

  14. 14

    3つのデータセットを持つ折れ線グラフのMPAndroidChart複数のツールチップ/マーカービュー

  15. 15

    Pythonで「複数線」の折れ線グラフをプロットする方法は?

  16. 16

    特定の列を使用してSeabornで複数の折れ線グラフをプロットする方法は?

  17. 17

    Chart.js->折れ線グラフ->同じXを持つ複数のポイント

  18. 18

    複数の変数を持つグラフのExcelデータポイントを変更するにはどうすればよいですか?

  19. 19

    C3グラフにロードする単一のポイントを持つ複数のX軸値がある場合のX軸スタイルの問題を克服する方法

  20. 20

    データフレームとは別の軸に複数のグラフをプロットする

  21. 21

    React-Nativeの折れ線グラフに2つのデータをプロットする方法

  22. 22

    複数のインデックスを持つmongodbにデータをインポートする方法

  23. 23

    x軸に月単位の時間、y軸に発生数を使用して、1つのグラフに複数の線をプロットします。

  24. 24

    1つのグラフに複数のx、yデータのセットをプロットします

  25. 25

    1つのプロットに同じx軸を持つ複数の系列(散布線)をプロットする

  26. 26

    1つのグラフに複数のパンダデータフレームをプロットする

  27. 27

    複数のパンダデータフレームを1つのグラフにプロットするpythonplotly

  28. 28

    R光沢のあるggplot2リーフレット-折れ線グラフのX軸に複数のフィールドをプロットする方法

  29. 29

    1つのx値に対して複数のy値を持つ折れ線グラフをplotlyでプロットするにはどうすればよいですか?

ホットタグ

アーカイブ