Custom axis function in D3JS - javascript

I'm using D3JS and I want an axis in x with this kind of values : 125, 250, 500, 1000 ... until 8000. So multiply by 2 my values each time.
So I tried a Quantize Scales but axis do not support it.
How can I do this ? Can I do a custom mathematical function like y = mx + b (where m = 2 in my case and b = 0) and use it in axis?
Here you can see my code
Podelo

The linear scale is pretty flexible if you mass in multiple values for the range and domain to create a polylinear scale:
tickWidth = (ChartWidth - padding)/7
xScale = d3.scale.linear()
.domain([0, 125, 250, 500, 1000, 2000, 4000, 8000])
.range(d3.range(8).map(function(d){ return d*tickWidth; }));
http://jsfiddle.net/h2juD/6/

Related

Y-axis should display whole number values from 0 to maxYValue on d3.js without repetition

I want to show values like [0,1,2,..., maxYValue] instead of [0, 0.5, 1, 1.5 ... maxYValue].
var y = d3.scaleLinear()
.range([height - margin, 0])
.domain([0, this.maxYValue]); //maxYValue can be any whole. number
Original:
d3.axisLeft(y).ticks(5).tickSize(-width + margin)
Modified:
d3.axisLeft(y).ticks(5).tickSize(-width + margin).tickFormat("f")
After using tickFormat("f"), it starts displaying the y-axis values like [0,0,0, 1, 1, 1]. It is rounding off the values. But, I want to set a step value to the y-axis values to get the data like [0,1,2,3,.., maxYValue]
If you simply wants all integers up to the maxYValue, instead of using axis.tickFormat on the auto-generated ticks just use d3.range to generate an array based on the scale's domain, and pass that to axis.tickValues:
d3.axisLeft(y).tickValues(d3.range(y.domain()[0], y.domain()[1] + 1, 1));
For instance:
const y = d3.scaleLinear()
.domain([0, 12]);
console.log(d3.range(y.domain()[0], y.domain()[1] + 1, 1))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/d3.min.js"></script>
If maxYValue is not the last value in the scale's domain, just use that variable instead.

Personalized axis range

I have values going these kinds of range (400k to 600 million)
And I would like to create a comprehensive y-axis on a D3 plot.
If I use a log scale, all the variations in the huge numbers are erased, If I use a linearScale, all variations in the small numbers is also erased.
Therefore I thought of doing two-axis (one over the other like in the picture below) but I don't know if there is a simpler way.
Can I specify all the tick values to get an axis where all the variations would be visible?
Thank you.
Use a regular linear scale with more than two values in both the domain and range, thus creating a piecewise scale.
For instance:
const scale = d3.scaleLinear()
.domain([0, 5e7, 1e8, 6e8])
.range([h-10, h/2 + 10, h/2 - 10, 10]);
Here is the running code:
const svg = d3.select("svg");
const h = 600;
const scale = d3.scaleLinear()
.domain([0, 5e7, 1e8, 6e8])
.range([h - 10, h / 2 + 10, h / 2 - 10, 10]);
const axis = d3.axisLeft(scale).tickValues(scale.ticks().concat(d3.range(0, 5e7, 5e6)))(svg.append("g").attr("transform", "translate(100,0)"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="200", height="600"></svg>
Do not forget to make sure that the user understands the y axis is truncated, preferably with a clear annotation showing that.

Find max value of JSON and store as a variable

I have a d3 graph which specifies the range on the Y axis like this:
var yScale = d3.scaleLinear()
.domain([0, 1]) // input
.range([height, 0]); // output
However a scale of 0 to 1 isn't very useful. I want it to work out what is a suitable range for me. I'm a bit new to this so I thought if I did something like this:
// Data
var dataset = [{
y: 0.1
},
{
y: 0.6
},
{
y: 0.6
},
{
y: 0.7
}
];
var mymax = Math.max(dataset);
Then I can find the maximum value in my dataset, and then feed that into my .domain range like this:
.domain([0, mymax]) // input
However, I appreciate my attempt at this is wrong because I get NaN returned. I think it might be pointing at the letter Y and not my numbers.
I don't feel like this is a duplicate of the question.
var mymax = Math.max.apply(Math, dataset.map(function(o) { return o.y; }));

How to make d3 scales proportional even if domains are different

Here is the example data set:
var dataset = [
{
x: 0,
y: 1.188
},
{
x: 22,
y: 0.822
},
{
x: 72,
y: 1.366
},
{
x: 82,
y: 1.163
},
{
x: 111,
y: 1.601
}
];
So, what I desire, for example: Distance between 0.001 and 0.002 on Y scale to be equal in width/proportions to distance from 1 to 2 on X scale on chart.
I tried it with linear scales but couldn't achieve proportions. I don't know if there is some built in method for setting those things.
Here is an attempt:
http://jsbin.com/goxamemare/8/edit?js,output
So, if I get it correctly in order to have equal ticks regardless of domain I need to take at least two things into considoration:
1. How many values (steps like 0.001, 0.002 for Y scale or 1, 2, 3 for X scale) there are for X and Y respectfully
2. To set one dimension, let's say width of the chart
So, that way I can work out:
height : number of values on Y = width : number of values on X scale
Which gives for example:
height : 810 = 360px : 300
height = 810 * 1.2
height = 972px
And so I get proportional ticks between Y and X. Right?

D3.js polylinear quantize scale

I want this kind of map function:
for 0 <= x < 0.96, returns 'red';
for 0.96 <= x < 0.98, returns 'yellow';
for 0.98 <= x <= 1, returns 'green'.
I tried to use this but it doesnt work as I expected:
//<0.96: Red, 0.96 - 0.98: Yellow, 0.98-1: Green
var color = d3.scale.quantize()
.domain([0, 0.96, 0.98, 1])
.range(["red", "yellow", "green"]);
How to express that function in D3js? Thanks!
I found the solution. Actually I should not use quantize scale, quantile scale is the correct answer:
//<0.96: Red, 0.96 - 0.98: Yellow, 0.98-1: Green
var color = d3.scale.quantile()
.domain([0, 0.96, 0.98, 1])
.range(["red", "yellow", "green"]);
According to this page (https://github.com/mbostock/d3/issues/751): "the quantize scale does (perhaps improperly, and inconsistent with the documentation) allow the domain to be specified with more than two numbers; the intermediate numbers are ignored. This feature was added for parity with d3.scale.linear and other quantitative scales which allow polylinear domains. The quantize scale does not compute the extent of the input domain.".

Categories