繁体   English   中英

使用d3.js的多个圆圈/线条

[英]multiple circles / lines using d3.js

我有一个d3.js问题,已经为此苦苦挣扎了一段时间,似乎无法解决。 我相信这很容易,但是缺少一些非常基本的东西。

具体来说,我有以下代码,它为JSON中的第一个条目生成了一行和两个圆圈-我为第一个条目进行了“硬编码”。

现在,我想将JSON文件的第2和第3项添加到图形中,并控制线条和圆圈的颜色,然后概括代码。

通过阅读文档和StackOverflow,似乎正确的方法是使用嵌套,但是我似乎无法使其正常工作?

代码在jsfiddle上的以下URL上,而javascript在下面。

http://jsfiddle.net/GVmVk/

        // 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");

在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比例尺的域,以便不截断第一个数据点,并且需要确定如何使用电影标题属性,但这应该可以帮助您。

是的,的确, 嵌套选择是进行圆的一种方法,尽管路径不需要它们:

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");

这里完整的例子。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM