我正在尝试在d3 js中对条形图和折线图进行分组,为此我跟踪了一个Link,
以下是我的Ajax返回的内容:
[
{
"date_created": "2017-12-27",
"jobs_fail": 19,
"jobs_resub": 31,
"jobs_success": 50
},
{
"date_created": "2017-12-29",
"jobs_fail": 18,
"jobs_resub": 25,
"jobs_success": 44
},
{
"date_created": "2017-12-28",
"jobs_fail": 8,
"jobs_resub": 24,
"jobs_success": 44
},
{
"date_created": "2018-01-02",
"jobs_fail": 2,
"jobs_resub": 0,
"jobs_success": 0
}
我想要展示的是将jobs_fail
和jobs_resub
显示为条形,将jobs_sucess
显示为相对于date_created
的相同图表中的折线图,
这是我的代码。
<script>
function get_data() {
console.log("create post is working!") // sanity check
return $.ajax({
url : "/group/guest/query/", // the endpoint
type : "GET", // http method
});
};
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10, "");
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var ajdata = get_data();
var k = [];
ajdata.success(function (data) {
var obj = jQuery.parseJSON(data);
alert(data);
var options = d3.keys(obj[0]).filter(function(key) { if (key != "date_created" & key != "jobs_success" ) { return key }}); // & key != "date_created"){return key} });
var line_option = d3.keys(obj[0]).filter(function(key) { if (key == "jobs_success" & key == "date_created"){return key} });
alert(options);
obj.forEach(function(d) {
d.valores = options.map(function(name) {return { name: name, value: +d[name]}; });});
x0.domain(obj.map(function(d) { return d.date_created; }));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(obj, function(d) { return d3.max(d.valores, function(d) { return d.value; }); })]);
var line = d3.svg.line()
.x(function(d) { return x1(d.date_created); })
.y(function(d) { return y(d.jobs_success); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number of jobs");
var bar = svg.selectAll(".bar")
.data(obj)
.enter().append("g")
.attr("class", "rect")
.attr("transform", function(d) { return "translate(" + x0(d.date_created) + ",0)"; });
bar.selectAll("rect")
.data(function(d) { return d.valores; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("value", function(d){return d.name;})
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
bar
.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX, y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
elementData = elements[l].__data__
divTooltip.html((d.date_created)+"<br>"+elementData.name+"<br>"+elementData.value);
});
bar
.on("mouseout", function(d){
divTooltip.style("display", "none");
});
var legend = svg.selectAll(".legend")
.data(options.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
svg.append("path")
//.data(obj)
.attr("class", "line")
.attr("d", line(obj));
更新
我面临的问题是我能够渲染条形而不是条形图上的折线图。
我正在尝试调试但不能这样做。
请告诉我这里可能出错的地方。
答案 0 :(得分:0)
你有一些小问题和一个大问题。
小问题是:
您的y
比例应考虑数据集中的最大值:
y.domain([0, d3.max(obj, function(d) {
return d.jobs_success
})]);
您的线路生成器应使用x0
。除此之外,你必须将这一行移动半个范围带:
.x(function(d) {
return x0(d.date_created) + x0.rangeBand() / 2;
})
默认情况下,<path>
有黑色填充。改变它:
.style("fill", "none")
data()
方法:
svg.append("path")
.data(obj)
.attr("class", "line")
.attr("d", line);
让我们详细了解这里发生了什么。您已将obj
数组传递给data()
。但是,如果这样做,该数组的每个元素将单独传递给行生成器。
所以,假设这是你的阵列......
["foo", "bar", "baz"]
...你传递给线路生成器的只是:
"foo".
这里有一些不同的解决方案。首先,您可以直接将数组传递给线生成器,就像在编辑中一样。其次,您可以将数组包装在外部数组中:
svg.append("path")
.data([obj])
.attr("class", "line")
.attr("d", line);
这样,整个obj
数组将传递给行生成器。
或者,第三,您可以使用datum
:
svg.append("path")
.datum(obj)
.attr("class", "line")
.attr("d", line);
以下是包含这些更改的代码,并使用datum
绘制路径:
var obj = [{
"date_created": "2017-12-27",
"jobs_fail": 19,
"jobs_resub": 31,
"jobs_success": 50
}, {
"date_created": "2017-12-29",
"jobs_fail": 18,
"jobs_resub": 25,
"jobs_success": 44
}, {
"date_created": "2017-12-28",
"jobs_fail": 8,
"jobs_resub": 24,
"jobs_success": 44
}, {
"date_created": "2018-01-02",
"jobs_fail": 2,
"jobs_resub": 0,
"jobs_success": 0
}];
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10, "");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var options = d3.keys(obj[0]).filter(function(key) {
if (key != "date_created" & key != "jobs_success") {
return key
}
}); // & key != "date_created"){return key} });
var line_option = d3.keys(obj[0]).filter(function(key) {
if (key == "jobs_success" & key == "date_created") {
return key
}
});
obj.forEach(function(d) {
d.valores = options.map(function(name) {
return {
name: name,
value: +d[name]
};
});
});
x0.domain(obj.map(function(d) {
return d.date_created;
}));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(obj, function(d) {
return d.jobs_success
})]);
var line = d3.svg.line()
.x(function(d) {
return x0(d.date_created) + x0.rangeBand() / 2;
})
.y(function(d) {
return y(d.jobs_success);
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number of jobs");
var bar = svg.selectAll(".bar")
.data(obj)
.enter().append("g")
.attr("class", "rect")
.attr("transform", function(d) {
return "translate(" + x0(d.date_created) + ",0)";
});
bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.name);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("value", function(d) {
return d.name;
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d) {
return color(d.name);
});
bar
.on("mousemove", function(d) {
divTooltip.style("left", d3.event.pageX + 10 + "px");
divTooltip.style("top", d3.event.pageY - 25 + "px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX,
y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l - 1
elementData = elements[l].__data__
divTooltip.html((d.date_created) + "<br>" + elementData.name + "<br>" + elementData.value);
});
bar
.on("mouseout", function(d) {
divTooltip.style("display", "none");
});
var legend = svg.selectAll(".legend")
.data(options.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
svg.append("path")
.datum(obj)
.attr("class", "line")
.attr("d", line)
.style("fill", "none")
.style("stroke", "red")
.style("stroke-width", 2);
&#13;
.axis line,
.axis path {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
&#13;
<script src="https://d3js.org/d3.v3.min.js"></script>
&#13;
答案 1 :(得分:-1)
好几件事。您的行的x
功能应该依赖于x0
而不是x1
:
var line = d3.svg.line()
.x(function(d) { return x0(d.date_created); })
.y(function(d) { return y(d.jobs_success); });
你的路径需要这样调用:
svg.append("path")
.attr("class", "line")
.attr("d", line(obj));
这应该可以帮助你完成大部分工作 - 你可能想要调整最大y值,并将线的x坐标移动x0.rangeBand()/2
以使其正确排列酒吧的中心。