D3js - 为文件中的多个数据类别重用行定义/函数

时间:2013-04-26 17:52:07

标签: javascript d3.js data-visualization

所以,我一直在使用R& ggplot2取得良好进展并分享我们的数据分析结果。但是,我们想要更具互动性的东西。我们使用过Highcharts.js,但它在许多数据点的重压下破解,并且在定制方面不是很灵活。所以,我过去曾经和protovis玩过一段时间,但现在我想让D3工作。

我的两个关键问题如下:

  • 如何通过传入指向数据集 part 的指针来重用行定义
  • 工具提示(取得了一些进展,我会跟进另一篇文章,除非有人在这里看到明显的答案)

在下面的代码中,我高举了行声明,然后调用这些函数添加到svg&样式。

我正在寻找的是帮助弄清楚如何将参数传递给line函数以指定要添加到给定行的数据元素。我可能需要以不同的方式格式化数据,如果这是最好的解决方案,这是完全可能的。

感谢任何输入!

----------------的更新 ----------------

此处需要帮助:

        // MPGL
    var line1 = d3.svg.line()
        .x(function(d,i) {return x(startTime + (timeStep*i));})
        .y(function(d) {return y(d.MPGL+d.MPGI+d.MTTFB);})

而不是传递

 .y(function(d) {return y(d.MPGL+d.MPGI+d.MTTFB);}) 

我希望有一个更通用的声明,如:

.y(function(d) {return y(Z);})

然后以这样的方式调用该泛型行语句:

 graph.append("svg:path").attr("d", line1(<something_corresponding_to_Z_here>)).attr("class", "MPGL");

那么,这是可能的,还是我只是在做梦?我需要以不同的方式划分我的数据吗?

----------------的 / UPDATE ----------------

完整代码:

<html>
<head>
    <title>D3.js Test</title>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <style>
        body { font-family: "Helvetica Neue", Helvetica;}

        /* tell the SVG path to be a thin line without any area fill */
        path { stroke-width: 1; fill: none;}

        /* Define Line color based on category class */
        .MPGL {stroke: #644a9b;}
        .MPGI {stroke: #009966;}
        .MTTFB {stroke: #0066FF;}

        /* Axis Formatting/styling */
        .axis {
          shape-rendering: crispEdges;
        }

        .x.axis line {
          stroke: lightgrey;
        }

        .x.axis .minor {
          stroke-opacity: .5;
        }

        .x.axis path {
          display: none;
        }

        .x.axis text {
          font-size: 10px;
        }

        .y.axis line, .y.axis path {
          fill: none;
          stroke: lightgrey;
        }

        .y.axis text {
            font-size: 12px;
        }

    </style>
</head>
    <body>


    <div id="graph" class="aGraph" style="position:absolute;top:0px;left:0; float:left;"></div>


    <script>
        // define dimensions of graph
        var m = [20, 20, 20, 40]; // margins
        var w = 550;    // width
        var h = 300; // height

    data = [ { "WK" : 14, "EOBSHR" : 1364839200000, "VOL" : 71383, "MPGL" : 2.901, "MPGI" : 1.203, "MTTFB" : 1.221, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364842800000, "VOL" : 70447, "MPGL" : 2.804, "MPGI" : 1.182, "MTTFB" : 1.211, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364846400000, "VOL" : 64878, "MPGL" : 2.781, "MPGI" : 1.169, "MTTFB" : 1.172, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364850000000, "VOL" : 56668, "MPGL" : 2.734, "MPGI" : 1.18, "MTTFB" : 1.153, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364853600000, "VOL" : 48721, "MPGL" : 2.722, "MPGI" : 1.134, "MTTFB" : 1.137, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364857200000, "VOL" : 45605, "MPGL" : 2.862, "MPGI" : 1.155, "MTTFB" : 1.116, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364860800000, "VOL" : 51002, "MPGL" : 3.219, "MPGI" : 1.136, "MTTFB" : 1.124, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364864400000, "VOL" : 62180, "MPGL" : 3.7, "MPGI" : 1.13, "MTTFB" : 1.143, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364868000000, "VOL" : 67299, "MPGL" : 3.965, "MPGI" : 1.198, "MTTFB" : 1.221, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364871600000, "VOL" : 58893, "MPGL" : 3.953, "MPGI" : 1.275, "MTTFB" : 1.24, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364875200000, "VOL" : 52752, "MPGL" : 4.082, "MPGI" : 1.373, "MTTFB" : 1.295, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364878800000, "VOL" : 55881, "MPGL" : 4.401, "MPGI" : 1.393, "MTTFB" : 1.39, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364882400000, "VOL" : 65844, "MPGL" : 4.608, "MPGI" : 1.394, "MTTFB" : 1.37, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364886000000, "VOL" : 78441, "MPGL" : 4.484, "MPGI" : 1.366, "MTTFB" : 1.399, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364889600000, "VOL" : 91130, "MPGL" : 4.047, "MPGI" : 1.321, "MTTFB" : 1.57, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }, 
             { "WK" : 14, "EOBSHR" : 1364893200000, "VOL" : 89911, "MPGL" : 3.674, "MPGI" : 1.248, "MTTFB" : 1.314, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364896800000, "VOL" : 81673, "MPGL" : 3.548, "MPGI" : 1.298, "MTTFB" : 1.301, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364900400000, "VOL" : 85718, "MPGL" : 3.515, "MPGI" : 1.245, "MTTFB" : 1.289, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364904000000, "VOL" : 95746, "MPGL" : 3.541, "MPGI" : 1.236, "MTTFB" : 1.306, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 },
             { "WK" : 14, "EOBSHR" : 1364907600000, "VOL" : 105282, "MPGL" : 3.296, "MPGI" : 1.201, "MTTFB" : 1.273, "mPGL" : 3.549, "mPGI" : 1.274, "mTTFB" : 1.248 }]

// Find timeframe of dataset to create variables for display
    var startTime = d3.min(data, function(d) { return d.EOBSHR; });
    var endTime = d3.max(data, function(d) { return d.EOBSHR; })
    var timeStep = 3600000;

// Setup scales to adjust display size based on content 
    var x = d3.time.scale().domain([startTime, endTime]).range([0, w]);
    x.tickFormat(d3.time.format("%Y-%m-%d"));
    var y = d3.scale.linear().domain([0, d3.max(data, function(d) { return d.MPGL+d.MPGI+d.MTTFB; })]).range([h, 0]);

// create a line function that can convert data[] into x and y points
//*********************************************
//*********************************************
//
//      This is the area where input is needed!
//
//*********************************************
//*********************************************
    // MPGL
    var line1 = d3.svg.line()
        .x(function(d,i) {return x(startTime + (timeStep*i));})
        .y(function(d) {return y(d.MPGL+d.MPGI+d.MTTFB);})
    // MPGI
    var line2 = d3.svg.line()
        .x(function(d,i) {return x(startTime + (timeStep*i));})
        .y(function(d) {return y(d.MPGI+d.MTTFB);})

    // MTTFB
    var line3 = d3.svg.line()
        .x(function(d,i) { return x(startTime + (timeStep*i)); })
        .y(function(d) { return y(d.MTTFB);})


//--------------------------------------------------------------------
// Creating the visualization by pulling all of the elements together
//--------------------------------------------------------------------
// Add an SVG element with the desired dimensions and margin.
    var graph = d3.select("#graph").append("svg:svg")
          .attr("width", w + m[1] + m[3])
          .attr("height", h + m[0] + m[2])
        .append("svg:g")
          .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

// create yAxis
    var xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(1);

// Add the x-axis.
    graph.append("svg:g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + h + ")")
          .call(xAxis);


// create left yAxis
    var yAxisLeft = d3.svg.axis().scale(y).ticks(6).orient("left");
// Add the y-axis to the left
    graph.append("svg:g")
          .attr("class", "y axis")
          .attr("transform", "translate(-10,0)")
          .call(yAxisLeft);

//*********************************************************
   //  How do I pass something in the line_x_(...) portion
   //     that would give the function a clue which data point
   //     to add to the line/path?
   //*********************************************************
// add lines
// do this AFTER the axes above so that the line is above the tick-lines
    graph.append("svg:path").attr("d", line1(data)).attr("class", "MPGL");
    graph.append("svg:path").attr("d", line2(data)).attr("class", "MPGI");
    graph.append("svg:path").attr("d", line3(data)).attr("class", "MTTFB");

</script>
</body>
</html>

1 个答案:

答案 0 :(得分:1)

使用D3时,在传入数据时,最好坚持选择模式。例如,请参阅this tutorial。在您的特定情况下,您可以将数据提供给datum()函数,然后相应地添加行。也就是说,代码的最后三行将成为

graph.append("path")
     .datum(data)
     .attr("class", "MPGL")
     .attr("d", line1);

和其他线类似。现在,您可以将data参数替换为要绘制的数据子集并更新该行。您可以使用任何D3或Javascript函数来过滤数据。 This tutorial详细介绍了更新数据。

对于工具提示,this answer应该有所帮助。