我有一个d3.js问题,并且已经挣扎了一段时间,似乎无法解决它。我相信这很简单,但我遗漏了一些非常基本的东西。
具体来说,我有以下代码,它为JSON中的第一个条目生成一行和两个圆圈 - 我已为第一个条目“硬编码”。
我现在想将JSON文件的第2和第3个条目添加到图形中,并控制线条和圆形颜色,然后概括代码。
从阅读文档和StackOverflow,似乎正确的方法是使用嵌套,但我似乎无法使其工作?
代码位于以下网址的jsfiddle,javascript位于以下位置。
// INPUT
dataset2 =
[
{
movie : "test",
results :
[
{ week: "20130101", revenue: "60"},
{ week: "20130201", revenue: "80"}
]
},
{
movie : "beta",
results :
[
{ week: "20130101", revenue: "40"},
{ week: "20130201", revenue: "50"}
]
},
{
movie : "gamm",
results :
[
{ week: "20130101", revenue: "10"},
{ week: "20130201", revenue: "20"}
]
}
];
console.log("1");
var parseDate = d3.time.format("%Y%m%d").parse;
var lineFunction = d3.svg.line()
.x(function(d) { return xScale(parseDate(String(d.week))); })
.y(function(d) { return yScale(d.revenue); })
.interpolate("linear");
console.log("2");
//SVG Width and height
var w = 750;
var h = 250;
//X SCALE AND AXIS STUFF
//var xMin = 0;
//var xMax = 1000;
var xScale = d3.time.scale()
.domain([parseDate("20130101"),parseDate("20131231")])
.range([0, w]);
console.log(parseDate("20130101"));
console.log("3");
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
console.log("4S");
//Y SCALE AND AXIS STUFF
var yScale = d3.scale.linear()
.domain([0, 100])
.range([h, 0]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
console.log("4S1");
//CREATE X-AXIS
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - 30) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + 25 + ",0)")
.call(yAxis);
svg.selectAll("circle")
.data(dataset2[0].results)
.enter()
.append("circle")
.attr("cx", function(d) {
// console.log(d[0]);
console.log(parseDate(d.week));
return xScale(parseDate(d.week));
})
.attr("cy", function (d) {
return yScale(d.revenue);
})
.attr("r", 3);
//create line
var lineGraph = svg.append("path")
.attr("d", lineFunction(dataset2[0].results))
.attr("class", "line");
答案 0 :(得分:4)
“嵌套”一词出现在d3中的两个上下文中 - 使用d3.nest
创建嵌套数据数组,并使用嵌套数据创建嵌套选择。
您的数据已经采用了嵌套选择的正确格式 - 一个对象数组,每个对象都有一个单独数据点的子数组。因此,您无需担心操纵数据,只需要在嵌套的d3选择中直接将数据加入元素中:
我将尽快带您通过,但以下教程将成为未来的好参考:
在您的示例中:您有一个顶级数据结构,它是一个电影对象数组,每个数组都包含一个每周收入值的子数组。您需要确定的第一件事是您希望与每个数据级别关联的元素类型。您正在为子数组中的数据绘制一条线和一组圆,但当前没有为顶级数组对象(电影)添加任何内容。您需要为它们添加某些内容才能使嵌套选择生效,并且它需要包含您的直线和圆。在SVG中,这几乎总是一个<g>
(分组)元素。
为数据数组中的每个对象有效地创建一个<g>
元素 - 并将数据对象附加到元素以供将来参考 - 您创建一个空选择,加入您的数据,然后使用数据连接选择的enter()
方法为每个与元素不匹配的数据对象添加元素。在这种情况下,由于我们没有任何要启动的元素,因此所有数据对象都将在enter()
选择中。但是,更新某些数据时也可以使用相同的模式。
var movies = svg //start with your svg selection,
//it will become the parent to the entering <g> elements
.selectAll("g.movie") //select all <g> elements with class "movie"
//that are children of the <svg> element
//contained in the `svg` selection
//this selection will currently be empty
.data( dataset2 ); //join the selection to a data array
//each object in the array will be associated with
//an element in the selection, if those elements exist
//This data-joined selection is now saved as `movies`
movies.enter() //create a selection for the data objects that didn't match elements
.append("g") //add a new <g> element for each data object
.attr("class", "movie") //set it's class to match our selection criteria
//for each movie group, we're going to add *one* line (<path> element),
//and then a create subselection for the circles
.append("path") //add a <path> within *each* new movie <g> element
//the path will *inherit* the data from the <g> element
.attr("class", "line"); //set the class for your CSS
var lineGraph = movies.select("path.line")
//All the entered elements are now available within the movies selection
//(along with any existing elements that we were updating).
//Using select("path") selects the first (and only) path within the group
//regardless of whether we just created it or are updating it.
.attr("d", function(d){ return lineFunction(d.results); });
//the "d" attribute of a path describes its shape;
//the lineFunction creates a "d" definition based on a data array.
//If the data object attached to the path had *only* been the d.results array
//we could have just done .attr("d", lineFunction), since d3
//automatically passes the data object to any function given as the value
//of an .attr(name, value) command. Instead, we needed to create an
//anonymous function to accept the data object and extract the sub-array.
var circles = movies.selectAll("circle")
//there will be multiple circles for each movie group, so we need a
//sub-selection, created with `.selectAll`.
//again, this selection will initially be empty.
.data( function(d) {return d.results; });
//for the circles, we define the data as a function
//The function will be called once for each *movie* element,
//and passed the movie element's data object.
//The resulting array will be assigned to circles within that particular
//movie element (or to an `enter()` selection, if the circles don't exist).
circles.enter() //get the data objects that don't have matching <circle> elements
.append("circle") //create a circle for each
//the circles will be added to the appropriate "g.movie"
//because of the nested selection structure
.attr("r", 3); //the radius doesn't depend on the data,
//so you can set it here, when the circle is created,
//the same as you would set a class.
circles //for attributes that depend on the data, they are set on the entire
//selection (including updating elements), after having created the
//newly entered circles.
.attr("cx", function(d) { return xScale( parseDate(d.week) ); })
.attr("cy", function(d) { return yScale( d.revenue ); });
包含其余代码的实时版本:http://jsfiddle.net/GVmVk/3/
您需要调整x-scale的域名,以便不会切断第一个数据点,并且您需要决定如何使用您的电影标题属性,但这应该可以帮到您去。
答案 1 :(得分:3)
确实如此,nested selection是圈子的方式,虽然你不需要它们用于路径:
svg.selectAll("g.circle")
.data(dataset2)
.enter()
.append("g")
.attr("class", "circle")
.selectAll("circle")
.data(function(d) { return d.results; })
.enter()
.append("circle")
.attr("cx", function(d) {
// console.log(d[0]);
console.log(parseDate(d.week));
return xScale(parseDate(d.week));
})
.attr("cy", function (d) {
return yScale(d.revenue);
})
.attr("r", 3);
//create line
var lineGraph = svg.selectAll("path.line")
.data(dataset2).enter().append("path")
.attr("d", function(d) { return lineFunction(d.results); })
.attr("class", "line");
完整示例here。