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
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>
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>
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>
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);
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.