D3 - Vertical axis is not displaying correctly - d3.js

I have a CSV file containing the French population by department. I can correctly display a map colored with population density but I encounter problems with the associated legend.
You can see the current result here: http://i.stack.imgur.com/Y26JT.jpg
After loading the CSV, here is my code to add the legend :
legend = svg.append('g')
.attr('transform', 'translate(525, 150)')
.attr('id', 'legend');
legend.selectAll('.colorbar')
.data(d3.range(9))
.enter().append('svg:rect')
.attr('y', function(d) { return d * 20 + 'px'; })
.attr('height', '20px')
.attr('width', '20px')
.attr('x', '0px')
.attr("class", function(d) { return "q" + d + "-9"; })
.attr('stroke', 'none');
legendScale = d3.scale.linear()
.domain([0, d3.max(csv, function(e) { return +e.POP; })])
.range([0, 9 * 20]);
legendAxis = d3.svg.axis()
.scale(legendScale)
.orient('right')
.tickSize(1);
legendLabels = svg.append('g')
.attr('transform', 'translate(550, 150)')
.attr('class', 'y axis')
.call(legendAxis);
Colors are obtain using ColorBrewer CSS (https://github.com/mbostock/d3/tree/master/lib/colorbrewer)
I have two problems:
The Hyphen '-' (a SVG line) is not displayed for each value of my axis
I cannot choose the number of values in my axis, I would like one at the beginning of each color block.
Thanks in advance for any help.

The reason your solution isn't showing the 'hyphen' (svg lines) is because you have the tickSize set very small. Try not setting it and it will default to 6 (according to the API docs - https://github.com/mbostock/d3/wiki/SVG-Axes).
To choose the number of values in your axis, you can add a call to ".ticks(N)", where N is the number of ticks you want. D3 will try to show that many ticks. You could also call ".tickValues([...])" and pass in the exact array of values to use for the ticks.
Here's a JSFiddle that corrects the issues in your example: http://jsfiddle.net/TRkGK/3/
And a sample of the part that fixes your issues:
var legendAxis = d3.svg.axis()
.scale(legendScale)
.orient('right')
.tickSize(6) // Tick size controls the width of the svg lines used as ticks
.ticks(9); // This tells it to 'try' to use 9 ticks
UPDATED:
You also want to make sure you're setting the CSS correctly. Here's what I use:
.y.axis line { stroke: #ccc; }
.y.axis path { display: none; }
In your example, when you add the larger tickSize, you are seeing the path in which the tick lines are defined. If you hide the path and give the lines a color, you'll see the ticks rather than the area in which the ticks are defined.
Hope this helps!

It looks like it could be a css issue, did you look at reblace's css in his fiddle?

Related

Adding a y axis horizonal line to a D3 scatter chart

I have created a scatter chart in D3 using images and now need to add a horizonal line to the chart based on the value of the "yave" field from my dataset which equals 5
I have added the following script that I know has worked in previous assignments but now I can't seem to align it to the y-axis:
//y-average-line
var yaveline = function(d) {
return data[0].yave;
}
var line = svg.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", yaveline)
.attr("y2", yaveline)
.attr("stroke-width", 1)
.attr("stroke", "black")
.attr("stroke-dasharray", "3,3");
A line is created but it appears near the top of the y-axis rather than at y = 5
Any ideas would be greatly appreciated. My fiddle is here
It appears at the top because the 5 is interpreted by the SVG as pixel coordinates, so it is at pixel y=5 (SVG counts from top to bottom). In your case, the 5 is not in pixel space, but in data space. To convert from the data space to the pixel space you have to use the yScale, the same way you do with the circles on the scatterplot:
var yaveline = function(d) {
return yScale(data[0].yave);
}
This will convert data[0].yave from data to pixel, that is, it will return the pixel that is associated with the data value.

Putting tspan inside rectangle D3JS SVG

i'm working in projet of data visualization using D3JS.
i have to put some information inside a rectangle, and i did that using wrap function to split the content, no i'm looking to put each line (tspan) inside a rectangle. and i don't know how to do that, any help is appreciated for me.enter image description here
the small rectangles will contain informations. does any one have an example how to that. thakns
there!
Actually, what you need to do is set right position for groups.
var data = [0,1,2,3,4]; // example data
var selection = svg.selectAll('g').data(data).enter();
// set position for rects and texts using transform-translate
var groups = selection.append('g')
.attr('transform', function(d, i) { return 'translate(0,' + i * 35 + ')' });
groups.append('rect')
.attr('width', 100)
.attr('height', 30)
.attr('fill', 'white')
.attr('stroke', 'black'); // all rects
groups.append('text')
.text((d) => d)
.attr('font-size', '10px')
.attr('y', 15); // all texts
And an additional link for you, maybe it would be helpful.

D3 v4 - make a horizontal bar chart with fixed width

I have made a horizontal bar chart using d3 v4, which works fine except for one thing. I am not able to make the bar height fixed. I am using bandwidth() currently and if i replace it with a fixed value say (15) the problem is that it does not align with the y axis label/tick http://jsbin.com/gigesi/3/edit?html,css,js,output
var w = 200;
var h = 400;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h)
.attr("transform", "translate(80,30)");
var data = [
{Item: "Item 1", count: "11"},
{Item: "Item 2", count: "14"},
{Item: "Item 3", count: "10"},
{Item: "Item 4", count: "14"}
];
var xScale = d3.scaleLinear()
.rangeRound([0,w])
.domain([0, d3.max(data, function(d) {
return d.count;
})]);
var yScale = d3.scaleBand()
.rangeRound([h,0]).padding(0.2)
.domain(data.map(function(d) {
return d.Item;
}));
var yAxis = d3.axisLeft(yScale);
svg.append('g')
.attr('class','axis')
.call(yAxis);
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('width', function(d,i) {
return xScale(d.count);
})
.attr('height', yScale.bandwidth())
.attr('y', function(d, i) {
return yScale(d.Item);
}).attr("fill","#000");
The y axis seemed to be off SVG in the link you provided. (Maybe you have overflow: visible; for the SVG.
Anyway, I've added a few margins to the chart so that the whole chart is visible. Here it is (ignore the link description):
DEMO: H BAR CHART WITH HEIGHT POSITIONING TO THE TICKS
Relevant code changes:
As you are using a scale band, the height is computed within. You just need to use .bandWidth().
.attr('height', yScale.bandwidth())
Added a margin and transformed the axis and the bars to make the whole chart visible :
: I'm assigning margins so that the y-axis is within the viewport of the SVG which makes it easier to adjust the left margin based on the tick value as well. And I think this should be a standard practice.
Also, if you notice, the rects i.e. bars are now a part of <g class="bars"></g>. Inspect the DOM if you'd like. This would be useful for complex charts with a LOT of elements but it's always a good practice.
var margin = {top: 10, left: 40, right: 30, bottom: 10};
var xScale = d3.scaleLinear()
.rangeRound([0,w-margin.left-margin.right])
var yScale = d3.scaleBand()
.rangeRound([h-margin.top-margin.bottom,0]).padding(0.2)
svg.append('g')
.attr('class','axis')
.attr('transform', 'translate(' + margin.left+', '+margin.top+')')
Try changing the data and the bar height will adjust and align according to the ticks. Hope this helps. Let me know if you have any questions.
EDIT:
Initially, I thought you were facing a problem placing the bars at the center of the y tick but as you said you needed fixed height bars, here's a quick addition to the above code that lets you do that. I'll add another approach using the padding (inner and outer) sometime soon.
Updated JS BIN
To position the bar exactly at the position of the axis tick, I'm moving the bar from top to the scale's bandwidth that is calculated by .bandWidth() which will the position it starting right from the tick and now subtracting half of the desired height half from it so that the center of the bar matches the tick y. Hope this explains.
.attr('height', 15)
.attr('transform', 'translate(0, '+(yScale.bandwidth()/2-7.5)+')')

nvd3 multiBarChart with line along x axis

I need to add a line with multiple values along the x axis of a multiBarChart. I cannot use another nvd3 control like multiChart or linePlusBarChart due to existing functionality breaking if i switch.
The following code and fiddle show what i have so far.
var limits = [[60,166990904656],[300,154990904656],[500,142990904656]];
var lineFunction = d3.svg.line()
.x(function(d) { return d[0] })
.y(function(d) {
d = d[1] / 1000000000;
return d
}).interpolate('step-after');
//The line SVG Path we draw
d3.select("#chart svg")
.append("path")
.attr("d", lineFunction(limits))
.attr("stroke", "red")
.attr("stroke-width", 1)
.attr("fill", "none");
https://jsfiddle.net/s2vemzht/11/
I am facing 3 issues: First is the x axis placement of the line. At the moment i have hardcoded this value into the limits array because i am unsure how to position it dynamically based on where the next bar starts.
The second issue is the limit value in relation to the other values in the data array. It does not seem accurately positioned.
The third issue is with the line not drawing over the 3rd bar even though there are 3 values in the limits array. I tried changing the interpolate property but it's still an issue.
I am a beginner with D3 so apologies for all the questions :-)
I managed to figure it out by drawing lines over the bars at particular points and positioning based on the y and x axis scales
var yValueScale = chart.yAxis.scale(),
yValue = 0,
xValueScale = chart.xAxis.scale(),
g = d3.select("#chart svg .nvd3");
for(var i=0;i<limits.length;i++){
g.append("line")
.attr("class","limit-line")
.attr("x1", xValueScale(d3.time.format('%b-%d')(new Date(limits[i][0]))))
.attr("y1", yValueScale(limits[i][1]/ 1000000000))
.attr("x2", xValueScale(d3.time.format('%b-%d')(new Date(limits[i][0]))) + parseInt(d3.select("#chart svg .nv-bar").attr("width")))
.attr("y2", yValueScale(limits[i][1]/ 1000000000))
;
}
https://jsfiddle.net/s2vemzht/25/

d3js scatterplot custom icons and animation

I'm just starting with d3js and I wanted to know if it's possible to create a scatterplot with custom icons for the data points similar to this method for Forced Layout?
I don't want to use d3.svg.symbol() as I want to use a custom icon with my company logo to mark each data point.
My final goal is to translate a point (with a custom icon) along a horizontal axis depending on the x value. I've searched high and low on how to do this with d3js but have had no luck.
To use an icon instead of a symbol, just swap out the path element (that the symbol generator is called on) with an image element.
Given a data set, D, with elements like {src: http.myImageURL, x: 10, y : 20} it would look something like this:
var svg = d3.select('body').append('svg');
svg.append('g').selectAll('.myPoint')
.data(D)
.enter()
.append('image')
.attr("xlink:href", function(d){ return d.src })
.attr("x", function(d){ return d.x })
.attr("y", function(d){ return d.y })
.attr("width", 16)
.attr("height", 16);

Resources