scaleTime minimum tick value - javascript

Using d3 I have an xAxis defined as
var xScale = d3.scaleTime()
.domain([fromDate, toDate])
.range([0, width]);
var xAxis = d3.axisBottom(xScale);
function customXAxis(g) {
g.call(xAxis);
g.select(".domain").remove();
g.selectAll(".tick line").attr("stroke", "white");
g.selectAll(".tick text").attr("fill", "white");
}
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(customXAxis);
All is working very well indeed.
However, I would like the scale to show ticks at a minimum of a day. As it stands if fromData and toDate are only a few days difference it show ticks....
Mon-10___12PM___Tue-11___12PM___Wed-13___12PM___Thu-14___12PM
How can I get it to not show the time of day values?
Any help appreciated.

You can set the intervals in the axis generator:
Constructs a new custom interval given the specified floor and offset functions and an optional count function.
For instance, this is your code as it is (the domain here has just 3 days):
var svg = d3.select("svg");
var xScale = d3.scaleTime()
.domain([new Date("January 1, 2017 00:00:00"), new Date("January 4, 2017 00:00:00")])
.range([20, 480]);
var xAxis = d3.axisBottom(xScale);
svg.append("g")
.attr("transform", "translate(0,100)")
.call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
Now the same code, with d3.timeDay:
var svg = d3.select("svg");
var xScale = d3.scaleTime()
.domain([new Date("January 1, 2017 00:00:00"), new Date("January 4, 2017 00:00:00")])
.range([20, 480]);
var xAxis = d3.axisBottom(xScale)
.ticks(d3.timeDay)
.tickFormat(d=>d3.timeFormat("%a %d")(d));
svg.append("g")
.attr("transform", "translate(0,100)")
.call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
PS: the tickFormat is just to change the first tick, don't pay attention to it.

Related

How to reformat axis labels?

I've begun learning D3, and many tutorials are written for v3. I read through a lot of v4's documentation, but I can't wrap my mind around how to format my axis labels. Right now I have a visualization that looks like this:
The months overlapping is not ideal. I know I can use d3's timeFormat and use "%b" to use an abbreviated month. But I'm not sure how syntactically it fits in. My code for the bottom axis is:
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.ticks(d3.timeMonth.every(4)));
I would've expected it to be something like
format = d3.time.format("%b")
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.ticks(format(d3.timeMonth.every(4))));
But that doesn't work. I know this is probably very simple, but I'm not getting it.
You should use tickFormat instead of ticks:
.tickFormat(d3.timeFormat("%b"))
Here is a demo:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setYear(new Date().getFullYear() + 1)]);
var axis = d3.axisBottom(scale)
.tickFormat(d3.timeFormat("%b"))
.ticks(d3.timeMonth);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
EDIT: For showing the year instead of January:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setYear(new Date().getFullYear() + 1)]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d) {
return d3.timeFormat("%b")(d) === "Jan" ?
d3.timeFormat("%Y")(d) : d3.timeFormat("%b")(d);
})
.ticks(d3.timeMonth);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>

How can I format the day of the week as a single letter?

To format my ticks to display an abbreviated day of the week, I can use:
.tickFormat(d3.timeFormat("%a")) // Mon Tue Wed Thu Fri Sat Sun
How can I format the day of the week as a single letter?
.tickFormat(d3.timeFormat()) // M T W T F S S
There is no time format in D3 library to display just the first letter of the day.
However, the task here is very simple. First, let's see a regular axis, and then show a couple of solutions.
This is the regular axis:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setDate(new Date().getDate() + 7)]);
var axis = d3.axisBottom(scale)
.tickFormat(d3.timeFormat("%a"))
.ticks(d3.timeDay);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
Solution #1: Using substring:
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).substring(0, 1)
})
Here is the demo:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setDate(new Date().getDate() + 7)]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).substring(0, 1)
})
.ticks(d3.timeDay);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
Solution #2: using slice:
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).slice(0, 1)
})
Here is the demo:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setDate(new Date().getDate() + 7)]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).slice(0, 1)
})
.ticks(d3.timeDay);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
Solution #3: using charAt:
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).charAt(0)
})
Here is the demo:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setDate(new Date().getDate() + 7)]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).charAt(0)
})
.ticks(d3.timeDay);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
Solution #4: using the index:
.tickFormat(function(d) {
return d3.timeFormat("%a")(d)[0]
})
Here is the demo:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setDate(new Date().getDate() + 7)]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d) {
return d3.timeFormat("%a")(d)[0]
})
.ticks(d3.timeDay);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>
Solution #5: using a regex (just because):
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).match('^.{0,1}')
})
Here is the demo:
var svg = d3.select("svg")
var scale = d3.scaleTime()
.range([20, 480])
.domain([new Date(), new Date().setDate(new Date().getDate() + 7)]);
var axis = d3.axisBottom(scale)
.tickFormat(function(d) {
return d3.timeFormat("%a")(d).match('^.{0,1}')
})
.ticks(d3.timeDay);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>

D3 x-axis for each day of the week

I have a JSON array like the following:
[
{
"day": "Monday",
"sales": 242
},
{
"day": "Tuesday",
"sales": 256
},
...
]
This data covers one week, so there is an object for each day Monday through Sunday.
I have built a bar graph with D3 with a bar for each day of the week. I am now attempting to add an x-axis with a tick label for each day.
I've done the following to set up my y-axis:
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.sales;
})])
.range([height, 0]);
var yAxis = d3.axisLeft(yScale)
.ticks(5);
svg.append("g")
.call(yAxis);
This works great, but for some reason, I am stumped on how to setup my x-axis with each day of the week under the corresponding bar. Note: I am using D3 version 4.
Once your days are just strings, you can use scaleBand instead of scaleTime:
var xScale = d3.scaleBand()
.domain(data.map(function(d){ return d.day}))
.range([0, width])//you can use rangeRound instead
.paddingInner(someValue);//the value of the inner padding, if any.
Then, set the x axis accordingly:
var xAxis = d3.axisBottom(xScale);
Check this snippet:
var width = 550, height = 200;
var data = [{day:"Monday"},
{day:"Tuesday"},
{day:"Wednesday"},
{day:"Thursday"},
{day:"Friday"},
{day:"Saturday"},
{day:"Sunday"}
];
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleBand()
.domain(data.map(function(d){ return d.day}))
.range([0, width*0.95])
var xAxis = d3.axisBottom(xScale)
.ticks(7);
svg.append("g")
.attr("transform", "translate(0,100)")
.call(xAxis);
text { font-size: 12px;}
<script src="https://d3js.org/d3.v4.min.js"></script>

D3.js y-Axis time scale

is it possible to have a line chart with a time-scaled y-Axis in D3.js?
I found the documentation:
https://github.com/mbostock/d3/wiki/Time-Scales
and there doesn't seem to be a limitation for the Y-Axis.
Do you have any examples?
Its pretty much the same as using a linear scale:
var svg = d3.select('#your_svg_id').select("svg")
.attr('width', 300)
.attr('height', 300)
.append("g");
var yScale = d3.time.scale()
.domain([new Date(1980, 0, 1), new Date() ])
.range([100, 0]);
// Domian being the from and to date and range the from to positioning of the axis
svg.append("svg:g")
.attr("class", "y axis")
.call(yAxisGen);

D3.js - how to draw grid lines for specific axis ticks

I am trying to draw some line charts using D3.js. I found some codes like http://jsfiddle.net/BDWFW/.
var w = 760;
var h = 400;
var pad = 50;
var d0 = new Date("Jan 29 2011 UTC");
var d1 = new Date("March 15 2011 UTC");
var x = d3.time.scale() .domain([d0, d1]).range([0,w]);
var y = d3.scale.linear().domain([0, 1]) .range([h,0]);
var svg = d3.select("body")
.append("svg:svg")
.attr("height", h + pad)
.attr("width", w + pad)
var vis = svg.append("svg:g")
.attr("transform", "translate(40,20)")
var rules = vis.append("svg:g").classed("rules", true)
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(8)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10)
}
rules.append("svg:g").classed("grid x_grid", true)
.attr("transform", "translate(0,"+h+")")
.call(make_x_axis()
.tickSize(-h,0,0)
.tickFormat("")
)
rules.append("svg:g").classed("grid y_grid", true)
.call(make_y_axis()
.tickSize(-w,0,0)
.tickFormat("")
)
rules.append("svg:g").classed("labels x_labels", true)
.attr("transform", "translate(0,"+h+")")
.call(make_x_axis()
.tickSize(5)
// .tickFormat(d3.time.format("%Y/%m"))
)
rules.append("svg:g").classed("labels y_labels", true)
.call(make_y_axis()
.tickSubdivide(1)
.tickSize(10, 5, 0)
)
As we can see in the result, all grid lines are connected to every ticks. Instead, I would like to choose specific ticks and draw grid lines only for those ticks. Unfortunately, I am not sure how I can do it with D3.js. For example, in this example, how can we make gridlines for Feb06, Feb20, and Mar06?
Sometimes, I really don't understand D3.js. Look at this gridline drawing part:
rules.append("svg:g").classed("grid y_grid", true)
.call(make_y_axis()
.tickSize(-w,0,0)
.tickFormat("")
)
I am really not sure about how this code draws a gridline. Among the chained function, I couldn't find which one doing that. Some novice users like me feel like everything is in a Blackbox.

Categories