Desi Delite Desi Delite - 2 months ago 15
jQuery Question

How to change color of a data point in line chart according to a condition?

I designed a line chart using D3.js. The line goes on the x axis only. It contains data points and when the mouse move on that data point, simply shows a tooltip which contain some particular data about that data point.I needed to append data point one by one,means first data point appears and next one appears after 1 minute and so on. So I append data points into the line inside a time period. That means I set a setInterval function and a data point append one by one inside this function. (For this I increase the array which holds the data step by step and each time data points are overwrite and it shows like new data point append inside the time interval.)

Then I needed to change the color of a particular data point. According to this example, if a particular data element has "A" as its 'Record' value then I need to change the color of its data point. But according to overwriting or any other error, it does not work properly. Can someone please show where was I wrong and is there any possibility to do this task more easier than this way?

(I tried to explain this my best. Sometime you may can't understand what I say.So perhaps this code will help you to understand it properly)



<html>
<head>
<title>myD3Trial1</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js" charset="utf-8"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://rawgit.com/jaz303/tipsy/master/src/javascripts/jquery.tipsy.js"></script>
<link href="tipsy.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" type="text/css" href="D3LineChart.css">
<style>
.axis path,
.axis line{
fill: none;
stroke: blue;
stroke-width: 2px;
}

.line{
fill: none;
stroke: black;
stroke-width: 1px;
}

.tick text{
font-size: bold 11px;
}

.tick line{
opacity: 0.2;
}
</style>
</head>
<body>

<div class="chart3"></div>

<script>

var line_xAxisGroup = null,
line_dataCirclesGroup = null,
line_dataLinesGroup = null;

var line_maxDataPointsForDots = 50,
line_transitionDuration = 1000;

var line_pointRadius = 7;

var line_parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;

//set original data set for here

var OriginalDataForLineChart = [{
"Date": "2013-03-12 05:09:04",
"Record":"A",
"Value": "0"
}, {
"Date": "2013-03-12 14:59:06",
"Record":"B",
"Value": "0"
}, {
"Date": "2013-03-12 14:49:04",
"Record":"C",
"Value": "0"
}, {
"Date": "2013-03-13 14:39:06",
"Record":"D",
"Value": "0"
},{
"Date": "2013-03-12 14:29:03",
"Record":"A",
"Value": "0"
}];

var line_margin = {top: 20, right: 20, bottom: 30, left: 50};
var line_width = 1100 - line_margin.left - line_margin.right;
var line_height = 100 - line_margin.top - line_margin.bottom;

var line_x = d3.time.scale()
.range([0, line_width]);

var line_y = d3.scale.linear()
.range([line_height, 0]);

var line_xAxis = d3.svg.axis()
.scale(line_x)
.orient("bottom");

var line_yAxis = d3.svg.axis()
.scale(line_y)
.orient("left");

var line_line = d3.svg.line()
.x(function(d) { return line_x(d.Date); })
.y(function(d) { return line_y(d.Value); });


var line_svg = d3.select(".chart3").append("svg")
.attr("width", line_width + line_margin.left + line_margin.right)
.attr("height", line_height + line_margin.top + line_margin.bottom)
.append("g")
.attr("transform", "translate(" + line_margin.left + "," + line_margin.top + ")");

OriginalDataForLineChart.forEach(function(d) {
d.Date = line_parseDate(d.Date);
d.Value = +d.Value;
});

line_x.domain(d3.extent(OriginalDataForLineChart, function(d) { return d.Date; }));
line_y.domain(d3.extent(OriginalDataForLineChart, function(d) { return d.Value;}));

line_svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + line_height + ")")
.call(line_xAxis);



line_svg.append("path")
.datum(OriginalDataForLineChart)
.attr("class", "line")
.attr("d", line_line);

var i = 1;
var interval = setInterval(function() {
updateLineChart(i);
i++;
if(i==OriginalDataForLineChart.length) clearInterval(interval);
},1000);


var duplicateDataForLineChart = [];

function updateLineChart(index){

for(var counut2 = 0 ; counut2<index ; counut2++){
duplicateDataForLineChart[counut2] = OriginalDataForLineChart[counut2];
}

if (!line_dataCirclesGroup) {
line_dataCirclesGroup = line_svg.append('svg:g');
}

var line_circles = line_dataCirclesGroup.selectAll('.data-point').data(duplicateDataForLineChart);
//.data(data);

line_circles
.enter()
.append('svg:circle')
.attr('class', 'data-point')
.style('opacity', 1e-6);

for(var x=0 ; x<duplicateDataForLineChart.length ; x++){ //<==I add this for loop to change data point color
if(duplicateDataForLineChart[x].Record=="A"){
line_circles
.enter()
.append('svg:circle')
.attr('class', 'data-point')
.style('opacity', 1e-6)
.style('fill','#FF45FF');
}
}

line_circles
.attr('cx', function(d) { return line_x(d.Date); })
.attr('cy', function(d) { return line_y(d.Value); })
.attr('r', function() { return (duplicateDataForLineChart.length <= line_maxDataPointsForDots) ? line_pointRadius : 0 })
.transition()
.duration(line_transitionDuration)
.style('opacity', 1);

line_circles
.exit()
.transition()
.duration(line_transitionDuration)
// Leave the cx transition off. Allowing the points to fall where they lie is best.
//.attr('cx', function(d, i) { return line_xAxis(i) })
.attr('cy', function() { return line_y(0) })
.style("opacity", 1e-6)
.remove();

$('svg circle').tipsy({
gravity: 'width',
html: true,
title: function() {
console.log(this.__data__);
var d = this.__data__;
//var pDate = d.line_x;
return d.Date;//.toLocaleDateString();//+'</br>'+d.Date.to;
}
});

}


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




Answer

I have removed for loop because its not needed. We can add a callback function to check for 'A' type records and set 'fill' attribute to RED color if it satisfies the condition.

<html>
<head>
<title>myD3Trial1</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js" charset="utf-8"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
<script src="https://rawgit.com/jaz303/tipsy/master/src/javascripts/jquery.tipsy.js"></script>     
<link href="tipsy.css" rel="stylesheet" type="text/css" />  
 <link rel="stylesheet" type="text/css" href="D3LineChart.css">    
<style>
.axis path,
.axis line{
    fill: none;
    stroke: blue;
     stroke-width: 2px;
  }

.line{
    fill: none;
    stroke: black;
    stroke-width: 1px;
  }

.tick text{
    font-size: bold 11px;
  }

.tick line{
    opacity: 0.2;
  }  
</style>    
</head>
<body>
    
<div class="chart3"></div>
    
<script>
    
    var line_xAxisGroup = null,
	    line_dataCirclesGroup = null,
	    line_dataLinesGroup = null; 
    
    var line_maxDataPointsForDots = 50,
	    line_transitionDuration = 1000; 
    
   var line_pointRadius = 7; 
    
   var line_parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;  
    
    //set original data set for here
    
   var OriginalDataForLineChart = [{
            "Date": "2013-03-12 05:09:04",
            "Record":"A",
            "Value": "0"
        }, {
            "Date": "2013-03-12 14:59:06",
            "Record":"B",
            "Value": "0"
        }, {
            "Date": "2013-03-12 14:49:04",
            "Record":"C",
            "Value": "0"
        }, {
            "Date": "2013-03-13 14:39:06",
            "Record":"D",
            "Value": "0"
        },{
            "Date": "2013-03-12 14:29:03",
            "Record":"A",
            "Value": "0"
    }];
       
    var line_margin = {top: 20, right: 20, bottom: 30, left: 50};
    var line_width = 1100 - line_margin.left - line_margin.right;
    var line_height = 100 - line_margin.top - line_margin.bottom;
    
    var line_x = d3.time.scale()
        .range([0, line_width]);

    var line_y = d3.scale.linear()
        .range([line_height, 0]);

    var line_xAxis = d3.svg.axis()
        .scale(line_x)
        .orient("bottom");

    var line_yAxis = d3.svg.axis()
        .scale(line_y)
        .orient("left");

    var line_line = d3.svg.line()
        .x(function(d) { return line_x(d.Date); })
        .y(function(d) { return line_y(d.Value); });


    var line_svg = d3.select(".chart3").append("svg")
        .attr("width", line_width + line_margin.left + line_margin.right)
        .attr("height", line_height + line_margin.top + line_margin.bottom)
        .append("g")
        .attr("transform", "translate(" + line_margin.left + "," + line_margin.top + ")");

    OriginalDataForLineChart.forEach(function(d) {
        d.Date = line_parseDate(d.Date);
        d.Value = +d.Value;
    });

    line_x.domain(d3.extent(OriginalDataForLineChart, function(d) { return d.Date; }));
    line_y.domain(d3.extent(OriginalDataForLineChart, function(d) { return d.Value;}));

    line_svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + line_height + ")")
          .call(line_xAxis);

    

    line_svg.append("path")
          .datum(OriginalDataForLineChart)
          .attr("class", "line")
          .attr("d", line_line);
    
    var i = 1;
    var interval = setInterval(function() {
        updateLineChart(i);
        
        if(i==OriginalDataForLineChart.length + 1)  clearInterval(interval);
        i++;
    },1000);
    
    
    var duplicateDataForLineChart = [];
    
function updateLineChart(index){
    
    for(var counut2 = 0 ; counut2<index ; counut2++){
        duplicateDataForLineChart[counut2] = OriginalDataForLineChart[counut2];
    }
        
    if (!line_dataCirclesGroup) {
		line_dataCirclesGroup = line_svg.append('svg:g');
	}

	var line_circles = line_dataCirclesGroup.selectAll('.data-point').data(duplicateDataForLineChart);
		//.data(data);

	line_circles
		.enter()
			.append('svg:circle')
				.attr('class', 'data-point')
				.style('opacity', 1e-6);
  
      
	line_circles
		.attr('cx', function(d) { return line_x(d.Date); })
		.attr('cy', function(d) { return line_y(d.Value); })
		.attr('r', function() { return (duplicateDataForLineChart.length <= line_maxDataPointsForDots) ? line_pointRadius : 0 })
        .style('fill', function(d){
                           if(d.Record == 'A'){
                              return 'RED';}
                          else{
                              return 'GREEN';
                               } 
                })
		.transition()
		.duration(line_transitionDuration)
		.style('opacity', 1);

	line_circles
		.exit()
			.transition()
			.duration(line_transitionDuration)
				// Leave the cx transition off. Allowing the points to fall where they lie is best.
				//.attr('cx', function(d, i) { return line_xAxis(i) })
				.attr('cy', function() { return line_y(0) })
				.style("opacity", 1e-6)
				.remove();

    $('svg circle').tipsy({ 
        gravity: 'width', 
        html: true, 
        title: function() {
          console.log(this.__data__);
          var d = this.__data__;
	  //var pDate = d.line_x;
          return d.Date;//.toLocaleDateString();//+'</br>'+d.Date.to; 
        }
    });
       
    }
    

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