Using D3 I want to create an X Axis that looks like:
I've worked out how to do the axis and ticks, but not the labels using the following:
var svgWidth = 500;
var svgHeight = 500;
var svgAxisPadding = 20;
var xScale = d3.scale.log()
.domain([Math.pow(10, 5), Math.pow(10, 7)])
.range([svgAxisPadding, svgWidth - svgAxisPadding]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(0, "e");
var svg = d3.select('#diagram')
.append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
svg.append('g')
.attr("class", "axis")
.call(xAxis);
And here's a jsFiddle with the complete code.
d3. ticks generates an array of nicely-rounded numbers inside an interval [start, stop]. The third argument indicates the approximate count of values needed. For example, to cover the extent [0, 10] with about 100 values, d3.ticks will return these ticks: start = 0.
d3. range returns an array of evenly-spaced numbers. In its simplest form, it returns the integers from zero to the specified end minus one. Array(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
scaleBand() function in D3. js is used to construct a new band scale with the domain specified as an array of values and the range as the minimum and maximum extents of the bands. This function splits the range into n bands where n is the number of values in the domain array.
You could use unicode:
var superscript = "⁰¹²³⁴⁵⁶⁷⁸⁹",
formatPower = function(d) { return (d + "").split("").map(function(c) { return superscript[c]; }).join(""); },
formatTick = function(d) { return 10 + formatPower(Math.round(Math.log(d) / Math.LN10)); };
For example, formatTick(1e5)
returns "10⁵"
. Example at bl.ocks.org/6738109:
The downside of this approach is that the vertical alignment of the superscript numerals seems inconsistent. So using post-selection (say, selecting the text elements and adding a tspan element for the superscript to each) might be better. Another example at bl.ocks.org/6738229:
There's a tickFormat
function available on the axis. Unfortunately, it expects a String as a return value and plops that on the axis. This would be great if you wanted to display 10^6, but not as helpful when you want to use the superscript notation.
A workaround is to create 2 axes: one for displaying the 10 and another for displaying the exponent. Here's an example:
var svgWidth = 500;
var svgHeight = 500;
var svgAxisPadding = 20;
var xScale = d3.scale.log()
.domain([Math.pow(10, 5), Math.pow(10, 7)])
.range([svgAxisPadding, svgWidth - svgAxisPadding]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(0, "e")
.tickFormat(function (d) {
var log = Math.log(d) / Math.LN10;
return Math.abs(Math.round(log) - log) < 1e-6 ? 10 : '';
});
var xAxis2 = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(0, "e")
.tickFormat(function (d) {
var log = Math.log(d) / Math.LN10;
return Math.abs(Math.round(log) - log) < 1e-6 ? Math.round(log) : '';
});
var svg = d3.select('#diagram')
.append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
svg.append('g')
.attr("class", "axis")
.call(xAxis);
svg.append('g')
.attr("class", "axis")
.attr("transform", "translate(12, -5)") //shifted up and to the right
.style("font-size", "12px")
.call(xAxis2);
It's not necessarily the most elegant solution, but it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With