Reputation: 9008
I am building an area graph in d3.js.
For my y axis, I want to use a linear scale that extends from the minimal value to the maximal value of the data represented in the graph.
Using
y = d3.scale.linear().range([height, 0]),
yAxis = d3.svg.axis().scale(y).orient("left")
d3 shows ticks only for multiples of 10000.
I would like also to see ticks for the starting and the ending value. Is this possible? How?
Upvotes: 19
Views: 15682
Reputation: 8328
Hacky way
Before trying this approach just try with ticks, tickSize, etc. functions once.
To be frank, I went through lots of solutions, and unfortunately, none of them worked for me. Finally, I played with the CSS and get the job done.
Hiding the in-between elements between the first and last tick value.
// displaying only first and last x-axis tick.
#x-axis {
.tick {
display: none
&:first-child,
&:last-of-type {
display: block;
}
}
}
Upvotes: 0
Reputation: 27544
The nice()
approach is usually preferable, but if you do want to have explicit tick labels at the max and min values of your data, you can force the axis to include them, along with whatever default tick values would be created by the scale:
axis.tickValues( scale.ticks( 5 ).concat( scale.domain() ) );
scale.ticks(count)
returns an array of approximately that many tick values from the scale's domain, rounded off to nice even numbers. scale.domain()
returns the [min,max]
domain array that you set based on the data. array.concat(array)
concatenates one array onto the end of the other, and axis.tickValues(array)
tells the axis to draw the ticks at those values specifically.
Live example: https://jsfiddle.net/zUj3E/671/
(function () {
//Set up SVG and axis//
var svg = d3.select("svg");
var width = window.getComputedStyle(svg[0][0])["width"];
width = parseFloat(width);
var height = window.getComputedStyle(svg[0][0])["height"];
height = parseFloat(height);
var margin = 50;
var scale = d3.scale.linear()
.domain([0.05, 0.95])
.range([0, height - 2*margin]);
var formatPercent = d3.format(".0%");
var axis = d3.svg.axis()
.scale(scale)
.orient("right")
.tickFormat(formatPercent);
axis.tickValues( scale.ticks( 5 ).concat( scale.domain() ) );
//set the axis tick values explicitly, as the array of ticks
//generated by the scale PLUS the max and min values from the scale domain
//concatenated into a single array
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + [margin, margin]+")")
.call(axis);
})();
g.axis line, g.axis path {
fill:none;
stroke:royalblue;
shape-rendering:crispEdges;
}
g.axis text{
fill:royalblue;
font-family:sans-serif;
}
g.axis path {
stroke-width:2;
stroke:seagreen;
}
svg {
display: block;
width: 100vw;
height: 100vh;
}
body {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg></svg>
Upvotes: 44
Reputation: 109232
One way to do this is to extend the domain of a scale to be "nice", i.e. to include "round" values that will show up on the axis. You can do this by calling .nice()
after setting the domain:
y = d3.scale.linear().range([height, 0]).domain(...).nice();
The alternative would be to specify the ticks explicitly, which is much more painful in general.
Upvotes: 23