Trouble getting D3-generated SVG to appear on screen consistently - d3.js

I'm currently working on a Javascript project where I am trying to render the following chart using d3.
The problem, though is that sometimes svg elements for the yellow chart fails to show sometimes (and at random). The problem usually goes away after I refresh the page (once or multiple times). When this happens, the browser dev tools still show that the svg elements are present:
This only happens to the yellow chart and never to the blue chart.
This is the function that I used to create the chart:
function makeGraphs(filterDisease,filterAir) {
var width = 840;
var height = 110;
var barPadding = 1;
var dateFormat = d3.time.format("%Y-%m-%d");
var xScale = d3.time.scale()
.range([0,width-50]);
var yScaleDisease = d3.scale.linear()
.range([height,0]);
var yScaleAir = d3.scale.linear()
.range([0,height]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("top");
var yAxisDisease = d3.svg.axis()
.scale(yScaleDisease)
.orient("left")
.ticks(5);
var yAxisAir = d3.svg.axis()
.scale(yScaleAir)
.orient("left")
.ticks(5);
var svgDisease = d3.select("body").select("#comparison-chart")
.append("svg")
.attr("class","chart-comparison")
.attr("id","chart-comparison-disease")
.attr("width",width)
.attr("height",height);
var svgAir = d3.select("body").select("#comparison-chart")
.append("svg")
.attr("class", "chart-comparison")
.attr("id", "chart-comparison-air")
.attr("width", width)
.attr("height", height + 20);
d3.json("/datasets/disease", function(error, datasetDisease) {
datasetDisease.forEach(function(d) {
d["date"] = dateFormat.parse(d["date"]);
d["total"] = 0
for (i=0;i<filterDisease.length;i++) {
d["total"] += d[filterDisease[i]];
}
});
var ndxDisease = crossfilter(datasetDisease);
var dateDimDisease = ndxDisease.dimension(function(d) {return d["date"];});
var total_disease = dateDimDisease.group().reduceSum(function(d) {return d["total"];});
var datasetDisease_formatted = total_disease.all();
xScale.domain([new Date(datasetDisease_formatted[0]["key"]), new Date(datasetDisease_formatted[datasetDisease_formatted.length -1]["key"])]);
yScaleDisease.domain([0,d3.max(datasetDisease_formatted,function(d) {return d["value"];})]);
svgDisease.selectAll("rect")
.data(datasetDisease_formatted)
.enter()
.append("rect")
.attr("x", function(d) { return xScale(new Date(d["key"]));})
.attr("y", function(d) { return yScaleDisease(d["value"]); })
.attr("width", (width-50)/datasetDisease_formatted.length - barPadding)
.attr("height", function(d) {
return height - yScaleDisease(d["value"]);
})
.attr("fill", "#19C3CD")
.attr("transform", "translate(50,0)");
svgDisease.append("g")
.attr("class", "y axis")
.attr("transform", "translate(30,0)")
.call(yAxisDisease);
svgDisease.append("text")
.text("Disease Records")
.attr("x", 650)
.attr("y", 20);
});
d3.json("/datasets/air", function(error, datasetAir) {
datasetAir.forEach(function(d) {
d["date"] = dateFormat.parse(d["date"]);
d["total"] = 0
for (i=0;i<filterAir.length;i++) {
d["total"] += d[filterAir[i]];
}
});
var ndxAir = crossfilter(datasetAir);
var dateDimAir = ndxAir.dimension(function(d) {return d["date"];});
var total_pollutants = dateDimAir.group().reduceSum(function(d) {return d["total"];});
var datasetAir_formatted = total_pollutants.all();
yScaleAir.domain([0, d3.max(datasetAir_formatted, function(d) {return d["value"];})])
svgAir.selectAll("rect")
.data(datasetAir_formatted)
.enter()
.append("rect")
.attr("x", function(d) { return xScale(new Date(d["key"]));})
.attr("y",0)
.attr("width", (width-50)/datasetAir_formatted.length - barPadding)
.attr("height", function(d) {
return yScaleAir(d["value"]);
})
.attr("fill", "#FED40A")
.attr("transform", "translate(50,0)");
svgAir.append("g")
.attr("class","x axis")
.attr("transform", "translate(50," + (height+20) + ")")
.call(xAxis);
svgAir.append("g")
.attr("class", "y axis")
.attr("transform", "translate(30,0)")
.call(yAxisAir);
svgAir.append("text")
.text("Air Pollutant")
.attr("x", 650)
.attr("y", 90);
});
};
Is there any problem with my code that is causing this issue? Oh, and I'm using crossfilter as well to format my JSON data.

Related

Adding axes eats up my data

I'm following the D3 tutorial but adding the axis makes half of my data disappear and I don't understand why. I thought that maybe the axis is taking up the space that's meant for the data so I added an extra 10px to the transform property, but it doesn't make any difference.
var GIST = "https://gist.githubusercontent.com/charisseysabel/f8f48fbf11b8a1b0d62cbe2d6bdc2aa6/raw/2ead1537adb822fbd59a666afd5334d525480a13/nano-2017.tsv"
var width = 1000,
height = 550,
margin = {top: 20, right: 30, bottom: 30, left: 4};
var y = d3.scaleLinear()
.range([height, 0]);
var yScale = d3.scaleLinear()
.range([height, 0]);
var xScale = d3.scaleLinear()
.range([0, width]);
var xAxis = d3.axisLeft(yScale);
var yAxis = d3.axisBottom(xScale);
var chart = d3.select(".chart")
.attr("width", width)
.attr("height", height);
chart.append("g")
.attr("transform", "translate(10, 0)")
.call(xAxis);
chart.append("g")
.attr("transform", "translate(0, 540)")
.call(yAxis);
d3.tsv(GIST, type, function(error, data) {
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var barWidth = width / data.length;
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(" + ((i * barWidth) + 10) + ",0)"; }
);
bar.append("rect")
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", barWidth - 1);
bar.append("text")
.attr("x", (barWidth / 2) - 2)
.attr("y", function(d) { return y(d.value) + 3; })
.attr("dy", ".75em")
.text(function(d) { return d.value; });
});
function type(d) {
d.value = +d.value;
return d;
}
When you do this...
var bar = chart.selectAll("g").etc...
... you're selecting group elements that already exist in the SVG, which are the axes, and binding your data to them.
There are two easy solutions:
Move your code that creates the axes to the bottom of the d3.tsv, that is, after you have appended the bars.
Select something that doesn't exist, like
var bar = chart.selectAll(null).etc. To read more about the logic behind selectAll(null), have a look at my answer here.

Remove old points from line graph in d3

I am trying to create a multi-line graph and updating the data on button click. On each line, I want to highlight the intersection point with a cirlce. Now on button click, I was able to update the line path, but the old highlighted intersection points are not removed from the svgContainer(for eaxmple clicking update2 then update1 do not removes the last set of circles which are not connected to any line).
<input type="button" onclick="update1()" value="Update" />
<input type="button" onclick="update2()" value="UpdateDimension_T" />
<div id="outputViz">
</div>
<script type="text/javascript">
var data = [
[{'index':1,'score':0},{'index':2,'score':5},{'index':3,'score':10},{'index':4,'score':0},{'index':5,'score':6}],
[{'index':1,'score':1},{'index':2,'score':6},{'index':3,'score':11},{'index':4,'score':1},{'index':5,'score':7}],
[{'index':1,'score':2},{'index':2,'score':7},{'index':3,'score':12},{'index':4,'score':2},{'index':5,'score':8}],
[{'index':1,'score':3},{'index':2,'score':8},{'index':3,'score':13},{'index':4,'score':3},{'index':5,'score':9}],
[{'index':1,'score':4},{'index':2,'score':9},{'index':3,'score':14},{'index':4,'score':4},{'index':5,'score':10}]
];
var data_O = [
[{'index':1,'score':1},{'index':2,'score':6},{'index':3,'score':11},{'index':4,'score':1},{'index':5,'score':7},{'index':6,'score':12}],
[{'index':1,'score':2},{'index':2,'score':7},{'index':3,'score':12},{'index':4,'score':2},{'index':5,'score':8},{'index':6,'score':13}],
[{'index':1,'score':3},{'index':2,'score':8},{'index':3,'score':13},{'index':4,'score':3},{'index':5,'score':9},{'index':6,'score':14}],
[{'index':1,'score':4},{'index':2,'score':9},{'index':3,'score':14},{'index':4,'score':4},{'index':5,'score':10},{'index':6,'score':15}],
[{'index':1,'score':5},{'index':2,'score':10},{'index':3,'score':15},{'index':4,'score':5},{'index':5,'score':11},{'index':6,'score':16}]
];
var data_T = [
[{'index':1,'score':5},{'index':2,'score':10},{'index':3,'score':15},{'index':4,'score':5},{'index':5,'score':12},{'index':6,'score':20},{'index':7,'score':15}],
[{'index':1,'score':6},{'index':2,'score':11},{'index':3,'score':16},{'index':4,'score':6},{'index':5,'score':13},{'index':6,'score':21},{'index':7,'score':16}],
[{'index':1,'score':7},{'index':2,'score':12},{'index':3,'score':17},{'index':4,'score':7},{'index':5,'score':14},{'index':6,'score':22},{'index':7,'score':17}],
[{'index':1,'score':8},{'index':2,'score':13},{'index':3,'score':18},{'index':4,'score':8},{'index':5,'score':15},{'index':6,'score':23},{'index':7,'score':18}],
[{'index':1,'score':9},{'index':2,'score':14},{'index':3,'score':19},{'index':4,'score':9},{'index':5,'score':16},{'index':6,'score':24},{'index':7,'score':19}]
];
var colors = [
'steelblue',
'green',
'red',
'purple',
'black'
];
var dataset = ["","Or","Se","Tr","De","Cc"];
var dataset_O = ["","O_1","O_2","O_3","O_4","O_5","O_6"];
var dataset_T = ["","T_1","T_2","T_3","T_4","T_5","T_6","T_7"];
var margin = {top: 20, right: 30, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 30;
var x = d3.scale.linear()
.domain([0, dataset.length])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 16])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickFormat(function(d) { return dataset[d]; })
.tickSize(-height)
.tickPadding(10)
.tickSubdivide(false)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(false)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", (-margin.left) + 10)
.attr("x", -height/2)
.text('Axis Label');
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.index); })
.y(function(d) { return y(d.score); });
svg.selectAll('.line')
.data(data)
.enter()
.append("path")
.attr("class", "line")
.attr('stroke', function(d,i){
return colors[i%colors.length];
})
.attr("d", line);
var points = svg.selectAll('.dots')
.data(data)
.enter()
.append("g")
.attr("class", "dots")
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")"; }
);
function update1(){
var x = d3.scale.linear()
.domain([0, dataset_O.length])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 16])
.range([height, 0]).nice();
xAxis = d3.svg.axis()
.scale(x)
.tickFormat(function(d) { return dataset_O[d]; })
.tickSize(-height)
.tickPadding(10)
.tickSubdivide(false)
.orient("bottom");
yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(false)
.orient("left");
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.index); })
.y(function(d) { return y(d.score); });
svg.selectAll('.line')
.data(data_O)
.transition(750)
.attr("d", line)
.attr("class", "line");
// change the x axis
svg.select(".x.axis").call(xAxis);
// change the y axis
svg.select(".y.axis").call(yAxis);
var points = svg.selectAll('.dots').data(data_O);
//UPDATE - HANDLE the current count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
//ENTER - add the newly added count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
d3.selectAll('g.dots').data(data_O).exit().remove();
}
function update2(){
var x = d3.scale.linear()
.domain([0, dataset_T.length])
.range([0, width]);
//var yExtents = d3.extent(d3.merge(data_T), function (d) { return d.score; });
var y = d3.scale.linear()
.domain([-1, 29])
.range([height, 0]).nice();
xAxis = d3.svg.axis()
.scale(x)
.tickFormat(function(d) { return dataset_T[d]; });
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.index); })
.y(function(d) { return y(d.score); });
svg.selectAll('.line')
.data(data_T)
.transition(750)
.attr("d", line)
.attr("class", "line");
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
var points = svg.selectAll('.dots').data(data_T);
//ENTER - add the newly added count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
//UPDATE - HANDLE the current count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
}
</script>
Here is the link to fiddle:
https://jsfiddle.net/aakashjain/1dc57aL7/1/
You'll need an "exit" selection:
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.exit()
.remove();
Here is the update fiddle:. https://jsfiddle.net/1dc57aL7/2/
(Just a tip: you have a lot of duplicated code here. Your "update1" and "update2" functions could be way smaller)

Horizontal gradient in a bar chart

I have a bar chart.
function svg_render(data, svg) {
var node = d3.select(svg).append("svg")
.attr("class", "chart")
.attr("width", width)
.attr("height", height);
var y = d3.scale.linear().range([height, -height]);
var max_val = d3.max(data, function(d) {
return d;
});
y.domain([-max_val, max_val]);
var x = d3.scale.linear().domain([0, data.length]);
var bar_width = width / data.length;
var chart = node.attr("width", width).attr("height", height);
var bar = chart.selectAll("g")
.data(data)
.enter().append("g") // svg "group"
.attr("transform", function(d, i) {
return "translate(" + i * bar_width + ",0)";
});
bar.append("rect")
.attr("y", function(d) {
var yv = height - Math.abs(y(d) / 2) - height / 2 + 2;
return yv;
})
.attr("height", function(d) {
return Math.abs(y(d));
})
.attr("width", bar_width);
var axis = d3.svg.axis()
.scale(y)
.ticks(12)
.orient("left");
d3.select(".svg").append("svg")
.attr("class", "axis")
.attr("width", 60)
.attr("height", height)
.append("g")
.attr("transform", "translate(40," + (height / 2) + ")")
.call(axis);
}
would be great to be able to have a gradient towards the chart. An horizontal one.
Something like
Each bar can have a specific rgb code, but would be better if it was all calculated with a single gradient.
Also, bonus question, why i have that white lines as a border of my bars if i actually didn't specify any border at all (feels like aliasing svg issue)
So, i managed to achieve that by doing
var color = d3.scale.linear()
.domain([0, width])
.range(["hsl(62,100%,90%)", "hsl(222,30%,20%)"]);
And later on, for each bar element append
.style("fill", function(d, i) {
return color(i);
});
wonder if it's the fast way to do this

nvD3 : want to Create a DualAxisBarChart using NVD3

I want to create a DualAxisBarchart but kind of stuck. Tried many way but actually am able to create Two yAxis but instead to create two separate bar its creating two bar at the same place please suggest me some approach am creating this using multichart() function
I have not used nvd3, however I have created a dual axis bar chart using d3. In the code below I am assuming the variable height, x, svg are already defined. The only differences are the ranges for the upperY and lowerY functions and how the lowerBars y and height are defined. I really hope this helps
var upperY = d3.scale.linear().range([height / 2, 0]);
var lowerY = d3.scale.linear().range([height / 2, height]);
var upperYAxis = d3.svg.axis()
.scale(upperY)
.orient("left");
var lowerYAxis = d3.svg.axis()
.scale(lowerY)
.orient("left");
svg.append("g")
.attr("class", "y axis")
.call(upperYAxis);
svg.append("g")
.attr("class", "y2 axis")
.call(lowerYAxis);
var upperBars = svg.selectAll(".upperBar")
.data(upperBarData)
.enter()
.append("rect")
.attr("class", "upperBar")
.attr("x", function(d) { return x(d.index); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return upperY(d.value); })
.attr("height", function(d) { return height / 2 - upperY(d.value); });
var lowerBars = svg.selectAll(".lowerBar")
.data(lowerBarData)
.enter()
.append("rect")
.attr("class", "lowerBar")
.attr("x", function(d) { return x(d.index); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return height / 2; })
.attr("height", function(d) { return lowerY(d.value) - height / 2; });

How do we get nested json array values using D3JS

I'm new to D3JS, trying to use the nested json array to show the bar chart.Below is my json.
[
{
"image":"suresh.jpg",
"name":"Suresh",
"email":"abc#gmail.com",
"barValues":[
{
"letter":"A",
"frequency":".04253"
},
{
"letter":"B",
"frequency":".12702"
},
{
"letter":"C",
"frequency":".02288"
}
]
}
]
Below is my D3 code.
$scope.showDetails = function(relatedData) {
$http.get("searchInfo.json").success(function(response) {
var x = response;
$scope.data = [];
var searchT = relatedData;
var margin ={top:20, right:30, bottom:30, left:20},
width=360-margin.left- margin.right,
height=200-margin.top-margin.bottom;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
var y = d3.scale.linear().range([height, 0]);
var chart = d3.select("#chart")
.append("svg")
.attr("width", 600)
.attr("height", height+margin.top+margin.bottom);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
d3.json(searchT+'Details.json', function(error, data){
x.domain(data.map(function(d){ return d.letter}));
y.domain([0, d3.max(data, function(d){return d.frequency})]);
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i){
return "translate("+x(d.letter)+", 0)";
});
bar.append("rect")
.attr("y", function(d) {
return margin.top+margin.right;
})
.attr("x", function(d,i){
return x.rangeBand()+(margin.left/4);
})
.attr("height", function(d) {
return height - y(d.frequency);
})
.attr("width", 29);
bar.append("text")
.attr("x", x.rangeBand()+margin.left )
.attr("y", function(d) { return y(d.frequency) -10; })
.attr("dy", ".75em")
.text(function(d) { return d.frequency; });
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate("+margin.left+","+ height+")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.attr("transform", "translate("+margin.left+",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
});
});
};
}
I'm not able to get the X-axis and Y-axis values. I've tried in different ways but was not working.Could any one help me on this,Thanks.

Resources