d3js add volume bars to line graph - d3.js

I built this line graph with d3js: jsfiddle
Example Data:
{
date: '18-May-18',
close: 281755783529,
volume: 11792035643,
notes: null
}
How can I use the "volume" value from data to plot a rectangle bar corresponding to each date? The line graph with volume bars would look something like this:
Thank you!

Because the volume uses a different Y-range you need to define a new yScale for that
var yVolume = d3.scaleLinear().range([height, 0]);
yVolume.domain([0, d3.max(data, function(d) { return d.volume; })]);
Draw a right axis for this scale
var yAxisVol = d3.axisRight(yVolume).ticks(10);
svg.append("g")
.attr("class", "yaxisVol")
.attr("transform", `translate(${width},0)`)
.call(yAxisVol);
Then draw the rect on the correct location
svg.append("g").attr("class", "barsVol")
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("fill", "yellow")
.attr("x", function(d) { return x(new Date(d.date.getTime()-11*60*60*1000)); })
.attr("y", function(d) { return yVolume(d.volume); })
.attr("height", function(d) { return height - yVolume(d.volume); })
.attr("width", function(d) {
return x(new Date(d.date.getTime()+11*60*60*1000)) -
x(new Date(d.date.getTime()-11*60*60*1000)); });
The rectangles have a width of 1 "day" (22 hours).
Add a clip rectangle to the barsVol group or extend the x-domain with a day on the left and right.

Related

in d3js bar chart i want to have fixed bar width

http://bl.ocks.org/d3noob/8952219
I want to have bar size width to be fixed..
from above example i have changed the code from
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
to
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.date); })
.attr("width", 50)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
but the labels are not moving to proper place also bars are getting overlapped
You have to change the range() of your x scale, to fit with your bar width value:
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
to (if you want 50px as bar width)
var x = d3.scale.ordinal().range([0, data.length * 50]);
The range() method is used to define the display space for your scale.
I was looking for a similar solution. What #JulCh gave as an answer did not work out of the box for me, but lead me in the right direction.
Try:
var x = d3.scale.ordinal()
.range(d3.range(data.length).map(function (d) { return d * 50; }));
Where the inner d3.range creates an array containing the number of elements determined by data.length or some constant number (the number of bars you would like displayed).
Example: If data.length or some constant is 8 then [0,1,2,3,4,5,6,7] is returned from d3.range(8)
The map function then multiplies your fixed width of 50 against each element in the array returning [0,50,100,150,200,250,300,350].
D3 will then use these exact values to place your bars.

Why point closeness is differing from scatter plot to hexbin plot?

Please look at Hexbin and scatterplots: http://imgur.com/a/2oR68
Why in Hexbinplot, points donot touch each other whereas in scatterplot it clearly touches the close points ?
I expected my hexbin plot comes up like this: https://bl.ocks.org/mbostock/4248145 but it didnot.
I am using d3.hexbin plugin.
The only code that is differing from Hexbin plot to scatter plot (I am dealing with same dataset) apart from little bit of scaling is:
For Hexbin:
var color = d3.scale.linear()
.range(["white", "steelblue"])
.interpolate(d3.interpolateLab);
var hexbin = d3.hexbin()
.extent([[0,0],[size - padding , padding]])
.radius();
hexbin.x(function(d,i){return x(subdata[0][i]);})
hexbin.y(function(d,i){return y(subdata[0][i]);})
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("class", "mesh")
.attr("width", w)
.attr("height", size);
svg.append("g")
.attr("clip-path", "url(#clip)")
.selectAll(".hexagon")
.data(hexbin(datum))
.enter()
.append("path")
.attr("class", "hexagon")
.attr("d", hexbin.hexagon())
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style("fill", function(d) { return color(d.length); });
For scatterplot:
svg.selectAll("circle")
.data(datum)
.enter()
.append("circle")
.style("fill", "steelblue")
.attr("cx", function (d, i) {
return x(subdata[0][i]);
})
.attr("cy", function (d,i) {
return y(subdata[0][i]);
})
.attr("r", 3)
Where am i doing wrong ?
Edit1: Included some fraction of code under Hexbin
If you set...
.attr("d", hexbin.hexagon(5))
//radius value here ------^
..., the hexagons will touch only if you set the same value in the hexabin generator:
var hexbin = d3.hexbin()
.radius(5)//same value here
.extent([[0, 0], [width, height]]);
According to your result, I believe that was not the case. Thus, the solution can be simply removing that value:
.attr("d", hexbin.hexagon())
//no radius here --------^

dataset created with d3.nest isn't drawing correctly

I am trying to visualize a dataset to see major players in the pangolin trade. I want each country to be part of a categorical scale on the y-axis, and the x-axis is the date, and I want each trade instance to be represented as a circle, with x being the date it happened, y being the position for that particular country, and r being the number of instances accumulated so far (represented in my data as r). Basically my data is from 2010 to 2016, and includes the country name where pangolins are either imported to or exported from, the count (accumulated trade instances up until this date), and the date (yyyy-mm-dd).
Below is part of my data, which I store in the variable trade:
[{"date":"2010-10-22","country":"Thailand","rank":4,"count":1},{"date":"2010-10-28","country":"Malaysia","rank":2,"count":1},{"date":"2010-11-8","country":"Thailand","rank":4,"count":2},{"date":"2010-11-18","country":"Nepal","rank":7,"count":1},{"date":"2010-11-22","country":"China","rank":5,"count":1},{"date":"2010-11-22","country":"China","rank":5,"count":2},{"date":"2010-11-27","country":"India","rank":1,"count":1},{"date":"2010-11-28","country":"India","rank":1,"count":2},{"date":"2010-11-28","country":"India","rank":1,"count":3},{"date":"2010-11-30","country":"India","rank":1,"count":4},{"date":"2010-12-17","country":"Malaysia","rank":2,"count":2},{"date":"2010-12-22","country":"Vietnam","rank":3,"count":1},{"date":"2011-01-3","country":"Nepal","rank":7,"count":2},{"date":"2011-02-12","country":"Myanmar","rank":8,"count":1},{"date":"2011-02-25","country":"Malaysia","rank":2,"count":3},{"date":"2011-02-26","country":"Malaysia","rank":2,"count":4},{"date":"2011-03-2","country":"South Africa","rank":18,"count":1},{"date":"2011-03-2","country":"Rwanda","rank":35,"count":1},{"date":"2011-03-2","country":"Mozambique","rank":22,"count":1},{"date":"2011-03-2","country":"Kenya","rank":12,"count":1},{"date":"2011-03-3","country":"China","rank":5,"count":3},{"date":"2011-02-21","country":"Vietnam","rank":3,"count":2},{"date":"2011-03-24","country":"Malaysia","rank":2,"count":5},{"date":"2011-04-4","country":"Malaysia","rank":2,"count":6},{"date":"2011-03-25","country":"India","rank":1,"count":5},{"date":"2011-03-26","country":"Malaysia","rank":2,"count":7},{"date":"2011-04-2","country":"Nepal","rank":7,"count":3},{"date":"2011-04-20","country":"Thailand","rank":4,"count":3},{"date":"2011-05-11","country":"China","rank":5,"count":4},{"date":"2011-05-11","country":"China","rank":5,"count":5},{"date":"2011-05-26","country":"Indonesia","rank":6,"count":1},{"date":"2011-05-26","country":"India","rank":1,"count":6},{"date":"2011-05-29","country":"Indonesia","rank":6,"count":2},{"date":"2011-06-6","country":"India","rank":1,"count":7},{"date":"2011-06-7","country":"Mozambique","rank":22,"count":2},{"date":"2011-06-5","country":"India","rank":1,"count":8},{"date":"2011-06-12","country":"Malaysia","rank":2,"count":8},{"date":"2011-06-13","country":"Singapore","rank":21,"count":1},{"date":"2011-06-14","country":"Malaysia","rank":2,"count":9},{"date":"2011-06-17","country":"India","rank":1,"count":9},{"date":"2011-06-19","country":"India","rank":1,"count":10},{"date":"2011-06-26","country":"Thailand","rank":4,"count":4},{"date":"2011-06-30","country":"India","rank":1,"count":11},{"date":"2011-07-4","country":"Malaysia","rank":2,"count":10},{"date":"2011-07-5","country":"Zimbabwe","rank":14,"count":1},{"date":"2011-07-12","country":"Indonesia","rank":6,"count":3},{"date":"2011-07-18","country":"Indonesia","rank":6,"count":4},{"date":"2011-07-27","country":"Nepal","rank":7,"count":4},{"date":"2011-08-16","country":"Nepal","rank":7,"count":5},{"date":"2011-08-19","country":"Namibia","rank":33,"count":1},{"date":"2011-08-23","country":"India","rank":1,"count":12},{"date":"2010-09-17","country":"Myanmar","rank":8,"count":2},{"date":"2011-09-1","country":"Zimbabwe","rank":14,"count":2},{"date":"2011-09-13","country":"Indonesia","rank":6,"count":5},{"date":"2011-09-13","country":"Malaysia","rank":2,"count":11},{"date":"2011-09-13","country":"Myanmar","rank":8,"count":3},{"date":"2011-09-21","country":"Malaysia","rank":2,"count":12},{"date":"2011-09-26","country":"Thailand","rank":4,"count":5},{"date":"2011-09-30","country":"Indonesia","rank":6,"count":6},{"date":"2011-10-1","country":"Sri Lanka","rank":19,"count":1},{"date":"2011-10-6","country":"India","rank":1,"count":13},{"date":"2011-10-7","country":"India","rank":1,"count":14},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":7},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":8},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":9},{"date":"2011-10-22","country":"India","rank":1,"count":15},{"date":"2011-10-24","country":"India","rank":1,"count":16},{"date":"2011-11-28","country":"United States","rank":32,"count":1},{"date":"2011-12-15","country":"Vietnam","rank":3,"count":3},{"date":"2011-12-27","country":"Thailand","rank":4,"count":6},{"date":"2012-01-4","country":"Philippines","rank":15,"count":1},{"date":"2012-01-5","country":"Kenya","rank":12,"count":2},{"date":"2012-01-6","country":"Philippines","rank":15,"count":2},{"date":"2012-01-17","country":"Philippines","rank":15,"count":3},{"date":"2012-01-24","country":"China","rank":5,"count":6},{"date":"2012-02-22","country":"Malaysia","rank":2,"count":13},{"date":"2012-03-1","country":"Malaysia","rank":2,"count":14},{"date":"2012-03-19","country":"Pakistan","rank":11,"count":1},{"date":"2012-03-21","country":"Malaysia","rank":2,"count":15},{"date":"2012-03-23","country":"Vietnam","rank":3,"count":4},{"date":"2012-04-27","country":"Vietnam","rank":3,"count":5},{"date":"2012-04-23","country":"Belgium","rank":31,"count":1},{"date":"2012-06-7","country":"Thailand","rank":4,"count":7},{"date":"2012-06-7","country":"Thailand","rank":4,"count":8}];
and here is my code:
var margin = {left:120, top:20, right:0, bottom:50};
var width = 1000;
var height = 800;
var data=trade;
var tradeByCountry = d3.nest()
.key(function(d) { return d.country; })
.entries(trade);
console.log(tradeByCountry);
tradeByCountry.forEach(function(country){
country['number']=country.values.length;
console.log(country);
});
var country_colors = ["#393b79","#5254a3", '#6b6ecf', '#9c9ede', '#637939', '#8ca252','#b5cf6b','#cedb9c',
'#8c6d31','#bd9e39','#e7ba52','#e7cb94','#843c39','#ad494a','#d6616b','#e7969c','#7b4173','#a55194',
'#ce6dbd','#de9ed6', '#9467bd', '#c5b0d5','#3182bd', '#6baed6','#17becf','#9edae5','#e6550d','#fd8d3c','#fdae6b',
'#31a354','#74c476','#a1d99b','#d62728','#ff9896','#7f7f7f','#c7c7c7'];
var colors = d3.scale.ordinal()
.domain(d3.range(tradeByCountry.length))
.range(country_colors);
tradeByCountry.sort(function(x, y){
return d3.descending(x.number, y.number);
})
var countriesArray = [];
tradeByCountry.forEach(function(country){
countriesArray.push(country.key);
});
console.log(countriesArray);
var x = d3.time.scale()
.rangeRound([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var timeFormat = d3.time.format("%Y-%m-%d");
x.domain([timeFormat.parse('2010-10-22'),timeFormat.parse('2016-12-30')]);
y.domain(countriesArray);
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 + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("date");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "translate(35,-25)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("countries");
svg.selectAll(".dot")
.data(tradeByCountry)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 7)
.attr("cx", function(d) { return 0; })
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("fill", function(d,i) { return colors(i); });
svg.selectAll("text.labels")
.data(tradeByCountry)
.enter()
.append("text")
.text(function(d) {return d.key})
.attr("x", 0)
.attr("y", function(d,i) { return (height/tradeByCountry.length)*i; })
.attr("transform", "translate(-120,5)")
.attr("fill",function(d,i) { return colors(i); });
svg.selectAll('.line')
.data(tradeByCountry)
.enter().append('line')
.attr("x1", 0) // x position of the first end of the line
.attr("y1",function(d,i) { return (height/tradeByCountry.length)*i; })
.attr("x2", width) // x position of the second end of the line
.attr("y2", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("stroke",function(d,i) { return colors(i); })
.attr("id", function(d){return d.key});
//PROBLEM HERE!!!!!!!!!!!
var g = svg
.selectAll("g")
.data(tradeByCountry)
.enter().append("g")
.selectAll(".dot")
.data(function(d) {return d.values;})
.enter().append("circle")
.attr("id", function(d){ return d.count;})
.attr("r", function(d){return d.count;})
.attr("cx", function(d,i) { console.log (d.date);return (x(timeFormat.parse(d.date))); })
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("fill", function(d,i) { return colors(i); });
I am having trouble specifically at the very last part of my code, where I can't get all the circles to draw and not in the correct r, as I would like r to increase as the trade accumulates over time for a country, instead it seems that r is different according to country:
Two things, firstly in your example .selectAll("g") at the point you mark as having the error was picking up g elements in the axes, so the first few countries weren't getting their data displayed. This doesn't appear to be the case in your screenshot but it was happening given the code you posted, so I just qualified those gs with the .country class.
The second thing, and what was causing your specific problem was this line:
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
I'm guessing you thought the index variable i here was still tied to the tradeByCountry array, which it would have been after selectAll("g.country").data(tradebyCountry) but at this point we've now made a nested selection .selectAll(".dot") on d.values for each country's data so i is now indexing those list of values. So that line of code above will take the values for each country and separate them all vertically, always starting from the top row - when in fact you want them on the same line, just separated by country.
What you wanted (I = India, M = Malaysia, T = Thailand)
I--- I0 I1 I2
M--- M0M1 M2
T--- T0 T1 T2
What you were getting
I--- I0 M0 T0
M--- M1 I1 T1
T--- I2 T2 M2
This was also hidden by the fact .attr("fill") also had the same mistake so the colours on each row were consistent (I've used d.rank instead to fix it).
Solution 1: To make sure the values stay on the same correct line use i before you do the nested selection so it still refers to the countries like this, which will offset each g element by the correct amount:
.attr("transform", function(d,i) {
return "translate(0,"+(height/tradeByCountry.length)*i+")";
})
and simply set cy to be zero for everything you add to this g element and they'll all be in a straight line (and on the right line)
Full code at the PROBLEM HERE! stage:
var g = svg
.selectAll("g.country")
.data(tradeByCountry)
.enter().append("g")
.attr("class", "country")
.attr("transform", function(d,i) {
return "translate(0,"+(height/tradeByCountry.length)*i+")";
})
.selectAll(".dot")
.data(function(d) {return d.values;})
.enter().append("circle")
.attr("class", "dot")
.attr("id", function(d){ return d.country+"_"+d.date+"_"+d.count;})
.attr("r", function(d){ return d.count;})
.attr("cx", function(d,i) { console.log (d.date);return (x(timeFormat.parse(d.date))); })
.attr("cy", function(d,i) { return 0; })
.style("fill", function(d,i) { return colors(d.rank); });
http://jsfiddle.net/d4typ567/1/
Solution 2: It's also the case that d3 maintains a parent index variable for nested selections (usually denoted ii) that can be passed into most d3 .attr and .style functions, so you could do .attr("cy", function(d,i, ii) { return (height/tradeByCountry.length)*ii; }) instead, but offsetting the g element is only 1 operation whereas this is done for every circle. Remember to do the same for the color (fill) function.

While creating a bar graph using d3 how to associate the bar height with the numbers on the scale?

When creating a bar graph with data for both the axis in d3.js, how do I link the position and height of the bar with the numbers on the axes?
no point adding new libraries as mentioned in the comments. Just scale your width and height of your bars with your axis.
Simple example : http://bl.ocks.org/d3noob/8952219
Notice these lines of code :
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
He is passing the number he wants to use as the height (d.value) to the y scale. That way the labels on the axis coincide to the height of the bars

D3 vertical line graph

I have a line (& area) graph which works ok, when horizontal. But I really need it to be vertical, to stand up. I have tried all kinds of changes to the existing code. Mostly with some strange results.
Here’s the code (modified it a bit). Is there a way to change it to make the graph vertical?:
var x = d3.scale.linear().domain([1, itemCount]).range([0, width]);
var y = d3.scale.linear().domain([0, maxValue]).rangeRound([height, 0]);
// Set up linar x and y axis.
var xAxis = d3.svg.axis().scale(x).ticks(10);
var yAxis = d3.svg.axis().scale(y).ticks(2).orient("left");
// Line graph.
line = d3.svg.line()
.interpolate("basis")
.x(function (d) {
return x(d.x);
})
.y(function (d) {
return y(d.y);
});
// Create SVG element.
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// X-Axis, to bottom.
svg.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(1," + height + ")")
.call(xAxis);
//Y-Axis
svg.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(40, 1)")
.call(yAxis);
// Horizontal axis guide lines.
svg.selectAll("line.y")
.data(y.ticks(5))
.enter()
.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", y)
.attr("y2", y)
.style("stroke", "#000000")
.style("stroke-opacity", 0.1);
// Vertical axis guide lines.
svg.selectAll("line.x")
.data(y.ticks(5))
.enter()
.append("line")
.attr("x1", x)
.attr("x2", x)
.attr("y1", 0)
.attr("y2", this.heightInside - pushDown)
.style("stroke", "#000000")
.style("stroke-opacity", 0.1);
// Set up domains. Nice ensures the domains ends on nice round values.
x.domain([dataValues[0].x, dataValues[dataValues.length - 1].x]).nice();
y.domain([d3.min(dataValues, function (d) { return (d.y); }),
d3.max(dataValues, function (d) { return (d.y); })])
.nice();
// Draw line on graph.
svg.append("svg:path")
.attr("class", "line")
.attr("d", line(dataValues))
.style("stroke", function(d) { return colors[i]; });
// Marks.
svg.selectAll("circle_" + i)
.data(dataValues)
.enter()
.append("circle")
.style("fill", function(d) { return _this.colors[i]; })
.attr("r", 4)
.attr('cx', function (d) { return x(d.x); })
.attr('cy', function (d) { return y(d.y); });

Resources