Im using this scatter chart example to achieve dynamic axis changing on data change.
I want to achieve two things:
1 - the X and Y axis intercept at 0
2 - both axis intercept in the middle of the chart to accommodate negative numbers better
This is where Ive got to : Ive managed to get the Y axis into the middle but once the data is changing the X and Y axis are not aligning properly. Could anyone suggest a fix in my update function ? My edited example is here.
Thank you
To make axis intercept at 0 in the middle of the chart with linear scales, you should define symmetric domains:
var ds = randomData(200);
var xmax = d3.max(ds, function (d) { return Math.abs(d.x); });
var ymax = d3.max(ds, function (d) { return Math.abs(d.y); });
x.domain([-xmax, xmax]).nice();
y.domain([-ymax, ymax]).nice();
Demo
Related
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)
I have the following Line Graph (CodePen) and as you can see, the Y-Axis isn't very smart. It begins from 0 when it should begin from somewhere near 2200.
My guess was that this would be to do with scales:
// set the ranges
var x = d3.scalePoint().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
But I tried all sorts to get this to behave the "smart" and "flexible" way and couldn't.
How can I make the axis smarter? So if tomorrow I feed the chart a different set of data that starts at 150, the code is smart enough to draw relevant axis values.
If you don't want the Y axis starting at 0, you shouldn't set the lower value in the domain to zero, as you did:
y.domain([0, d3.max(result, function(d) {
return d.consumption;
})]);
If you want the Y axis to start next to the minimum value, you should use:
y.domain([d3.min(result, function(d) {
return d.consumption; })*0.975,
d3.max(result, function(d) {
return d.consumption; })*1.025
]);
Here, the numbers 0.975 and 1.025 are just values to make the axis going a little bit below and after the minimum and maximum values, respectively. You can change them or remove them.
Here is your updated CodePen: http://codepen.io/anon/pen/EgOBvO?editors=0010
PS: while in a bar chart it's highly recommended to always use a zero baseline for the Y axis, there is no problem using a non-zero baseline for the Y axis in a time series (line chart).
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.
I am trying to build a line chart using D3 and I am using this example.
The problem that I am facing is that when I am passing a dataset that contains the same value in the linear.domain() fof the y then the line of the line chart gets drawn on top of the horizontal axis and as a result is not visible. Also no numbers are printed on the y axis.
Here is a JSFiddle with my code.
The metrics variable contains 3 objects, three different timestamps with the same value. On the result panel the line is get drawn on top of x axis. If you change one of the three values from 5 to any other number then the line chart gets drawn as normal.
Any ideas on how can I draw the line in the middle of the y axis when the metrics variable contains values of the same value?
Thanks
Instead of line
y.domain(d3.extent(metrics, function(d) { return d.close; }));
use
y.domain([d3.max(metrics, function(d) { return d.close; }) + 0.01,
d3.min(metrics, function(d) { return d.close; }) - 0.01]);
The thing is, if y scale is just segment of length 0, like [5.0, 5.0] (or any other number other that 5.0), d3 is totally confused, and refuses to display anything on y axis, and places 5.0 right at origin.
With new code: the following is obtained for the same case:
]
Here is also link to jsfiddle.
I have a D3 stacked bar chart that is working great except that the last bar overhangs the right side of X axis and the left side of the axis is not touching the Y axis. This is because I had to move the bars so that they would be centered over the tick lines. I thought that if I padded the time scale by a date on either end that would take care of it, but instead the bars just spread out to take up the available space.
Here is a JSFiddle: http://jsfiddle.net/goodspeedj/cvjQq/
Here is the X scale:
var main_x = d3.time.scale().range([0, main_width-axis_offset - 5]);
This is my attempt to pad the X axis by a date on either end:
main_x.domain([
d3.min(data.result, function(d) {
return d.date.setDate(d.date.getDate() - 1);
}),
d3.max(data.result, function(d) {
return d.date.setDate(d.date.getDate() + 1);
}
)]);
The calculation for the x attribute on the bars is:
.attr("x", function(d) { return main_x(d.date) - (main_width/len)/2; })
This is a minor thing, but it is really annoying me. Thanks!
The main problem was that you had a clip path in your SVG that clipped parts of the plotting region. Once that is removed, you can see the full graph, but the first and last bars will still "hang" over the ends of the axis.
To change that, you have to extend the axis, e.g. by adding a day or two either way when computing the minimum and maximum for the scale.