d3 axis labeling - javascript

How do I add text labels to axes in d3?
For instance, I have a simple line graph with an x and y axis.
On my x-axis, I have ticks from 1 to 10. I want the word "days" to appear underneath it so people know the x axis is counting days.
Similarly, on the y-axis, I have the numbers 1-10 as ticks, and I want the words "sandwiches eaten" to appear sideways.
Is there a simple way to do this?

Axis labels aren't built-in to D3's axis component, but you can add labels yourself simply by adding an SVG text element. A good example of this is my recreation of Gapminder’s animated bubble chart, The Wealth & Health of Nations. The x-axis label looks like this:
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", width)
.attr("y", height - 6)
.text("income per capita, inflation-adjusted (dollars)");
And the y-axis label like this:
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", 6)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("life expectancy (years)");
You can also use a stylesheet to style these labels as you like, either together (.label) or individually (.x.label, .y.label).

In the new D3js version (version 3 onwards), when you create a chart axis via d3.svg.axis() function you have access to two methods called tickValues and tickFormat which are built-in inside the function so that you can specifies which values you need the ticks for and in what format you want the text to appear:
var formatAxis = d3.format(" 0");
var axis = d3.svg.axis()
.scale(xScale)
.tickFormat(formatAxis)
.ticks(3)
.tickValues([100, 200, 300]) //specify an array here for values
.orient("bottom");

If you want the y-axis label in the middle of the y-axis like I did:
Rotate text 90 degrees with text-anchor middle
Translate the text by its midpoint
x position: to prevent overlap of y-axis tick labels (-50)
y position: to match the midpoint of the y-axis (chartHeight / 2)
Code sample:
var axisLabelX = -50;
var axisLabelY = chartHeight / 2;
chartArea
.append('g')
.attr('transform', 'translate(' + axisLabelX + ', ' + axisLabelY + ')')
.append('text')
.attr('text-anchor', 'middle')
.attr('transform', 'rotate(-90)')
.text('Y Axis Label')
;
This prevents rotating the whole coordinate system as mentioned by lubar above.

If you work in d3.v4, as suggested, you can use this instance offering everything you need.
You might just want to replace the X-axis data by your "days" but remember to parse string values correctly and not apply concatenate.
parseTime might as well do the trick for days scaling with a date format ?
d3.json("data.json", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.year = parseTime(d.year);
d.value = +d.value;
});
x.domain(d3.extent(data, function(d) { return d.year; }));
y.domain([d3.min(data, function(d) { return d.value; }) / 1.005, d3.max(data, function(d) { return d.value; }) * 1.005]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(6).tickFormat(function(d) { return parseInt(d / 1000) + "k"; }))
.append("text")
.attr("class", "axis-title")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.attr("fill", "#5D6971")
.text("Population)");
fiddle with global css / js

D3 provides a pretty low-level set of components that you can use to assemble charts. You are given the building blocks, an axis component, data join, selection and SVG. It's your job to put them together to form a chart!
If you want a conventional chart, i.e. a pair of axes, axis labels, a chart title and a plot area, why not have a look at d3fc? it is an open source set of more high-level D3 components. It includes a cartesian chart component that might be what you need:
var chart = fc.chartSvgCartesian(
d3.scaleLinear(),
d3.scaleLinear()
)
.xLabel('Value')
.yLabel('Sine / Cosine')
.chartLabel('Sine and Cosine')
.yDomain(yExtent(data))
.xDomain(xExtent(data))
.plotArea(multi);
// render
d3.select('#sine')
.datum(data)
.call(chart);
You can see a more complete example here: https://d3fc.io/examples/simple/index.html

chart.xAxis.axisLabel('Label here');
or
xAxis: {
axisLabel: 'Label here'
},

Related

How to set minimal step for y-axis in d3.js?

I have a bar chart where values can range from 0 to 5. The values can only be integers (0, 1, 2, 3, 4, 5).
However, the y-axis renders with smaller steps, for example 0, 0.5, 1, 1.5, 2 etc. I want to set the axis values to integers only, but playing with domain and range hasn't helped me at all.
I don't see an option to set something like minimalInterval = 1. How do I do this? I'm sure there's an option somewhere. Current code for the axes:
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
x.domain(data.map(function(d) { return d.day; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("y", 0)
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "rotate(90)")
.style("text-anchor", "start");
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end");
There is nothing like steps for a D3 generated axis.
However, in your case, the solution is simple: you can use tickValues with d3.range(6) and a formatter for integers or, even simpler, you can use ticks.
According to the API,
Sets the arguments that will be passed to scale.ticks and scale.tickFormat when the axis is rendered, and returns the axis generator. The meaning of the arguments depends on the axis’ scale type: most commonly, the arguments are a suggested count for the number of ticks (or a time interval for time scales), and an optional format specifier to customize how the tick values are formatted.
So, in your case:
axis.ticks(5, "f");
Where 5 is the count and f is the specifier for fixed point notation.
Here is a demo (with an horizontal axis):
var svg = d3.select("svg");
var scale = d3.scaleLinear()
.domain([0, 5])
.range([20, 280]);
var axis = d3.axisBottom(scale)
.ticks(5, "f")
var gX = svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Just for completeness, the same code without ticks:
var svg = d3.select("svg");
var scale = d3.scaleLinear()
.domain([0, 5])
.range([20, 280]);
var axis = d3.axisBottom(scale);
var gX = svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

Best way to show Y axis values in Millions of £

I have data in this format:
[{"EndDate":"2012","Value":26473660},
{"EndDate":"2013","Value":54296732},
{"EndDate":"2014","Value":64063400},
{"EndDate":"2015","Value":81812464},
{"EndDate":"2016","Value":86899274}]
And I have managed to successfully render a bar chart. However, The Y-Axis Values are showing just "000" up and down the scale.
Here is the relevant code parts for the y axis.
var y = d3.scale.linear()
.range([height, 0]);
....
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
....
y.domain([0, d3.max(dataset, function(d) { return d.Value; })]);
....
svg.append("g") //Y AXIS ENTER
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value in £");
I've looked into d3.ticks/d3.tickFormat functions on bostocks website but not following what is actually going on. Essentially, I'd like to display a short hand way for displaying Millions: 0M, 10M, 20M, 30M.. for a simple solution.
Apologies if a duplicate. It probably is but can't seem to find the solution that applies to my style of dataset :/
Thanks in Advance.
Add .tickFormat('.0s') to your yAxis definition.
See:
Format Y axis values, original figures in millions, only want to show first three digits
D3: Formatting tick value. To show B (Billion) instead of G (Giga)

Log axis scale not formatting data

I am trying to create a log-normal plot with an array of data, but when I apply a log scale to the y axis, it only scales the axis ticks and not the actual data being plotted. In summary, all the data is plotted linearly, but the axis scale is shown as log. Below is my axis code:
var y = d3.scale.log()
.domain([.001,maxData])
.range([graphHeight, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("right")
.ticks(20, ".2")
.tickSize(-graphWidth,0,0);
svg.append("g")
.attr("class", "yaxis")
.attr("transform", "translate(" +graphWidth + ",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 70)
.attr("x", -graphHeight/2)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("YLabel");
var line = d3.svg.line()
.x(function(d,i) {
return (i-0.5)*horizontalBarDistance;
})
.y(function(d) {
return graphHeight - d*100;
})
for (names in dataArrays)
{
svg.append("svg:path").attr("class","line").attr("d", line(dataArrays[names]));
}
You have to use the scale in your code for it to make a difference. At the moment, your code contains no reference to it apart from when you're assigning it to the axis. You probably want something like
.y(function(d) {
return y(d);
})
in the definition of your line generator.

D3 js chart inverted issue

My Fiddle
I am studying d3js,i got this implementation of a bar chart with some data.
I need the chart to be inverted.
I tried adding:
var y = d3.scale.linear()
.domain([0, d3.max(jsonData.year)])
.range([500, 0]);
and calling that on the bars:
.attr("y", function(d) {
return y(d);
});
Didnt work..
How do i get around this? I think am missing something..
This is what i want along with the axis:
how's this? http://jsfiddle.net/jTs9A/3/
the problem was your transform, translate coordinates on appending the x and y axes at the bottom.
canvas.append("g")
.call(xAxis)
.attr("transform", "translate(0,0)");
canvas.append("g")
.call(yAxis)
.attr("transform", "translate(-10,0)");
you had (0,250) and (-10,-50) before
EDIT:
http://jsfiddle.net/jTs9A/4/
you needed to add this:
.attr("y", function(d) {
return (h- d.year*10); //Height minus data value
})
where h is the height of your graph area. check the tut in the comments (not enough rep yet)

How to set the label for each vertical axis in a parallel coordinates visualization?

I'm new to d3.js (and stackoverflow) and I'm currently working through the parallel coordinates example. I'm currently using a 2d array named 'row' for the data. Above each vertical axis is the label '0' or '1' or '2', etc. However, I'd like each vertical axis to be labeled with the text in row[0][i]. I believe the numbers 0,1,2 are coming from the datum. Any suggestions on how I may use the labels in row[0][i] instead? I suspect I'm doing something wrong that's pretty basic. Here's the relevant code. Thanks !
// Extract the list of expressions and create a scale for each.
x.domain(dimensions = d3.keys(row[0]).filter(function (d, i) {
return row[0][i] != "name" &&
(y[d] = d3.scale.linear()
.domain(d3.extent(row, function (p) { return +p[d]; }))
.range([height, 0]));
}));
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function (d) { return "translate(" + x(d) + ")"; });
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function (d) { d3.select(this).call(axis.scale(y[d])); })
.append("text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String);//.text(String)
If you only have a controlled set of Axis (like three axis), you may just want to set them up, individually, as follows...
svg.append("text").attr("class","First_Axis")
.text("0")
.attr("x", first_x_coordinate)
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
svg.append("text").attr("class","Second_Axis")
.text("1")
.attr("x", first_x_coordinate + controlled_offset)
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
svg.append("text").attr("class","Third_Axis")
.text("2")
.attr("x", first_x_coordinate + controlled_offset*2)
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
However, if you have dynamically placed axis that rely on the data, you may want to place the axis info using a function that holds the y coordinate constant while determining the x coordinate based on a fixed "offset" (i.e. data driven axis placement). For example...
svg.append("text")
.attr("class",function(d, i) {return "Axis_" + i; })
.text(function(d,i) {return i; })
.attr("x", function(d, i) { return (x_root_coordinate + x_offset_value*i); })
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
I hope this helps.
Frank

Categories