javascript 使用 D3.js 的 <circle> 属性 cx=“NaN” 的值无效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22846599/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Invalid value for <circle> attribute cx=“NaN” using D3.js
提问by Vanquiza
I'm trying to create a form of scatterplot. I have a custom x-axis and a specific scale for both a-axis. I have implemented a zoom functionality for it as well. So far everything is fine, but when I finally try to plot my data as circles I get two errors:
我正在尝试创建一种散点图形式。我有一个自定义的 x 轴和两个 a 轴的特定比例。我也为它实现了缩放功能。到目前为止一切都很好,但是当我最终尝试将数据绘制为圆圈时,出现两个错误:
.
.
My graph can be viewed on this website: http://servers.binf.ku.dk/hemaexplorerbeta/(the circles are huge, because I want to make sure I know approximately where they are before I style them)
我的图表可以在这个网站上查看:http: //servers.binf.ku.dk/hemaexplorerbeta/(圆圈很大,因为我想确保在我设计它们之前我知道它们大致在哪里)
I create my circles based on data read from a MYSQL server. I have checked all my data and the numbers are correct. They are either being plotting wrongly or my scales/zoom are faulty.
我根据从 MYSQL 服务器读取的数据创建我的圈子。我已经检查了我所有的数据并且数字是正确的。他们要么绘制错误,要么我的比例/缩放有问题。
Also you might notice I create my axis and scale with some values initially and change them in some functions right after. This is due to the fact that I'm planning on loading an empty graph on the website where the user can decide what dataset to load it, where the functions will have to customize both scales and axes to the data being loaded.
此外,您可能会注意到我最初创建了我的轴并使用一些值进行缩放,然后立即在某些函数中更改它们。这是因为我计划在网站上加载一个空图,用户可以在其中决定加载哪个数据集,函数必须在其中自定义要加载的数据的比例和轴。
I've pasted my source code below:
我在下面粘贴了我的源代码:
//Setting generic width and height values for our SVG.
var margin = {top: 60, right: 0, bottom: 70, left: 40},
genWidth = 1024;
genHeight = 768;
width = genWidth - 70 - margin.left - margin.right,
height = genHeight - 100 - margin.top - margin.bottom;
//Other variable declarations.
var valueY = 0;
var graphData = Array();
//Creating scales used to scale everything to the size of the SVG.
var xScale = d3.scale.linear()
.domain([0, genWidth])
.range([0, width-margin.right]);
var yScale = d3.scale.linear()
.domain([0, genHeight])
.range([height, margin.bottom]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//Zoom command ...
var zoom = d3.behavior.zoom()
.x(xScale)
.y(yScale)
.scaleExtent([1,10])
.on("zoom", zoomTargets);
// The mark '#' indicates an ID. IF '#' isn't included argument expected is a tag such as "svg" or "p" etc..
var SVG = d3.select("#mainSVG")
.attr("class", "SVG")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("pointer-events", "all")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//This creates a body with a clippath inside the svg where all element in the graph will be. This prevents elemnts on the graph to go past the axis.
var SVGbody = SVG.append("g")
.attr("clip-path", "url(#clip)")
.call(zoom);
//Create background. The mouse must be over an object on the graph for the zoom to work. The rectangle will cover the entire graph.
var rect = SVGbody.append("rect")
.attr("width", width)
.attr("height", height);
//Showing the axis that we created earlier in the script for both X and Y.
SVG.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", function(d) {
return "rotate(-30)"
});;
SVG.append("g")
.attr("class", "y axis")
.call(yAxis);
d3.json("getdata.php?type=load&gene=CCL5&data=human", function(error, data) {
var arrayValues = [];
if(error){ return console.log(error); }
data.forEach( function(d) {
arrayValues.push(d.gene_name);
valueY = getValueY(d.gene_data);
var string = JSON.stringify(d.gene_data);
graphData.push(string.split(" "));
});
//console.log(graphData);
arrayValues = removeDuplicatesInPlace(arrayValues);
updateScaleX(arrayValues.length);
updateAxisX(arrayValues);
//console.log(arrayValues);
updateScaleY(valueY);
//This selects 4 circles (non-existent, there requires data-binding) and appends them all below enter.
//The amount of numbers in data is the amount of circles to be appended in the enter() section.
for(var i = 0;i <= graphData.length;i++){
var circle = SVGbody
.selectAll("circle")
.data(graphData[i])
.enter()
.append("circle")
.attr("cx",function(d){return xScale((i*100)+100);})
.attr("cy",function(d){return yScale(d)})
.attr("r",20);
}
});
//Clipping is defined here used to prevent elements from the graph from going past the axis.
var clip = SVG.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr("width", width)
.attr("height", height);
//Resets zoom when click on circle object. Zoom work now, should be changed to a button instead of click on circle though.
SVG.selectAll("circle").on("click", function() {
zoom.scale(1);
zoom.translate([0,0]);
zoomTargets();
});
//The function handleling the zoom. Nothing is zoomed automatically, every elemnt must me defined here.
function zoomTargets() {
var translate = zoom.translate(),
scale = zoom.scale();
tx = Math.min(0, Math.max(width * (1 - scale), translate[0]));
ty = Math.min(0, Math.max(height * (1 - scale), translate[1]));
//This line applies the tx and ty which prevents the graphs from moving out of the limits. This means it can't be moved until zoomed in first.
zoom.translate([tx, ty]);
SVG.select(".x.axis").call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", function(d) {
return "rotate(-30)"
});
SVG.select(".y.axis").call(yAxis);
SVG.selectAll("circle").attr("cx",function(d){return xScale(d)}).attr("cy",function(d){return yScale(d)});
}
function resetZoom() {
zoom.scale(1);
zoom.translate([0,0]);
zoomTargets();
}
function updateAxisX(arr) {
var formatAxis = function(d, i) { return arr[i]; }
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickValues(createTickValuesArray(arr.length))
.tickFormat(formatAxis);
SVG.select(".x.axis")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", function(d) {
return "rotate(-30)"
});
}
function updateScaleX(newWidth){
genWidth = newWidth;
xScale = d3.scale.linear()
.domain([0, (newWidth*100)+50])
.range([0, width-margin.right]);
SVG.selectAll("circle").attr("cx",function(d){return xScale(d)}).attr("cy",function(d){return yScale(d)});
zoom.x(xScale);
}
function updateScaleY(newHeight){
console.log(newHeight);
var yScale = d3.scale.linear()
.domain([0, newHeight])
.range([height, margin.bottom]);
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
SVG.select(".y.axis").call(yAxis);
SVG.selectAll("circle").attr("cx",function(d){return xScale(d)}).attr("cy",function(d){return yScale(d)});
zoom.y(yScale);
}
function createTickValuesArray(amountOfTicks){
var tickValuesArr = [];
for(var i = 1;i<=amountOfTicks;i++){
tickValuesArr[i-1] = 100*i;
}
return tickValuesArr;
}
function getValueY(coordinates){
return d3.max(coordinates, Number);
}
//Custom functions used for specific uses.
var removeDuplicatesInPlace = function (arr) {
var i, j, cur, found;
for (i = arr.length - 1; i >= 0; i--) {
cur = arr[i];
found = false;
for (j = i - 1; !found && j >= 0; j--) {
if (cur === arr[j]) {
if (i !== j) {
arr.splice(i, 1);
}
found = true;
}
}
}
return arr;
};
采纳答案by Andreas
The first and last element of each array in graphData
cause errors when parsed as numbers because of an additional quote
For example the seventh array of graphData
looks like this:
graphData
由于附加引号,每个数组的第一个和最后一个元素在解析为数字时会导致错误
例如第七个数组graphData
如下所示:
console.log(graphData[6]) // [""5.149230", "4.965121""]
The cause of this seems to be the unnecessary JSON.stringfiy()
call when fetching the data
造成这种情况的原因似乎是JSON.stringfiy()
获取数据时不必要的调用
d3.json("getdata.php?type=load&gene=CCL5&data=human", function(error, data) {
var arrayValues = [];
if(error){ return console.log(error); }
data.forEach( function(d) {
arrayValues.push(d.gene_name);
valueY = getValueY(d.gene_data);
var string = JSON.stringify(d.gene_data); // <-- this one
graphData.push(string.split(" "));
});
d.gene_data
is already a string so it should work as expected, when you remove the JSON.stringify()
d.gene_data
已经是一个字符串,所以它应该按预期工作,当你删除 JSON.stringify()