[英]how to create dots(scatterplot) on a line in a d3 line chart
我的代碼工作正常,但該行的第一個點有問題。 第一個點始終位於y = 2和x = 1的位置,但其他點的放置正確。 請幫助我將第一個點放置在正確的位置。
圖的JSON數據:-
var data = [{
"label": "Execution: 6 - defadmin@gmail.com",
"x": [1, 2, 3, 4, 5, 6],
"y": [2, 1, 1, 1, 1, 1],
"xAxisDisplayData": ["1", "2", "3", "4", "5", "6"]
}];
這是我關於點創建的代碼,
// Set the ranges
var x = d3.time.scale().range([0, innerwidth]);
var y = d3.scale.linear().range([innerheight, 0]);
// Scale the range of the data
x.domain(d3.extent(datasets[0]['x'], function (d, i) {
return datasets[0]['x'][i];
}));
y.domain([1, d3.max(datasets[0]['y'], function (d, i) {
return datasets[0]['y'][i];
})]);
// Add the scatterplot
svg.selectAll("dot")
.data(datasets[0]['x'])
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function (d, i) {
return x(datasets[0]['x'][i]);
})
.attr("cy", function (d, i) {
return y(datasets[0]['y'][i]);
});
更新1:完整代碼
function createLineChart(data, number) {
// var data = [ { label: "Execution 1 - buddhika@gmail.com",
// x: [1,2,3,4,5,6],
// y: [2,1,1,1,1,1] }] ;
var widthForSVG;
var widthForChart;
if ((data[0]['x']).length < 13) {
widthForSVG = 1220;
widthForChart = 960;
} else {
widthForSVG = (((data[0]['x']).length - 12) * 80) + 1220;
widthForChart = (((data[0]['x']).length - 12) * 80) + 960;
}
var xy_chart = d3_xy_chart()
.width(widthForChart)
.height(500)
.xlabel("TCS")
.ylabel("STATUS");
// creating main svg
var svg = d3.select(".lineChartDiv" + number).append("svg")
.datum(data)
.call(xy_chart)
.attr("class", "lineChart" + number)
.attr('width', widthForSVG);
function d3_xy_chart() {
//1220px for 12 steps in svg
var width = widthForChart,
height = 480,
xlabel = "X Axis Label",
ylabel = "Y Axis Label";
function chart(selection, svg) {
var numberNUmber = 0;
selection.each(function (datasets) {
//
// Create the plot.
//
var margin = {top: 20, right: 80, bottom: 30, left: 50},
innerwidth = width - margin.left - margin.right,
innerheight = height - margin.top - margin.bottom;
// Set the ranges
var x_scale = d3.scale.linear()
.range([0, innerwidth])
.domain([d3.min(datasets, function (d) {
return d3.min(d.x);
}),
d3.max(datasets, function (d) {
return d3.max(d.x);
})]);
var y_scale = d3.scale.linear()
.range([innerheight, 0])
.domain([d3.min(datasets, function (d) {
return 1;
}),
d3.max(datasets, function (d) {
// d3.max(d.y)
return 3;
})]);
var color_scale = d3.scale.category10()
.domain(d3.range(datasets.length));
var x_axis = d3.svg.axis()
.scale(x_scale)
.orient("bottom")
.tickFormat(function (d, i) {
if (d % 1 == 0) {
return parseInt(datasets[0]['xAxisDisplayData'][i])
} else {
return " "
}
})
.ticks(d3.max(datasets, function (d) {
return d3.max(d.x);
}));
var y_axis = d3.svg.axis()
.scale(y_scale)
.orient("left")
.ticks(d3.max(datasets, function (d) {
return d3.max(d.y);
}))
.tickFormat(function (d, i) {
if (d == "1") {
return "NOT EXECUTED"
} else if (d == "2") {
return "FAILED"
} else if (d == "3") {
return "PASSED"
} else {
return " "
}
});
var x_grid = d3.svg.axis()
.scale(x_scale)
.orient("bottom")
.tickSize(-innerheight)
.ticks(d3.max(datasets, function (d) {
// d3.max(d.y)
return d3.max(d.x);
}))
.tickFormat("");
var y_grid = d3.svg.axis()
.scale(y_scale)
.orient("left")
.tickSize(-innerwidth)
.tickFormat("")
.ticks(d3.max(datasets, function (d) {
return d3.max(d.y);
}));
var draw_line = d3.svg.line()
.interpolate("linear")
.x(function (d) {
return x_scale(d[0]);
})
.y(function (d) {
return y_scale(d[1]);
});
var svg = d3.select(this)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 90 + "," + margin.top + ")");
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + innerheight + ")")
.call(x_grid);
svg.append("g")
.attr("class", "y grid")
.call(y_grid);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + innerheight + ")")
.call(x_axis)
.append("text")
.attr("dy", "-.71em")
.attr("x", innerwidth)
.style("text-anchor", "end")
.text(xlabel);
svg.append("g")
.attr("class", "y axis")
.call(y_axis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.style("text-anchor", "end")
.text(ylabel);
var data_lines = svg.selectAll(".d3_xy_chart_line")
.data(datasets.map(function (d) {
return d3.zip(d.x, d.y);
}))
.enter().append("g")
.attr("class", "d3_xy_chart_line");
data_lines.append("path")
.attr("class", "line")
.attr("d", function (d) {
return draw_line(d);
})
.attr("stroke", function (_, i) {
return color_scale(i);
});
data_lines.append("text")
.datum(function (d, i) {
return {name: datasets[i].label, final: d[d.length - 1]};
})
.attr("transform", function (d) {
return ( "translate(" + x_scale(d.final[0]) + "," +
y_scale(d.final[1]) + ")" );
})
.attr("x", 3)
.attr("dy", ".35em")
.attr("fill", function (_, i) {
return color_scale(i);
})
.text(function (d) {
return d.name;
});
// Set the ranges
var x = d3.time.scale().range([0, innerwidth]);
var y = d3.scale.linear().range([innerheight, 0]);
// Scale the range of the data
x.domain(d3.extent(datasets[0]['x']));
y.domain([1, d3.max(datasets[0]['y'])]);
svg.selectAll("dot")
.data(d3.zip(datasets[0].x, datasets[0].y))
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function (d) {
return x(d[0]);
})
.attr("cy", function (d) {
return y(d[1]);
});
});
}
chart.width = function (value) {
if (!arguments.length) return width;
width = value;
return chart;
};
chart.height = function (value) {
if (!arguments.length) return height;
height = value;
return chart;
};
chart.xlabel = function (value) {
if (!arguments.length) return xlabel;
xlabel = value;
return chart;
};
chart.ylabel = function (value) {
if (!arguments.length) return ylabel;
ylabel = value;
return chart;
};
return chart;
}
}
更新2:
創建的圓的html視圖(檢查第一個圓,它始終具有cx = 0和cy = 0坐標,其他圓都可以)
更新3:聯邦
您對d3.extent()
和d3.max()
的使用存在缺陷。 這些方法提供的功能僅僅是訪問器; 實際迭代沒有參數i
。 它們是實際訪問數組的相關數據的一種手段,該數據作為第一個參數傳入。 因為您已經在傳遞平面數據數組,所以兩個訪問器函數都可以簡化為function (d) { return d; }
function (d) { return d; }
。 這些可能會進一步省略,因為這是默認行為。 這樣,您的域設置將變為:
// Scale the range of the data
x.domain(d3.extent(datasets[0]['x']));
y.domain([1, d3.max(datasets[0]['y'])]);
就個人而言,我還將重寫您的數據綁定邏輯以提高可讀性:
// Add the scatterplot
svg.selectAll("dot")
.data(d3.zip(datasets[0].x, datasets[0].y))
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function (d) {
return x(d[0]);
})
.attr("cy", function (d) {
return y(d[1]);
});
不需要每次都需要這些值時對datasets
數組進行繁瑣的深度訪問,而是使用d3.zip()
構建包含點坐標的新數組數組,然后將其綁定到選擇。 如您所見,這將為您提供用於設置cx
和cy
屬性值的簡潔代碼。
除了這些技術缺陷存在設置你的邏輯故障y
規模的領域,如由安德魯表示意見 - ,你在哪里做
y.domain([1, d3.max(datasets[0]['y'])]);
但是,在數據集中,您提供的y的最大值為2。 這樣,您的域將被設置為[1, 2]
而不包含3
。 因此,使用該域將在原點繪制點。 因為您的y值是類別,所以顯然這不是您想要的。 要始終繪制所有類別的類別,可以使用靜態值來設置比例尺的域:
y.domain([1, 3]);
對於其他比例尺y_scale
,您已經以這種方式(但是相當尷尬)進行了此y_scale
,這就是正確繪制線條的原因。
當然,您也可以決定只繪制數據集中包含的類別,在這種情況下,您應將d3.max()
保留在域中,但隨后還必須對y_scale
的域進行相同的操作。
請看下面的示例片段。 它包含來自JSFiddle的代碼,只更改了一行,並在其中設置了y
標度的域。
var data = [{ "label": "Execution: 6 - defadmin@gmail.com", "x": [1, 2, 3, 4, 5, 6], "y": [2, 1, 1, 1, 1, 1], "xAxisDisplayData": ["1", "2", "3", "4", "5", "6"] }]; var number = 1; var widthForSVG; var widthForChart; if ((data[0]['x']).length < 13) { widthForSVG = 1220; widthForChart = 960; } else { widthForSVG = (((data[0]['x']).length - 12) * 80) + 1220; widthForChart = (((data[0]['x']).length - 12) * 80) + 960; } var xy_chart = d3_xy_chart() .width(widthForChart) .height(500) .xlabel("TCS") .ylabel("STATUS"); // creating main svg var svg = d3.select(".lineChartDiv1").append("svg") .datum(data) .call(xy_chart) .attr("class", "lineChartDiv1") .attr('width', widthForSVG); function d3_xy_chart() { var width = widthForChart, height = 480, xlabel = "X Axis Label", ylabel = "Y Axis Label"; function chart(selection, svg) { var numberNUmber = 0; selection.each(function(datasets) { // // Create the plot. // var margin = { top: 20, right: 80, bottom: 30, left: 50 }, innerwidth = width - margin.left - margin.right, innerheight = height - margin.top - margin.bottom; // Set the ranges var x_scale = d3.scale.linear() .range([0, innerwidth]) .domain([d3.min(datasets, function(d) { return d3.min(dx); }), d3.max(datasets, function(d) { return d3.max(dx); }) ]); var y_scale = d3.scale.linear() .range([innerheight, 0]) .domain([d3.min(datasets, function(d) { return 1; }), d3.max(datasets, function(d) { // d3.max(dy) return 3; }) ]); var color_scale = d3.scale.category10() .domain(d3.range(datasets.length)); var x_axis = d3.svg.axis() .scale(x_scale) .orient("bottom") .tickFormat(function(d, i) { if (d % 1 == 0) { return parseInt(datasets[0]['xAxisDisplayData'][i]) } else { return " " } }) .ticks(d3.max(datasets, function(d) { return d3.max(dx); })); var y_axis = d3.svg.axis() .scale(y_scale) .orient("left") .ticks(d3.max(datasets, function(d) { return d3.max(dy); })) .tickFormat(function(d, i) { if (d == "1") { return "NOT EXECUTED" } else if (d == "2") { return "FAILED" } else if (d == "3") { return "PASSED" } else { return " " } }); var x_grid = d3.svg.axis() .scale(x_scale) .orient("bottom") .tickSize(-innerheight) .ticks(d3.max(datasets, function(d) { // d3.max(dy) return d3.max(dx); })) .tickFormat(""); var y_grid = d3.svg.axis() .scale(y_scale) .orient("left") .tickSize(-innerwidth) .tickFormat("") .ticks(d3.max(datasets, function(d) { return d3.max(dy); })); var draw_line = d3.svg.line() .interpolate("linear") .x(function(d) { return x_scale(d[0]); }) .y(function(d) { return y_scale(d[1]); }); var svg = d3.select(this) .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + 90 + "," + margin.top + ")"); svg.append("g") .attr("class", "x grid") .attr("transform", "translate(0," + innerheight + ")") .call(x_grid); svg.append("g") .attr("class", "y grid") .call(y_grid); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + innerheight + ")") .call(x_axis) .append("text") .attr("dy", "-.71em") .attr("x", innerwidth) .style("text-anchor", "end") .text(xlabel); svg.append("g") .attr("class", "y axis") .call(y_axis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", "0.71em") .style("text-anchor", "end") .text(ylabel); var data_lines = svg.selectAll(".d3_xy_chart_line") .data(datasets.map(function(d) { return d3.zip(dx, dy); })) .enter().append("g") .attr("class", "d3_xy_chart_line"); data_lines.append("path") .attr("class", "line") .attr("d", function(d) { return draw_line(d); }) .attr("stroke", function(_, i) { return color_scale(i); }); data_lines.append("text") .datum(function(d, i) { return { name: datasets[i].label, final: d[d.length - 1] }; }) .attr("transform", function(d) { return ("translate(" + x_scale(d.final[0]) + "," + y_scale(d.final[1]) + ")"); }) .attr("x", 3) .attr("dy", ".35em") .attr("fill", function(_, i) { return color_scale(i); }) .text(function(d) { return d.name; }); // Set the ranges var x = d3.time.scale().range([0, innerwidth]); var y = d3.scale.linear().range([innerheight, 0]); // Scale the range of the data x.domain(d3.extent(datasets[0]['x'])); y.domain([1, 3]); // console.log(JSON.stringify(d3.extent(datasets[0]['x']))) // console.log(JSON.stringify(d3.max(datasets[0]['y']))) // Add the scatterplot svg.selectAll("dot") .data(d3.zip(datasets[0].x, datasets[0].y)) .enter().append("circle") .attr("class", datasets[0]['label']) .attr("r", 3.5) .attr("cx", function(d) { // console.log(JSON.stringify(d[0])+" XXXXXXXXXXx ") return x(d[0]); }) .attr("cy", function(d) { //console.log(JSON.stringify(d[1])+" YYYYYYYyy ") return y(d[1]); }); }); } chart.width = function(value) { if (!arguments.length) return width; width = value; return chart; }; chart.height = function(value) { if (!arguments.length) return height; height = value; return chart; }; chart.xlabel = function(value) { if (!arguments.length) return xlabel; xlabel = value; return chart; }; chart.ylabel = function(value) { if (!arguments.length) return ylabel; ylabel = value; return chart; }; return chart; }
.axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .grid path, .grid line { fill: none; stroke: rgba(0, 0, 0, 0.25); shape-rendering: crispEdges; } .x.axis path { display: none; } .line { fill: none; stroke-width: 2.5px; } svg { font: 10px sans-serif; } .area { fill: lightgray; clip-path: url(#clip); } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .brush .extent { stroke: #fff; fill-opacity: .125; shape-rendering: crispEdges; clip-path: url(#clip); } rect.pane { cursor: move; fill: none; pointer-events: all; }
<script src="https://d3js.org/d3.v3.js"></script> <div class="row"> <div class="col-sm-12"> <div class="lineChartDiv1" style=" overflow-x: scroll"> </div> </div> </div>
嘗試這個,
if(data[0]['y'][1]==1){
document.getElementsByClassName(data[0]['label'])[0].setAttribute('cx','0');
document.getElementsByClassName(data[0]['label'])[0].setAttribute('cy','225');
}else if(data[0]['y'][1]==2){
document.getElementsByClassName(data[0]['label'])[0].setAttribute('cx','0');
document.getElementsByClassName(data[0]['label'])[0].setAttribute('cy','450');
}else{
document.getElementsByClassName(data[0]['label'])[0].setAttribute('cx','0');
document.getElementsByClassName(data[0]['label'])[0].setAttribute('cy','0');
}
嘿我(Buddhika)通過以下方式改進了您的代碼,否則它是無用的:
var element = document.getElementsByClassName(data[0]['label']);
for (var i =0; i<element.length; i++){
if(data[0]['y'][0]==1 & data[0]['x'][i]==0){
document.getElementsByClassName(data[0]['label'])[i].setAttribute('cy','450');
}else if(data[0]['y'][0]==2 & data[0]['x'][i]==0){
document.getElementsByClassName(data[0]['label'])[i].setAttribute('cy','225');
}else if(data[0]['y'][0]==3 & data[0]['x'][i]==0){
document.getElementsByClassName(data[0]['label'])[i].setAttribute('cy','0');
}else if(data[0]['y'][i]==1){
document.getElementsByClassName(data[0]['label'])[i].setAttribute('cy','450');
}else if(data[0]['y'][i]==2){
document.getElementsByClassName(data[0]['label'])[i].setAttribute('cy','225');
}else if(data[0]['y'][i]==3){
document.getElementsByClassName(data[0]['label'])[i].setAttribute('cy','0');
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.