Линейная шкала d3.js возвращает NaN - PullRequest
0 голосов
/ 28 июня 2018

Я пытаюсь построить свою первую визуализацию с помощью d3.js, и у меня есть проблема с масштабированием данных из источника JSON (myData). Вот как я масштабирую его и создаю круги SVG:

var myData = [{
  "x": "45.4969717",
  "y": "10.605375399999957"
}, {
  "x": "45.4847328802866",
  "y": "9.236798286437988"
}, {
  "x": "45.4838657",
  "y": "9.25125330000003"
}]

var xline = d3.scaleLinear().domain(45.103300, 40.1053737).range([0, 450.57913]);
var yline = d3.scaleLinear().domain(12.186311, 12.605783).range([0, 350]);
var svgViewport = d3.select("#mappa-italia").append("g").attr("id", "locations");
var circleElements = svgViewport.selectAll("circle").data(myData).enter().append("circle").attr("cx", function(d) {
  return xline(d.x);
}).attr("cy", function(d) {
  return yline(d.y);
}).attr("r", "5");
<script src="https://d3js.org/d3.v5.min.js"></script>

<svg id="mappa-italia"></svg>

Ошибка, возвращаемая консолью:

Error: <circle> attribute cx: Expected length, "NaN".

Error: <circle> attribute cy: Expected length, "NaN".

Я использую d3.js версии 5

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Не рекомендуется устанавливать домен, используя статические значения. Вот похожий пример того, что вы ищете:

https://bl.ocks.org/mbostock/3887118

Использование следующих изменений:

  1. Определение ширины, высоты, полей в качестве переменных.

    var margin = {top: 10, bottom: 10, left: 10, right: 10},
      width = 600-margin.left-margin.right,
      height = 400-margin.top-margin.bottom;
    
  2. Причиной возврата NaN по линейной шкале является то, что значения данных (x & y) являются строками, а не числами . Чтобы проанализировать данные, вот один из подходов:

    // parse data
    myData.forEach(function(d) {
     d.x = +d.x;
     d.y = +d.y;
    });
    
  3. Важный совет: избегайте использования статических значений при настройке доменов осей. Используйте манипуляции с массивом d3 - мин, макс, экстент . Я использую d3-экстент

    var xline = d3.scaleLinear().domain(d3.extent(myData, function(d) { return d.x; })).nice().range([0, width]);
    var yline = d3.scaleLinear().domain(d3.extent(myData, function(d) { return d.y; })).nice().range([height, 0]);
    
  4. Поскольку данные теперь анализируются (2-й шаг), линейная шкала не будет иметь проблем с отображением значений.

    var circleElements = svgViewport.selectAll("circle").data(myData).enter().append("circle").attr("cx", function(d) {
      return xline(d.x);
    }).attr("cy", function(d) {
      return yline(d.y);
    })
    

Просто для эстетики я использую цветовую шкалу, чтобы добавить цвета к кружкам:

var colorScale = d3.scaleOrdinal(d3.schemeCategory10);

Вот фрагмент кода:

  var myData = [{
    "x": "45.4969717",
    "y": "10.605375399999957"
  }, {
    "x": "45.4847328802866",
    "y": "9.236798286437988"
  }, {
    "x": "42.4838657",
    "y": "9.25125330000003",
  }, {
    "x": "40.1053737",
    "y": "12"
  }, {
  	"x": "42.4",
    "y": "10.4"
  }];
  
  var margin = {top: 10, bottom: 10, left: 10, right: 10},
 		  width = 450.57913-margin.left-margin.right,
  		height = 350-margin.top-margin.bottom;
  
  
// parse data
myData.forEach(function(d) {
	d.x = +d.x;
  d.y = +d.y;
});

  var xline = d3.scaleLinear().domain(d3.extent(myData, function(d) { return d.x; })).nice().range([0, width]);
  var yline = d3.scaleLinear().domain(d3.extent(myData, function(d) { return d.y; })).nice().range([height, 0]);
  
  var colorScale = d3.scaleOrdinal(d3.schemeCategory10);
  
  var svgViewport = d3.select("#mappa-italia")
  			.attr('width', width+margin.left+margin.right)
        .attr('height', height+margin.top+margin.bottom)
        .append("g")
        .attr('transform', 'translate('+margin.left+', ' + margin.top+')')
        .attr("id", "locations");
  var circleElements = svgViewport.selectAll("circle").data(myData).enter().append("circle").attr("cx", function(d) {
    return xline(d.x);
  }).attr("cy", function(d) {
    return yline(d.y);
  }).attr("r", "5").style('fill', function(d, i) {
		return colorScale(i);
  });
<script src="https://d3js.org/d3.v5.min.js"></script>


<svg id="mappa-italia"></svg>

Надеюсь, это поможет. (Кстати, я добавил пару дополнительных строк в данные)

0 голосов
/ 28 июня 2018

Домен должен быть массивом так:

var xline = d3.scaleLinear().domain([45.103300,40.1053737]).range([0,450.57913]);
var yline = d3.scaleLinear().domain([12.186311,12.605783]).range([0,350]);
...