How to set x-axis values in d3 Javascript graph? - javascript

I'm using the d3 JS library to plot some graphs. It works fine, but I'm stuck on a weird problem which I've been struggling with for an hour - I can't set the x-axis values. Here is the graph (I added an alert that will show you the data format):
http://jovansfreelance.com/bikestats/d3/tipsy.php
I want the x-axis to show years, but for some reason that I can't see anywhere in the code, it's using decimal values instead, so instead of 2006 it has .006 - I have no idea where this is coming form, like it takes out the first digit and divides the rest by 100?!
If someone can point me to the lines of code that are doing this, that would be fine, I can take it from there.

As pointed out in another answer, a better way of handling time values is to explicitly use time scales. However, to achieve what you want it is sufficient to specify the format for the x axis explicitly. That is, to
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(h - margin * 2)
.tickPadding(10)
.ticks(7)
add
.tickFormat(d3.format("d"));

Could be related to this parseDate = d3.time.format("%Y") not working
If so, you might need
d3.svg.axis()
.scale(x)
.tickSize(h - margin * 2).tickPadding(10).ticks(7)
.tickFormat(function(d) { return d.toString(); }); // force the date value into a string
or, if you need the parse the date
.tickFormat(function(d) {
var fmt = d3.time.format("%Y");
return format.parse(d).toString()
});

Related

How to set unequal intervals on Y axis in D3.js?

I am trying to create a chart that will have a custom tick range. Having an issue on how to set up the axis though, tried using logscale too but it didn't work properly. Any help is appreciated, attaching a pic for reference.
How I want the axis to be
var y = d3.scaleLinear()
.domain(d3.extent(props.dailyDataAll, function (d) { return d.confirmed }))
.range([height, 0])
I know this really does not answer your question, but I think it may be just a common XY problem.
As such I would suggest instead of struggling to plot ticks properly, you could simply replace Y values with Math.log10(Y) which would make ticks work exactly as you wanted (100 being 2 on the Y scale, 1000 being 3, 10000 being 4 and so on, effectively one tick per order of magnitude just like in your requirements)

d3.js Nice End Ticks Exceeding Domain

I'm having an issue where I needed to use .nice() on one of my axis scales so that the ticks would make use of the end points and spread out properly (instead of leaving the end points unused).
Now that I fixed that, an unexpected problem has arisen. After I called .nice() like so:
var x = d3.time.scale().range([0, width])
x.domain(d3.extent(data, function(d) { return d.date; })).nice();
The axis now ranges up to the year 2018. This could spell trouble, because it looks very pretentious, as its only Feb. 2017. Obviously I don't have a crystal ball, there is no 2018 in my data anywhere, so my only guess is that the function went overboard when it was interpolating.
I love/literally need the tick spacing interpolating from .nice() or something equivalent to that, but at that same time I can't afford to have interpolations out of the domain of my data. Has anyone else had this problem? What can be brought to bear?
You are between a rock and a hard place.
The problem here is that D3 axis generator (specially when using a time scale) was not created having in mind such customizations.
Let's look at your problem: when using nice() you get the end ticks. However, as you said, the end value may exceed the domain, and that's a well known issue.
Here is a demo, the end date is today but the axis goes to 2020:
var svg = d3.select("svg");
var xScale = d3.scaleTime().domain([new Date("1980-01-01"), new Date()]).range([20,480]).nice();
var xAxis = d3.axisBottom(xScale);
var gX = svg.append("g").attr("transform","translate(0,50)").call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="80"></svg>
A possible solution is using concat with the scale's domain to guarantee that the first and last value in the domain will be the first and last tick, like this:
.tickValues(xScale.ticks(10).concat(xScale.domain()))
And setting the approximate number of ticks using ticks. Here is the demo:
var svg = d3.select("svg");
var xScale = d3.scaleTime().domain([new Date("1980-01-01"), new Date()]).range([20,480]);
var xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%Y")).tickValues(xScale.ticks(10).concat(xScale.domain()));
var gX = svg.append("g").attr("transform","translate(0,50)").call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="80"></svg>
However, as you can see, the ticks are not evenly spaced, as you wish.
Thus, an alternative solution for your problem, still using this concat approach, is tweaking the ticks value until we make the ticks appear to be more or less evenly spaced:
var svg = d3.select("svg");
var xScale = d3.scaleTime().domain([new Date("1980-01-01"), new Date()]).range([20,480]);
var xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%Y")).tickValues(xScale.ticks(5).concat(xScale.domain()));
var gX = svg.append("g").attr("transform","translate(0,50)").call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="80"></svg>
That being said, this is not a proper solution, because I doubt anyone can make (without a cumbersome hack) the axis starting and ending at the exact domain limits and having all the ticks evenly spaced .
This should be resolved with D3.js v6. The end tick out of domain issue is easily solved when using d3.scaleTime() together with .nice(). However, be aware of d3.scaleUtc(). When using d3.scaleUtc() together with .nice(), the same issue persists - so just switch to d3.scaleTime(). :)

Automatic Date Labeling for NVD3 Graphs

I want the date labels to automatically be calculated, appear, and disappear when I change the focus range so that they don't overlap.
I am using a MultiBar graph with a focus chart with the default ordinal scale for nv.models.multiBar(). When I use .ticks(availableWidth / 100 ) on the xAxis, it seems to generate a tick label for EVERY date, or at least a very large number of them:
On nv.models.lineWithFocusChart(), the labels are automatically reduced to fit in a space. This could be because it uses the scale for nv.models.scatter() which is a d3.scale.linear(), but I'm not sure. I tried creating my own scale with the following:
x = d3.scale.ordinal() //as well as x = d3.scale.linear()
.domain(d3.extent(data.map(function(d) {
return d.values.map(function(d,i) {
var X = getX(d,i);
return X.getTime();
});
})))
.range([0, availableWidth]);
I get the following for an ordinal scale:
and no labels for a linear scale. Will this approach work? If so, what am I doing wrong?
On nv.models.multiBarChart(), there is a .reduceXTicks(BOOLEAN) option but this only applies to multiBarChart and there doesn't seem to be an easy way to add it to nv.models.multiBar(). Can I somehow use this?
If there is anything I haven't tried please let me know. I don't want to calculate the labels myself and specify them using .tickValues()
The solution was in fact to use d3.scale.linear() for the x axis. What I tried above didn't work because I was specifying the whole domain of the context chart, when I needed to specify the min and max of the current selection.
In chart(selection) {...}, I put
x = d3.scale.linear()
.range([0, availableWidth]);
and in onBrush(), I put x.domain([new Date(extent[0]), new Date(extent[1])]);, where extent contains the min and max dates of the selection in milliseconds.

D3 linechart, can't edit the amount of ticks with an ordinal scale?

I asked a question before about d3, and they suggested me to use an ordinal scale, this would solve my problems. Indeed it solved my problems, but know I'm stuck with another issue...
It draws perfectly, but my X-axis is full of text.
As an example, I want:
1900 1904 1908 1912 ...
but I got:
190119021903190419051906. As you can see this is not clear. (this is just an example, if there were only dates I could use another scale).
Everywhere I looked they talk about axis.ticks(number). But this doesn't work. Nothing happens and I still get the same result.
I hacked a result to get less results on the x-axis:
var str = [];
var i = 0;
while(i < data.length) {
str.push(data[i].age);
i=i+8;
}
x.domain(str);
But if I do this it creates a random line and doesn't draw it perfectly anymore. Don't know how to solve this.. It's a simple line chart, nothing difficult, the only difficulty (for me) is the ordinal scale...
Hope someone can help me out.
this is how my x and x-axis is defined:
var x = d3.scale.ordinal()
.rangeRoundBands([0, width-150],1);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
without the while-loop (the nasty hack), I just had the following line defining the x.domain:
x.domain(data.map(function(d) { return d.age; }));
Have a look at the documentation for axes, in particular the ticks() function. You can use it (or tickValues()) to control how many (and what) values you want to show.
If you're working with dates, you might want to use a time scale instead of the ordinal one. In particular it will allow you to control the ticks in a more meaningful way, e.g. specify that you want ticks every five years.

D3 time series heatmap

I am trying to make a heatmap using d3 which on x axis a time series, on y a number and the color is the value for the cell. The data is loaded based on the input and the domain and range can change on different input. I was not able to find such example. Does anyone have an idea how I can create that?
Thanks
So I finally got the time to write this piece of code that I was looking for. My main problem was that I had understood the scales well. So after reading a bit I could define a time scale and map it to my data with the following code:
var xscale = d3.time.scale()
.domain([startDate, endDate])
.range([padding, w - padding]);
var xAxis = d3.svg.axis()
.scale(xscale)
.orient("bottom")
.ticks(d3.time.days, 5);
You can find a working demo of my code in the following jsfiddle:
http://jsfiddle.net/TD5Sk/1/
Explore around the d3 gallery of examples, mixing and matching you should be able to find a good starting point. The co-occurrence matrix has many of the properties you describe. Even the calendar example probably has some useful pointers.

Categories

Resources