In d3.js ticks are not showing in the x axis - d3.js

I am trying to show a barchart using d3.js. Y axis contains the speed and x axis contains time. I am using the following code:
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 400 - margin.left - margin.right,
height = 250 - margin.top;
var x = d3.scale.ordinal().rangeRoundBands([ 0, width ], .1);
var y = d3.scale.linear().range([ height, 0 ]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(20);
x.domain(data.map(function(d) { return d.datetime; }));
y.domain([0, d3.max(data, function(d) { return d.speed; })]);
var svg=d3.select("#bar").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 + ")");
var transition = svg.transition().duration(750), delay = function(d, i) {
return i * 50;
};
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" ).text("Time");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Speed");
svg.selectAll("rect")
.data(data)
.enter().append("rect").transition().delay(0)
.style("fill", "red")
.attr("x", function(d,i) { return 30*i+20; })
.attr("width", 25)
.attr("y", function(d) { return y(d.speed); })
.attr("height", function(d) { return height - y(d.speed); }); //function(d){return " "+d.datetime;}
transition.select(".y.axis").call(yAxis);
But unfortunately no ticks are showing in the x axis. Y axis ticks are working fine. Can anyone help me regarding this?

In your x-axis creation, this:
.attr("transform", "rotate(-90)" ).text("Time");
is just going to but the word "Time" on each tick. What you need is:
// define the time format you want
var format = d3.time.format("%Y-%m-%d");
// create x axis
...
.text(function(d){
return format(d);
});
Also in your rect placement:
svg.selectAll("rect")
...
.attr("x", function(d,i) { return 30*i+20; })
You are spacing them based on index. You need to match this to the axis position:
svg.selectAll("rect")
...
.attr("x", function(d, i) {
return x(d.datetime);
})
Here's an example.

Your problem may be where you set the domain for x:
x.domain(data.map(function(d) { return d.datetime; }));
You probably want something like:
x.domain([d3.min(data, function(d) { return d.datetime; }), d3.max(data, function(d) { return d.datetime; })]);

Related

Add labels to bar chart D3

I'm trying to add labels to my bar chart, and I can't make it work. I read a lot about it and tried many things already, but no success.
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y-%m");
var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m"));
var yAxis = d3.axisLeft(y)
.ticks(10);
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 + ")");
d3.csv("bar-data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.date); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) {
return d.value;
})
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("x", function(d, i) {
return i * (width / data.length);
})
.attr("y", function(d) {
return height - (d * 4);
});
});
Here is my Plunker.
Any help is appreciated. Thank you in advance.
You can add labels to the bars using the snippet below -
svg.selectAll(".text")
.data(data)
.enter()
.append("text")
.attr("class","label")
.attr("x", (function(d) { return x(d.date); } ))
.attr("y", function(d) { return y(d.value) - 20; })
.attr("dy", ".75em")
.text(function(d) { return d.value; });
Your problem was here. The correct approach to get x-y positions for the labels would be the same approach you used for the bars using the x and y variables.
.attr("x", function(d, i) {
return i * (width / data.length);
})
.attr("y", function(d) {
return height - (d * 4);
});
Updated Plunkr - https://plnkr.co/edit/e6HPuph3OSbpxeEVQXfF?p=preview

Change chart colors

I have a bar chart/histogram, all working fine.
I need to change the text and lines on the chart is on a black background.I
Also, the bar colors need to be orange.
I have had a look around the web, and seen some references to .attr("style":...); and have tried this without success.
Any pointers gratefully received.
<script>
// set the dimensions of the canvas
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 1890 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
// add the SVG element
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 + ")");
// load the data
d3.json("/assets/js/risk_hist_values.json", function(error, data) {
// the number of columns in this chart
var numCols = data.length;
data.forEach(function(d) {
d.Letter = d.bin_no;
d.Freq = +d.count;
});
// scale the range of the data
x.domain(data.map(function(d) { return d.Letter; }));
y.domain([0, d3.max(data, function(d) { return d.Freq; })]);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Count:</strong> <span style='color:red'>" + d.count + "</span>";
})
// call the tips
svg.call(tip);
// add axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Count");
// Add bar chart
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.Letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.Freq); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.on('click', drill)
.attr("id", function(d, i){ return 'b_'+i+''; })
.attr("height", function(d) { return height - y(d.Freq); });
});
function drill(){
alert( 'drilling' );
}
</script>

Limitting x and y axis ticks in bar graph with d3.js

I am developing bar graph using d3.js integrating with angular js.I am new to d3.js. I dont know how we can limt the the no.of x and y axis ticks.
The working is given below
mainApp.directive('ngTest', function() {
return {
restrict: 'AE',
scope: {
data: '='
},
link: function (scope, element) {
var margin = {top: 20, right: 30, bottom: 30, left: 60},
width = 410 - margin.left - margin.right,
height = 230 - margin.top - margin.bottom;
var chart = d3.select(element[0])
.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 + ")");
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:red'>" + d.value + "</span>";
});
chart.call(tip);
//Render graph based on 'data'
scope.render = function(data) {
var y = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(data, function(d) { return d.value; }))
.nice();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
x.domain(data.map(function(d) { return d.name; }));
//Redraw the axes
chart.selectAll('g.axis').remove();
chart.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(-20)";
});
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0-margin.left)
.attr("x",0-(height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Value");
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) { return d.value < 0 ? "bar negative" : "bar positive"; })
.attr("x", function(d) { return x(d.name); })
.attr("y", height)
.attr("height", 0)
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.transition().duration(2000)
.attr("y", function(d) {return y(Math.max(0, d.value)); })
.attr("height", function(d) {return Math.abs(y(d.value) - y(0)); })
// .attr("width", x.rangeBand());
.attr("width", Math.min.apply(null, [x.rangeBand()-2, 100]));
};
scope.$watch('data', function() {
scope.render(scope.data);
}, true);
}
};
});
The working example is given in following fiddle adderss
http://jsfiddle.net/HB7LU/9000/
Use ticks method of d3 axis. Since tick format of x axis is time, you might specify both a count and a tick format.
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(d3.time.day, 2);
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(5);
You can refer more about d3 svg axis from here and about time formats from here

d3.js line chart with negative numbers

I have a working d3.js line chart that renders linear numbers: http://jsfiddle.net/2g9VQ/
var probArray = ["1.0", "0.999999931839", "0.999816434171", "0.994147880224", "0.961785353466", "0.882923015661", "0.763731336472", "0.627901360001", "0.497594590727", "0.385100568858", "0.256161790111", "0.168894610653", "0.111773057", "0.0747467808441", "0.051065424573", "0.0355360834346", "0.0251527408762", "0.018097770"];
var imlArray = ["2.0", "4.0", "6.0", "8.0", "10.0", "12.0", "14.0", "16.0", "18.0", "20.0", "23.0", "26.0", "29.0", "32.0", "35.0", "38.0", "41.0", "44.0", "47.0", "50.0", "55.0", "60.0", "65.0", "70.0", "75.0", "80.0", "85.0", "90.0", "95.0", "100.0", "110.0", "120.0", "130.0", "140.0", "150.0", "160.0", "170.0", "180.0", "190.0", "200.0", "220.0", "240.0", "260.0", "280.0", "300.0"];
function log(n) {
return Math.log(n) / Math.LN10;
}
var data = [];
for(i=0; i<probArray.length; i++) {
// without log values...
data.push([parseFloat(imlArray[i]), parseFloat(probArray[i])]);
// with log valuse...
//data.push([log(parseFloat(imlArray[i])), log(parseFloat(probArray[i]))]);
}
console.log(data);
var margin = {top: 20, right: 20, bottom: 50, left: 50},
width = 400 - margin.left - margin.right,
height = 320 - margin.top - margin.bottom;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); });
var svg = d3.select("#dialog").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 + ")");
var dataCallback = function(d) {
d.x = +d[0];
d.y = +d[1];
};
data.forEach(dataCallback);
x.domain(d3.extent(data, function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", line);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", 160)
.attr("y", 30)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Intensity measure type");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -50)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Probabability of exceedance in "+invest_time+" years");
var legend = d3.select("#dialog").append("svg");
legend.append("text")
.attr("x", 20)
.attr("y", 7)
.attr("dy", ".35em")
.text("Location (Lon/Lat): "+lng+", "+lat);
d3.select('#chart').on("click", function() {
data.splice(0,1);
data.push([5,5]);
dataCallback(data[data.length - 1]);
x.domain(d3.extent(data, function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);
svg.selectAll("path").data([data])
.attr("d", line);
});
But the chart fails to render when I change the points to a logarithmic scale: http://jsfiddle.net/Z3Yms/
var probArray = ["1.0", "0.999999931839", "0.999816434171", "0.994147880224", "0.961785353466", "0.882923015661", "0.763731336472", "0.627901360001", "0.497594590727", "0.385100568858", "0.256161790111", "0.168894610653", "0.111773057", "0.0747467808441", "0.051065424573", "0.0355360834346", "0.0251527408762", "0.018097770"];
var imlArray = ["2.0", "4.0", "6.0", "8.0", "10.0", "12.0", "14.0", "16.0", "18.0", "20.0", "23.0", "26.0", "29.0", "32.0", "35.0", "38.0", "41.0", "44.0", "47.0", "50.0", "55.0", "60.0", "65.0", "70.0", "75.0", "80.0", "85.0", "90.0", "95.0", "100.0", "110.0", "120.0", "130.0", "140.0", "150.0", "160.0", "170.0", "180.0", "190.0", "200.0", "220.0", "240.0", "260.0", "280.0", "300.0"];
function log(n) {
return Math.log(n) / Math.LN10;
}
var data = [];
for(i=0; i<probArray.length; i++) {
// without log values...
//data.push([parseFloat(imlArray[i]), parseFloat(probArray[i])]);
// with log valuse...
data.push([log(parseFloat(imlArray[i])), log(parseFloat(probArray[i]))]);
}
console.log(data);
var margin = {top: 20, right: 20, bottom: 50, left: 50},
width = 400 - margin.left - margin.right,
height = 320 - margin.top - margin.bottom;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); });
var svg = d3.select("#dialog").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 + ")");
var dataCallback = function(d) {
d.x = +d[0];
d.y = +d[1];
};
data.forEach(dataCallback);
x.domain(d3.extent(data, function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", line);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", 160)
.attr("y", 30)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Intensity measure type");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -50)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Probabability of exceedance in "+invest_time+" years");
var legend = d3.select("#dialog").append("svg");
legend.append("text")
.attr("x", 20)
.attr("y", 7)
.attr("dy", ".35em")
.text("Location (Lon/Lat): "+lng+", "+lat);
d3.select('#chart').on("click", function() {
data.splice(0,1);
data.push([5,5]);
dataCallback(data[data.length - 1]);
x.domain(d3.extent(data, function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);
svg.selectAll("path").data([data])
.attr("d", line);
});
I believe this is due to the numbers becoming negative along the y axis.
You were setting the domain of the y axis as
y.domain([0, d3.max(data, function(d) { return d.y; })]);
which with the log values won't work because all values are less than 0. To fix, simply use
y.domain(d3.extent(data, function(d) { return d.y; }));
instead. You also might want to use a linear scale instead of a time scale for the x axis. Complete jsfiddle here.

how to add tooltip bar chart d3.js

I want to print the value of the data in a bar chart on top of the bar ... like if the count of population in 2012 was say 20000124 then on top of the bar at 2012 it should print 20000124.
how do i do that?
this is i worote the code to print bar chart..
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 220 - margin.left - margin.right,
height = 220 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.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 + ")");
d3.tsv("data/bar2.tsv", function(error, data) {
data.forEach(function(d) {
d.frequency = +d.frequency;
});
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, 100]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); })
.text(function(d) { return d.letter});
});
so basically how do i add a label on top of every bar ?
You can add the label to the bars by appending text elements after the rectangles. Something along the lines of
var sel = svg.selectAll(".bar")
.data(data).enter();
sel.append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
sel.append("text")
.attr("x", function(d) { return x(d.letter); })
.attr("y", function(d) { return y(d.frequency); })
.text(function(d) { return d.letter});
You might want to tweak the position of the text to your liking.

Resources