我正在尝试创建一种散点图形式.我有一个自定义的x轴和两个a轴的特定比例.我也为它实现了缩放功能.到目前为止一切都很好,但是当我最终尝试将数据绘制为圆圈时,我得到两个错误:
.
我的图表可以在这个网站上查看:http://servers.binf.ku.dk/hemaexplorerbeta/
(圈子很大,因为我想确保在我设计它们之前大致知道它们的位置)
我根据从MysqL服务器读取的数据创建我的圈子.我检查了所有数据,数字是正确的.他们要么错误地绘图,要么我的刻度/缩放有问题.
您也可能会注意到我创建了我的轴并最初使用某些值进行缩放,并在之后的某些函数中更改它们.这是因为我计划在网站上加载一个空图表,用户可以决定加载它的数据集,其中函数必须自定义要加载的数据的比例和轴.
我在下面粘贴了我的源代码:
//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",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",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",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 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 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; };
解决方法
由于附加引用,graphData中每个数组的第一个和最后一个元素在解析为数字时会导致错误
例如,第七个graphData数组如下所示:
例如,第七个graphData数组如下所示:
console.log(graphData[6]) // [""5.149230","4.965121""]
造成这种情况的原因似乎是在获取数据时不必要的JSON.stringfiy()调用
d3.json("getdata.PHP?type=load&gene=CCL5&data=human",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已经是一个字符串,所以当你删除JSON.stringify()时它应该按预期工作