0

i have a line graph, and perform a calculation for values of the line and based on some criteria the mean, upper limit and lower limit changes. so in the graph i'll b have 3 limit lines(mean , upper and lower) and the normal value line. right now i am able to achieve the limit lines perfectly through the said code.

here im looping and at each iteration im drawing the 3 limit lines. but now im now storing the values of the limits in a db , the calculation is done in a diff file and stores the limit values along with the main values in a db. how do i draw these lines from a db such that these lines are able to be used in a "brush"( very imp). the column values in the db are date, close(value), mean, upper, lower. eg( 21-feb-2013, 250, 63.50, 320, 33.89) ( 22-feb-2013, 255, 63.50, 320, 33.89) ( 23-feb-2013, 192, 63.50, 320, 33.89) ( 24-feb-2013, 90, 45.50, 120, 23.9) ( 25-feb-2013, 67, 45.50, 120, 23.9)

first ill be drawing the limit lines and later ill draw the valueline. im converting the limit values to db to reduce computation on client side and majorly to help in the "brush" slider functionality. i want the limit lines to break when their values change, for eg mean value from 63.50 to 45.50, there must be no line between these two values.

the normal valueline line code is the same as add scrollbar and navigator, range selector functionality in d3.js

for(var v=0;v<m;v++)
{

var mean_value=meanArr[v];
var st=line[v];
var end=line[v+1];


     focus.append("line")

       .attr("class", "mean-line")

      .attr({ x1: x(data[st].date), y1: y(mean_value), x2:x(data[end].date), y2: y(mean_value) })
      .on("mouseover", function(d,i) {

        coordinates = d3.mouse(this);
    var x = coordinates[0];
    var y = coordinates[1];





            div.transition()        
                .duration(200)      
                .style("opacity", .9);      
                div.html(function(){for(var k=0;k<m;k++)
                {if(x<x_val[k])
                { return "mean "+meanArr[k]}}
        ;})
                .style("left", (d3.event.pageX) + "px")     
                .style("top", (d3.event.pageY - 28) + "px");    
            }).on("mouseout", function() {      
            div.transition()        
                .duration(500)      
                .style("opacity", 0);
       });





var upper_limit = uslArr[v];

  focus.append("line")

        .attr("class", "limit-line")
    .attr({ x1: x(data[st].date) , y1: y(upper_limit), x2:x(data[end].date), y2: y(upper_limit) })
    .on("mouseover", function(d,i) {

        coordinates = d3.mouse(this);
    var x = coordinates[0];
    var y = coordinates[1];





            div.transition()        
                .duration(200)      
                .style("opacity", .9);      
                div.html(function(){for(var k=0;k<m;k++)
                {if(x<x_val[k])
                { return "upper Limit "+uslArr[k]}}
        ;})
                .style("left", (d3.event.pageX) + "px")     
                .style("top", (d3.event.pageY - 28) + "px");    
            }).on("mouseout", function(d) {     
            div.transition()        
                .duration(500)      
                .style("opacity", 0);
       });                  



    //document.write(down_limit[30]);
  // lower limit line

  var lower_limit = lslArr[v];

    var z;


  focus.data(lslArr)
    .append("line")

    .attr("class", "limit-line")

    .attr({ x1: x(data[st].date), y1: y(lower_limit), x2:function(){ z=x(data[end].date); x_val[v]=z; return z;}, y2: y(lower_limit) })
    .on("mouseover", function(d,i) {

        coordinates = d3.mouse(this);
    var x = coordinates[0];
    var y = coordinates[1];


    //z=Math.ceil(z);


            div.transition()        
                .duration(200)      
                .style("opacity", .9);      
                div.html(function(){for(var k=0;k<m;k++)
                {if(x<x_val[k])
                { return "lower limit "+lslArr[k]}}
        ;})
                .style("left", (d3.event.pageX) + "px")     
                .style("top", (d3.event.pageY - 28) + "px");    
            })                  
        .on("mouseout", function() {        
            div.transition()        
                .duration(500)      
                .style("opacity", 0);
       });




}

i have put the 3 lines in a group such as http://bl.ocks.org/mbostock/3884955 but im not able to update it in the brush as the other value line. the code for the graph is given below. and the city variable is a group of 3 values mean, lower and upper limit. how do i change the color of each line. because i have used d3.scale.category10() , i have predefined colors. and i want a break of line from one value to another value in the limits, the defined() wont work, what other way can i do that.

<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style>
body { font: 14px Arial;}
svg {
  font: 10px sans-serif;
}
circle {
   -moz-transition: all 0.3s;
   -o-transition: all 0.3s;
   -webkit-transition: all 0.3s;
   transition: all 0.3s;
}           
circle:hover {
        stroke: orange; 
        stroke-width:2;
            }
path { 
    stroke: steelblue;
    stroke-width: 1;
    fill: none;
}



.axis path,
.axis line {
    fill: none;
    stroke: green;
    stroke-width: 1;
    shape-rendering: crispEdges;
}
div.tooltip {   
    position: absolute;         
    text-align: center;         
    width: auto;                    
    height: auto;                   
    padding: 2px;               
    font: 14px sans-serif;      
    background: lightsteelblue; 
    border: 0px;        
    border-radius: 8px;         
    pointer-events: none;
}
.icon {
    float: right;
    display: block;
    margin-bottom: 100;
    margin-left: 0;
    margin-right: 0;
    margin-top: 0;
    padding-bottom: 0;
    padding-left: 0;
    padding-right: 0;
    padding-top: 0;
}       

.download { 
  background: lightblue; 
  color: blue; 
  font-weight: 900; 
  border: 2px; 
  padding: 4px; 
  margin:4px;
}   
.brush .extent {
  stroke: #fff;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}   

</style>


</script>
</head>
<body>
<div id="svg"></div>
<button class="download" onClick="javascript:(function () { var e = document.createElement('script'); if (window.location.protocol === 'https:') { e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js'); } else { e.setAttribute('src', 'http://nytimes.github.com/svg-crowbar/svg-crowbar.js'); } e.setAttribute('class', 'svg-crowbar'); document.body.appendChild(e); })();"> Download</button>

<script type="text/javascript" src="d3/d3.v3.js"></script>
<script>


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 color = d3.scale.category10();


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 line = d3.svg.line()
    .interpolate("step")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.limit); });

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 div = d3.select("body").append("div")   
    .attr("class", "tooltip")               
    .style("opacity", 0).style("float","left");    

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







var arr=new Array();
// Get the data
d3.json("data/data3.php", function(error, data) { 

color.domain(d3.keys(data[0]).filter(function(key) {  if(key !== "date"&&key !== "close") return key; }));


    data.forEach(function(d,i) {




    d.date = parseDate(d.date);

        d.close = +d.close;
    d.mean=+d.mean;
    d.ucl=+d.ucl;
    d.lcl=+d.lcl;   

    arr[i]=d.close;


    len=i+1;


    });


var cities = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, limit: +d[name]};
      })
    };
  });






 var min=0;
var max=200;
// Scale the range of the data

    x.domain(d3.extent(data, function(d) { return d.date; }));

  //  y.domain([min-10, max+10]);
    //y.domain([0, d3.max(data, function(d) { return d.ucl; })]);

y.domain([
    d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.limit; }); }),
    d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.limit; }); })
  ]);

    x2.domain(x.domain());
     y2.domain(y.domain());


    //y.domain([lsl-5, d3.max(data, function(d) { return d.close; })]);


  var city= focus.selectAll(".city")
      .data(cities)
      .enter().append("g")
      .attr("class", "city");

    city.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return color(d.name); });







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

    focus.selectAll(".dot").data(data).enter().append("a").attr("class", "dot")
        .attr("xlink:href",function(d,i){if(d.close>=d.ucl||d.close<=d.lcl)return "http://en.wikipedia.org";})
    .append("circle")
        .attr("r", 2)
    .style("fill", function(d,i) {            // <== Add these
        if(d.close==0) {return "none"}              
        if(d.close>=d.ucl||d.close<=d.lcl) {return "red"}

            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(d.close>=d.ucl)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " > UPPER LIMIT"}
    else if(d.close<=lcl)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " < LOWER LIMIT"}

    else {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b>"}
;})
                .style("left", (d3.event.pageX) + "px")     
                .style("top", (d3.event.pageY - 28) + "px");    
            })                  
        .on("mouseout", function(d) {       
            div.transition()        
                .duration(500)      
                .style("opacity", 0);
       }).style("pointer-events","visible");




    /*
city.append("text")
      .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
      .attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.limit) + ")"; })
      .attr("x", 3)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

*/
            // Add the X Axis

    focus.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis)
    .selectAll("text")  
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", function(d) {
                return "rotate(-65)" 
                });


    focus.append("text")             // text label for the x axis
        .attr("x", width/2 )
        .attr("y",  height+margin.bottom)
        .style("text-anchor", "middle")
        .text("Date");  

// Add the Y Axis

    focus.append("g").attr("class", "y axis").call(yAxis);

    focus.append("text").attr("transform","rotate(-90)").attr("y", 0-margin.left+10 )
        .attr("x",0-( height/2) )
        .style("text-anchor", "middle")
    .style("text-decoration", "underline")  
        .text("issue"); 

    //title to graph
focus.append("text")
        .attr("x", (width / 2))             
        .attr("y", 0 - (margin.top / 2))
        .attr("text-anchor", "middle")  
        .style("font-size", "16px") 
        .style("text-decoration", "underline")  
        .text("Issue vs Date Graph");


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);
  focus.selectAll(".dot").select("circle").attr("cx", function(d) { return x(d.date); });
  focus.selectAll(".city").attr("d",line);
  focus.select(".x.axis").call(xAxis);
}

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




</script>

</body>
<html>

how should i call the group line in brushed()

Community
  • 1
  • 1
Vasanth Srinivasa
  • 67
  • 1
  • 1
  • 11
  • You want to get your data into an array-of-arrays type structure, so you can do draw all the lines as one d3 selection, as in the [multi-line graph example](http://bl.ocks.org/mbostock/3884955). (Then you'll also be able to use the same selection to update all the lines when the scale changes from the brush). – AmeliaBR Mar 26 '14 at 16:03
  • To get the limit lines to "break" when the value changes, you'll either need to: use a `defined` function that makes a point undefined if it has a different value from the previous point (but then you'll have a gap with a missing point, not just a break), *or* split your array into multiple sub-arrays for each section, and draw separate lines for each. – AmeliaBR Mar 26 '14 at 16:06
  • P.S. You might want to check out the "step" [line interpolation modes](https://github.com/mbostock/d3/wiki/SVG-Shapes#wiki-line_interpolate) to see if that would be acceptable as an alternative to breaking the line; it would make your code much simpler! – AmeliaBR Mar 26 '14 at 16:07
  • is there a way i can make the each limit line into a set of lines based on the uniqueness of the value. so for eg if the mean limit changes it wil be a new line. so i don need a new solution for a break in the line here. is there a way i can make a group of lines and all of the be updated at one using a "brush". using step interpolation doesnt seem viable enough. since i want a complete break after the limt values change. – Vasanth Srinivasa Mar 28 '14 at 11:21
  • @AmeliaBR ive updated the ques regarding to the array of array lines, can u check it out – Vasanth Srinivasa Apr 01 '14 at 06:39
  • @AmeliaBR how to split your array into multiple sub-arrays for each section, and draw separate lines for each? so that i can use the same for "brush" – Vasanth Srinivasa Apr 01 '14 at 08:21
  • You'll need to manually loop through your array, and use [Array.slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) to create the sub-arrays. You'll also want to look at the multi-line graph example I linked above. – AmeliaBR Apr 01 '14 at 14:54
  • @AmeliaBR i get the array.slice but i want to know how to draw the broken lines in a single go, so ill be able to use it for a brush also. creating sub arrays is fine but how to draw them, should i loop through them every time in a brush too? and when i draw the line for the first time, can i draw it in a similar way as multi line meaning in a single command. ive also implemented the multi line graph and updated it in the question but the brush functionality is not working for it. – Vasanth Srinivasa Apr 02 '14 at 06:54
  • @AmeliaBR help me out with the brush functionality for the above code including multiline and the colorations. how do i change the colors of the line. since its using scale.category10(). i'll go ahead with step interpolation for now. – Vasanth Srinivasa Apr 02 '14 at 10:46
  • `focus.selectAll(".city").attr("d",line);` isn't working because "city" is the class on your `` elements, not on your paths. You need `focus.selectAll("g.city path.line")` to get the lines themselves. Also, when you create the lines you use `function(d){return line(d.values);}`, so you'd need to use the same structure in your update. – AmeliaBR Apr 02 '14 at 15:32
  • @AmeliaBR thanks a ton, can u give me a link to include the multi lines in the brush graph under the main graph and also how do i give markers for the multi line graph points, and want to change the colors of the multi lines. i want the mean line to be green and other two to be red. im unable to find any help on web about these. – Vasanth Srinivasa Apr 03 '14 at 09:57

0 Answers0