简体   繁体   中英

How to find coordinates to put circle on polar scatterplot using d3

I want to draw a polar scatterplot chart with d3,but having a hard time putting dots on the correct coordinates. I find this as an example .

One thing I'm not very clear in the example above the "+ Math.PI / 2" part while drawing the radial line.

    var line = d3.svg.line.radial()
    .radius(function(d) {
      return r(d[1]);
    })
    .angle(function(d) {
      return -d[0] + Math.PI / 2;
    });

& Here is what I have so far on

  var width = 1200, height = 700, radius = Math.min(width, height) / 2 - 30; //radius var r = d3.scale.linear() .range([0, radius]); //Line var l = d3.scale.linear() .range([0, 360]); //point var c = d3.scale.linear() .range([0, 15]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var data = [ {'Name':'A','Birth':1700, 'Point':20, 'size':120}, {'Name':'B','Birth':1696, 'Point':45,'size':30}, {'Name':'C','Birth':1660, 'Point':89, 'size':50}, {'Name':'D','Birth':1784, 'Point':12, 'size':80}, {'Name':'E','Birth':1793, 'Point':33, 'size':150}, {'Name':'F','Birth':1750, 'Point':56, 'size':67}, {'Name':'G','Birth':1738, 'Point':62, 'size':25}, {'Name':'H','Birth':1813, 'Point':87, 'size':83}, {'Name':'I','Birth':1723, 'Point':76, 'size':100}, {'Name':'J','Birth':1786, 'Point':53, 'size':90} ] var youngest = d3.min(data, function(d) { return d.Birth; }); var oldest = d3.max(data, function(d) { return d.Birth; }); l.domain([Number(youngest), Number(oldest)]); r.domain([0, d3.max(data, function(d) { return d.Point; })]); c.domain([0, d3.max(data, function(d) { return d.size; })]); var line = d3.svg.line.radial() .radius(function(d) { return r(d[1]); }) .angle(function(d) { return l(d[0]) + Math.PI / 2; } ); var gr = svg.append("g") .attr("class", "r axis") .selectAll("g") .data(r.ticks(5).slice(1)) .enter().append("g"); gr.append("circle") .attr("r", r); gr.append("text") .attr("y", function(d) { return -r(d) - 4; }) .attr("transform", "rotate(15)") .style("text-anchor", "middle") .text(function(d) { return d+'%'; }); var ga = svg.append("g") .attr("class", "a axis") .selectAll("g") .data(l.ticks(12).slice(0,-1)) .enter().append("g") .attr("transform", function(d) { return "rotate(" + (l(d)) + ")"; }); ga.append("line") .attr("x2", radius); ga.append("text") .attr("x", radius + 6) .attr("dy", ".35em") .style("text-anchor", function(d) { return l(d) < 270 && l(d) > 90 ? "end" : null; }) .attr("transform", function(d) { return l(d) < 270 && l(d) > 90 ? "rotate(180 " + (radius + 6) + ",0)" : null; }) .text(function(d) { return d; }); var color = d3.scale.category20(); var gc = svg.append("g") .attr("class", "circles") gc.selectAll("g") .data(data) .enter() .append("g") .attr("class", "cpoint") .append("circle") .attr("class", "point") .attr("transform", function(d) { let c = [Number(d.Birth), d.Point] var coors = line([c]).slice(1).slice(0, -1); return "translate(" + coors + ")" }) .attr("r", function(d){ return c(d.size); }) .attr("fill",function(d,i){ return color(i); }); gc.selectAll(".cpoint") .append("text") .attr("text-anchor", "middle") .attr("transform", function(d) { let c = [Number(d.Birth), d.Point] var coors = line([c]).slice(1).slice(0, -1); return "translate(" + coors + ")" }) .text(function(d) { return d.Name + ' ' + d.Point + '%' + ' ' + d.Birth; }) .style("font-size", '13px'); 
 .frame { fill: none; stroke: #000; } .axis text { font: 10px sans-serif; } .axis line, .axis circle { fill: none; stroke: #777; stroke-dasharray: 1,4; } .axis :last-of-type circle { stroke: #333; stroke-dasharray: none; } .line { fill: none; stroke: orange; stroke-width: 1.5px; } 
 <script src="https://d3js.org/d3.v3.min.js"></script> <p>Polar Scatterplot</p> 

Somehow the dot is on the correct radius (%), but the angle(year) doesn't seem to be right. I also tried just using cx and cy to place the dot instead of transform, but unfortunately it returns the same result.

I answered that previous question. In your case, you are missing that the "x" variable you feed to line is supposed to be an angle (in radians). You are giving it a "year".

Regardless, in your case I'd code this differently. Here's the proper transform with some basic trigonometry:

.attr("transform", function(d){
    // get angle and radius
    var an = l(d.Birth),
        ra = r(d.Point),
        // calc x, y position
        x = ra * Math.cos(an * Math.PI/180),
        y = ra * Math.sin(an * Math.PI/180);
    return "translate(" + [x,y] + ")";
  })

Also note, that I would just position the g and add the circle and text to it. Not, position the two elements separately.

Running code:

 <!DOCTYPE html> <html> <head> <style> .frame { fill: none; stroke: #000; } .axis text { font: 10px sans-serif; } .axis line, .axis circle { fill: none; stroke: #777; stroke-dasharray: 1, 4; } .axis:last-of-type circle { stroke: #333; stroke-dasharray: none; } .line { fill: none; stroke: orange; stroke-width: 1.5px; } </style> </head> <body> <script src="https://d3js.org/d3.v3.min.js"></script> <script> var width = 1200, height = 700, radius = Math.min(width, height) / 2 - 30; //radius var r = d3.scale.linear() .range([0, radius]); //Line var l = d3.scale.linear() .range([0, 360]); //point var c = d3.scale.linear() .range([0, 15]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var data = [{ 'Name': 'A', 'Birth': 1700, 'Point': 20, 'size': 120 }, { 'Name': 'B', 'Birth': 1696, 'Point': 45, 'size': 30 }, { 'Name': 'C', 'Birth': 1660, 'Point': 89, 'size': 50 }, { 'Name': 'D', 'Birth': 1784, 'Point': 12, 'size': 80 }, { 'Name': 'E', 'Birth': 1793, 'Point': 33, 'size': 150 }, { 'Name': 'F', 'Birth': 1750, 'Point': 56, 'size': 67 }, { 'Name': 'G', 'Birth': 1738, 'Point': 62, 'size': 25 }, { 'Name': 'H', 'Birth': 1813, 'Point': 87, 'size': 83 }, { 'Name': 'I', 'Birth': 1723, 'Point': 76, 'size': 100 }, { 'Name': 'J', 'Birth': 1786, 'Point': 53, 'size': 90 }] var youngest = d3.min(data, function(d) { return d.Birth; }); var oldest = d3.max(data, function(d) { return d.Birth; }); l.domain([Number(youngest), Number(oldest)]); r.domain([0, d3.max(data, function(d) { return d.Point; })]); c.domain([0, d3.max(data, function(d) { return d.size; })]); var line = d3.svg.line.radial() .radius(function(d) { return r(d[1]); }) .angle(function(d) { return l(d[0]) + Math.PI / 2; }); var gr = svg.append("g") .attr("class", "r axis") .selectAll("g") .data(r.ticks(5).slice(1)) .enter().append("g"); gr.append("circle") .attr("r", r); gr.append("text") .attr("y", function(d) { return -r(d) - 4; }) .attr("transform", "rotate(15)") .style("text-anchor", "middle") .text(function(d) { return d + '%'; }); var ga = svg.append("g") .attr("class", "a axis") .selectAll("g") .data(l.ticks(12).slice(0, -1)) .enter().append("g") .attr("transform", function(d) { return "rotate(" + (l(d)) + ")"; }); ga.append("line") .attr("x2", radius); ga.append("text") .attr("x", radius + 6) .attr("dy", ".35em") .style("text-anchor", function(d) { return l(d) < 270 && l(d) > 90 ? "end" : null; }) .attr("transform", function(d) { return l(d) < 270 && l(d) > 90 ? "rotate(180 " + (radius + 6) + ",0)" : null; }) .text(function(d) { return d; }); var color = d3.scale.category20(); var gc = svg.append("g") .attr("class", "circles") gc.selectAll("g") .data(data) .enter() .append("g") .attr("class", "cpoint") .attr("transform", function(d) { // get angle and radius var an = l(d.Birth), ra = r(d.Point), x = ra * Math.cos(an * Math.PI / 180), y = ra * Math.sin(an * Math.PI / 180); return "translate(" + [x, y] + ")"; }) .append("circle") .attr("class", "point") .attr("r", function(d) { return c(d.size); }) .attr("fill", function(d, i) { return color(i); }); gc.selectAll(".cpoint") .append("text") .attr("text-anchor", "middle") .text(function(d) { return d.Name + ' ' + d.Point + '%' + ' ' + d.Birth; }) .style("font-size", '13px'); </script> </body> </html> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM