D3: What does the scale do when passed an axis? - javascript

In d3, if you want to create an axis you might do something like this:
var xAxis = d3.svg.axis()
.scale(x)
where x is a scale function. I understand that the domain of x defines the start and ending values for the ticks. I'm having trouble understanding how the range of x changes the resulting axis. What does the domain map to in the context of an axis.

Think about what one must do to create a visual representation of any data set. You must convert each data point (e.g. 1 million dollars) into a point on the screen. If your data has a minimum value of $0 and maximum value of $1000000, you have a domain of 0 to 1000000. Now to represent your data on a computer screen you must convert each data point (e.g. $25) into a number of pixels. You could try a simple 1 to 1 linear conversion ($25 converts to 25 pixels on the screen), in which case your range would be the same as your domain = 0 to 1000000. But this would require a bloody big screen. More likely we have an idea of how large we want the graphic to appear on the screen, so we set our range accordingly (e.g. 0 to 600).
The d3 scale function converts each data point in your dataset into a corresponding value within your range. That enables it to be presented on the screen. The previous example is a simple conversion so the d3.scale() function is not doing much for you, but spend some time converting data points into a visual representation and you will quickly discover some situations where the scale function is doing a lot of work for you.
In the particular case of an axis, the scale function is doing exactly the same thing. It is doing the conversion (to pixels) for each 'tick' and placing them on the screen.

Related

When having mulitple Y lines data, how can I let the chart automatically scale to show them all?

Suppose I have a linechart with multiple lines (the number is dynamic) and I would need to always scale the Y so that all lines are shown - so the scale should always be based on the range with highest values. Is there a way how to it automatically? I found some example with automatic yScaling using d3.max but that is done for a known dataset. In my case, I do not know what range will be the one to use.

Bubble chart c3js

Following the c3js documentation there is no option for Bubble chart. One workaround for that is to setup scatter plot and specify point radius, but all of the bubbles will be the same height.
point = {
r: function(d) {
var num = d.value;
return num
},
Adding the value of axis inside the r solve the problem, but now the problem is how to setup very high or very low values ? For e.g if there is 1 000 000 value the whole chart will be colored. Is there any simple workarounds for that ?
First of all, set r to return the square root of your chosen variable e.g. return sqrt(num), that way a circle representing a data point 100 times the size of another has 100, not 10,000, times the area (area=pi r2 and all that)
If the numbers are still too big use a linear scale to restrict them to a usable size:
rscale = d3.scale.linear().domain([1,1000]).range([0,10])
and then return rscale(sqrt(num))
If your problem is to represent large and small values on the same chart so small values don't disappear and large values don't exceed the chart size look at using a d3 log scale:
rscale = d3.scale.log().base(10).domain([1,1000]).range([0,10])
Of course on a log scale the areas aren't linearly proportionate any more so whether the sqrt step is necessary is debatable. If you don't just remember to adjust the domain to account for this - change it to domain([1,1000000])
if you don't know the size of your numbers beforehand it will be worthwhile looping through your dataset to pick out the min and max to plug into the domain value: domain([your_min, your_max]). my examples above all assume a max of one million.
Here's an example I forked on jsfiddle, numbers from a few hundred to over a hundred thousand are displayed using a log scale and all are visible but the differences are still obvious:
http://jsfiddle.net/m9gcno5n/

Angular-nvd3: same distance between data on x scale

By default scale of x axis is calculated from values. This gives uneven distance between two adjasted points. Like for example if I have an array of values like [1,2,5], there will be different distance on x axis for point, and also x axis labels will contain some other values, like 1,2,3,4,5. In case on dates displayed on x axis there may be cases when two equal dates are printed, looks ugly.
Take a look at this plunker. If you maximize your browser window, you could see that x axis labels have duplicates (like 02/09/2015 is visible 2 times on my screen). Also the distance between point is different.
How can I:
Make so that no duplicate x axis labes are present?
Distance between points is equaly distributed based in graph's width (not scaled based on values)?
You can explicitly set tickValues() and specify what ticks you want to show.
Alternatively, ticks() is more flexible, but gives you less control.
(Search for "D3 duplicate dates". This one may be helpful for example).
The reason the dates are repeating is that they are in fact different (equally spaced) timestamps that occur on the same day, since the spacing is < 24 hours. If you want to label with distinct dates, you could select a specific time on each day for the tick to fall on.

How do we change the tick values generated by a linear scale in a d3.js line plot?

I only had 5 values[1,2,3,4,5] as my y - coordinates in the d3.js line plot. But, I end up getting more values [0.5,1,1.5,2,2.5,3,3.5,4,4.5,5] Is there a way to edit the d3.js file or the html file inorder to plot the values as per my requirement?
The tick marks created by a d3 axis can be controlled in two ways:
Using axis.tickValues(arrayOfValues) you can explicitly set the values that you want to show up on the axis. The ticks are positioned by passing each value to the associated scale, so the values should be within your scale's domain. This works for any type of scale, including ordinal scales, so long as the values you give are appropriate to that scale.
Alternately, using axis.ticks(parameters) you can modify the way the scale calculates tick marks. The types of parameters you can use depends on the type of scale you're using -- the values you specify will be passed directly to the scale's .ticks() method, so check the documentation for each scale type. (Parameters will be ignored for ordinal scales, which don't have a ticks() method.)
For linear scales, the scale.ticks() method accepts a number as a parameter; the scale then generates approximately that many ticks, evenly spaced within the domain with round number values. If you do not specify a tick count, the default is to create approximately 10 ticks, which is why you were getting ticks on 0.5 intervals when your domain was from 0 to 5.
So how do you get the behaviour you want (no decimal tick values)?
Using .tickValues(), you would create an array of unique Y-values to be your ticks:
var yValues = data.map(function(d){return d.y;});
//array of all y-values
yValues = d3.set(yValues).values();
//use a d3.set to eliminate duplicate values
yAxis.tickValues( yValues );
Be aware that this approach will use the specified y values even if they aren't evenly spaced. That can be useful (some data visualization books suggest using this approach as an easy way of annotating your graph), but some people may think your graph looks messy or broken.
Using .ticks(), you would figure out the extent of your Y domain, and set the number of ticks so that you do not have more tick marks then you have integers available on your domain:
var yDomain = yScale.domain();
yAxis.ticks( Math.min(10, (yDomain[1] - yDomain[0]) );
This will create the default (approximately 10) ticks for wide domains, but will create one tick per integer value when the difference between the max and min of your domain is less than 10. (Although the tick count is usually approximate, the scale will always prefer integer values if that matches the tick count specified.)
Yes you can also try
yAxis.ticks(5).tickFormat(D3.numberFormat(",d"));
It does the trick of eliminating the decimal numbers, does not effect number of ticks
Here is a good resource for the format of the numbers using D3.

Calculating relative point coordinates for a graph?

I'm making a simple JavaScript graphing library using the canvas element. I really suck at math so I'm stuck with a simple issue.
If I have a number - for example 30000, and I want to plot it relatively to graph's height which is 400. How do I calculate the y value for that?
You would want to figure out your max for the graph. Say, in this case 50000. Then, take your height and divide it by the max (so 400/50000) to get a ratio multiplier. Any number you want to plot you multiply by that ratio and that should give you a number that fits on your space. Is that what you're asking for?
For that you need to first find out the maximum and minimum values that you need to plot. For example, in this list of (x,y) coordinates: [(1,3),(2,10),(3,0),(4,-10)], the max value is 10 and the min value is -10. This gives you a span of (max-min = 10-(-10) = ) 20.
Notice that you can now translate the set of y values into a number in the range [0,max-min] (i.e. [0,20] in this case). Here, a value of 0 will get plotted as a 0 in the graph and a value of 20 will get plotted as 400. Also, a value of 20/2 will be plotted as 400/2. Thus, a value of 20/x is plotted as 400/x. This means that any value can now be plotted as 400*value/20.
So, to translate a given value n to its corresponding y value on the graph, simply convert n to (n-min)*400/(max-min).

Categories