So, I've been using R & ggplot2 to make good progress and share the results of our data analysis. However, we want something more interactive. We've used Highcharts.js, but it breaks under the weight of many data points and isn't very flexible in customization. So, I've played a bit with protovis in the past, but am now looking to make D3 work.
My two key problems are as follows:
- How to reuse a line definition by passing in a pointer to part of the dataset
- Tooltips (made some progress and I'll follow up on another post unless someone sees an obvious answer here)
In the code below, I've highlighed the line declaration and then where those functions are called for adding to the svg & styling.
What I'm looking for is help figuring out how to pass in a parameter to the line function to specify which data element to add to a given line. It is possible that I need to format the data differently, and that is perfectly possible if that's the best solution.
Any input is appreciated!
----------------UPDATE----------------
Help needed here:
        // 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);})
Instead of passing
 .y(function(d) {return y(d.MPGL+d.MPGI+d.MTTFB);}) 
I would like to have a more generic declaration like:
.y(function(d) {return y(Z);})
and then call that generic line statement in something like this:
 graph.append("svg:path").attr("d", line1(<something_corresponding_to_Z_here>)).attr("class", "MPGL");
So, is this possible, or am I just dreaming? Do I need to carve up my data differently?
----------------/UPDATE----------------
Full Code here:
<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>
 
     
    