2

i want to include scrollbar and navigator, range selector functionality in my line graph . something similar to http://www.highcharts.com/products/highstock Can this be done on d3 if so give me a link on a tutorial or code.

the code is

var margin = {top: 10, right: 10, bottom: 100, left: 40},
    margin2 = {top: 430, right: 10, bottom: 30, left: 40},
        width = 2000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom,
        height2 = 500 - margin2.top - margin2.bottom;


var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");

var x = d3.time.scale().range([0, width]);
var x2= d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height2, 0]);

var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");

var yAxis = d3.svg.axis().scale(y).orient("left");

var brush = d3.svg.brush()
    .x(x2)
    .on("brush", brushed);


var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });

var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });

var brush = d3.svg.brush()
    .x(x2)
    .on("brush", brushed);
var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);



svg.append("defs").append("clipPath")
    .attr("id", "clip")
  .append("rect")
    .attr("width", width)
    .attr("height", height);

var focus = svg.append("g")
    .attr("class", "focus")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


var context = svg.append("g")
    .attr("class", "context")
    .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");

d3.json("data/data2.php", function(error, data) { data.forEach(function(d,i) {

    //document.write(d.date);
    d.date = parseDate(d.date);
    //document.write(d.date);
        d.close = +d.close;

    //document.write(d.close);
    arr[i]=d.close;


    len=i+1;


    });

// Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([min-10, max+10]);
    x2.domain(x.domain());
     y2.domain(y.domain());

focus.append("path")        // Add the valueline path.
    .datum(data)
        .attr("class","valueline")
    .attr("d", valueline);

focus.selectAll("dot")
        .data(data)
    .enter().append("a")
    .attr("xlink:href",function(d,i){if(d.close>=usl||d.close<=lsl||signal8[i]==8||signal8dw[i]==8||signal6up[i]==6||signal6dw[i]==6)return "http://en.wikipedia.org";})
    .append("circle")
        .attr("r", 2)
    .style("fill", function(d,i) {            // <== Add these
        if(d.close==0) {return "none"}              
        if((ul[i]==9999)||(dl[i]==9999)) {return "red"}
        else if(signal8[i]==8 ){ return "orange" }
        else if(signal8dw[i]==8 ){return "gold"}
        else if(signal6up[i]==6 ){return "indianred"}
        else if(signal6dw[i]==6 ){return "#FF5C33"}
            else    { return "steelblue" }          // <== Add these
        ;})  
        .attr("cx", function(d) { return x(d.date); })
        .attr("cy", function(d) { return y(d.close); })
    .on("mouseover", function(d,i) {

            div.transition()        
                .duration(200)      
                .style("opacity", .9);      
                div.html(function(){
    if(d.close==0)
    {return}
    if(ul[i]==9999)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " UPPER "}
    else if(dl[i]==9999)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + "  LOWER "}
    else if(signal8[i]==8)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " ( hello1 )"}
    else if(signal8dw[i]==8)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " ( hello1  )"}
    else if(signal6up[i]==6)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " ( hello1 )"}
    else if(signal6dw[i]==6)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " ( hello1 )"}
    else {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b>"}
;})



context.append("path")      // Add the valueline path.
        .attr("d", valueline2(data));

context.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height2 + ")")
      .call(xAxis2);


context.append("g")
      .attr("class", "x brush")
      .call(brush)
    .selectAll("rect")
      .attr("y", -6)
      .attr("height", height2 + 7);
});


function brushed() {
  x.domain(brush.empty() ? x2.domain() : brush.extent());
  focus.select(".valueline").attr("d",valueline);
  focus.select(".x.axis").call(xAxis);
}

function type(d) {
  d.date = parseDate(d.date);
  d.close = +d.close;
  return d;
}

the above code is a snippet of the overall code. here when im executing im getting a parse error d="". where am i wrong. and i have drawn a few limit lines in the graph which i have not included in the above code. the bottom brush is working but the main graph is not getting updated as per the brush. i want to update the dots too. what should i include the brushed function.

Vasanth Srinivasa
  • 67
  • 1
  • 1
  • 11
  • 1
    You can do this with a d3 [brush control](https://github.com/mbostock/d3/wiki/SVG-Controls#wiki-brush). You'll probably want to start from [this example](http://bl.ocks.org/mbostock/1667367). – AmeliaBR Mar 17 '14 at 17:23
  • here the the brush is working , but the data in my main line graph is not changing as per the slider graph. the code where i think there is a problem is. function brushed() { x.domain(brush.empty() ? x2.domain() : brush.extent()); focus.select(".valueline").attr("d",valueline(data)); focus.select(".x.axis").call(xAxis); } function type(d) { d.date = parseDate(d.date); d.close = +d.close; return d; } – Vasanth Srinivasa Mar 18 '14 at 09:40
  • have valueline defined as var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); }); – Vasanth Srinivasa Mar 18 '14 at 09:41
  • @AmeliaBR can u help me out with this question too http://stackoverflow.com/questions/22448936/draw-a-line-from-x-and-y-axis-to-indicate-80-of-the-line-in-a-line-graph-in-d3 – Vasanth Srinivasa Mar 18 '14 at 09:42
  • Problem parsing d="" is the error im getting when i start using the slider – Vasanth Srinivasa Mar 18 '14 at 11:14
  • Can you update the question with your code -- including the scales, line generator, and the brush functions. – AmeliaBR Mar 18 '14 at 14:59
  • have updated the ques with code. i think there is something wrong with the function type(d){} – Vasanth Srinivasa Mar 19 '14 at 07:26
  • Change `focus.select(".valueline")` to `focus.selectAll(".valueline")`. Even though you only have the one line, you can't use `select` because that will [over-write the data you have bound to the path element with the data from the parent](https://github.com/mbostock/d3/wiki/Selections#wiki-select) (and you don't have any data bound to `focus`). It's a feature that makes updating data easier, but it can be easy to forget until it causes problems. P.S. If you get it working, post your final code as an answer. After all, you did most of it yourself with just a point in the right direction... – AmeliaBR Mar 19 '14 at 15:33
  • thanks again @AmeliaBR. appreciate it. its working :) – Vasanth Srinivasa Mar 20 '14 at 10:27
  • @AmeliaBR i got the line working but i have dots at the markers of the points in the graph. how do i make those also update along with the line too. have updated the question with the code of the dots – Vasanth Srinivasa Mar 20 '14 at 11:45
  • You need to split your `enter` chain from your update chain. [This answer should help you understand the update structure](http://stackoverflow.com/a/20754006/3128209). You might also want to read Mike Bostock's [General Update Pattern tutorials](http://bl.ocks.org/mbostock/3808218). – AmeliaBR Mar 20 '14 at 14:51
  • @AmeliaBR i am really clueless as to where i have to update it and how, meaning how should i update it in the brushed() function, ive split the enter but how should i update it according to the brush width. can u show me a snippet relative to my code to display the line markers(dots) as and when the brush updates. and i also have other lines in the graph which also needs to be updated. but first i want the dots for a start . thank you in advance. i cant put a snapshot of the graph to show u the lines bec i need 10 reputations ;p – Vasanth Srinivasa Mar 24 '14 at 05:34
  • Ah, wasn't reading your code closely, I was thinking your brush function was re-calling your update/draw function. You just need to re-select the dots and re-set their positions using the changed x scale. – AmeliaBR Mar 24 '14 at 17:10

2 Answers2

1

For the point marks, you again need a selectAll, and then reset the cx property to match the modified x scale:

function brushed() {
  x.domain(brush.empty() ? x2.domain() : brush.extent()); 
     //change the x-scale on the focus graph to match the brush extent
     //(or reset it to the full domain if the brush is empty)

  focus.selectAll(".valueline").attr("d",valueline); 
    // redraw the lines (using the updated scale)

  focus.selectAll("dot").select("circle")
     .attr("cx", function(d) { return x(d.date); });
    //update the x position of the dots based on the updated x-scale

  focus.select(".x.axis").call(xAxis); 
   //redraw the x-axis based on the updated x-scale
}
AmeliaBR
  • 27,344
  • 6
  • 86
  • 119
0
var margin = {top: 10, right: 10, bottom: 100, left: 40},
    margin2 = {top: 430, right: 10, bottom: 30, left: 40},
        width = 2000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom,
        height2 = 500 - margin2.top - margin2.bottom;


var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");

var x = d3.time.scale().range([0, width]);
var x2= d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height2, 0]);

var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");

var yAxis = d3.svg.axis().scale(y).orient("left");

var brush = d3.svg.brush()
    .x(x2)
    .on("brush", brushed);


var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });

var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });

var brush = d3.svg.brush()
    .x(x2)
    .on("brush", brushed);
var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);



svg.append("defs").append("clipPath")
    .attr("id", "clip")
  .append("rect")
    .attr("width", width)
    .attr("height", height);

var focus = svg.append("g")
    .attr("class", "focus")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


var context = svg.append("g")
    .attr("class", "context")
    .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");

d3.json("data/data2.php", function(error, data) { data.forEach(function(d,i) {

    //document.write(d.date);
    d.date = parseDate(d.date);
    //document.write(d.date);
        d.close = +d.close;

    //document.write(d.close);
    arr[i]=d.close;


    len=i+1;


    });

// Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([min-10, max+10]);
    x2.domain(x.domain());
     y2.domain(y.domain());

focus.append("path")        // Add the valueline path.
    .datum(data)
        .attr("class","valueline")
    .attr("d", valueline);

context.append("path")      // Add the valueline path.
        .attr("d", valueline2(data));

context.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height2 + ")")
      .call(xAxis2);


context.append("g")
      .attr("class", "x brush")
      .call(brush)
    .selectAll("rect")
      .attr("y", -6)
      .attr("height", height2 + 7);
});


function brushed() {
  x.domain(brush.empty() ? x2.domain() : brush.extent());
  focus.selectAll(".valueline").attr("d",valueline); // selectAll is the answer
  focus.select(".x.axis").call(xAxis);
}

function type(d) {
  d.date = parseDate(d.date);
  d.close = +d.close;
  return d;
}
Vasanth Srinivasa
  • 67
  • 1
  • 1
  • 11