Math: I need to normalize some bar graphs - javascript

I'm generating bar graphs. The range of data generating said graphs is very wide, which means some areas of the graph are always low, and some areas go off the chart.
What's the math to "normalize" this towards a certain number (e.g. 200), so large values are shrunk the larger they are, and smaller values are increased?

If you are talking about actually changing the data for display purposes, then there are a few basic approaches to bring values closer to a target value. The simplest is to just do a weighted average with that value: A' = (1-α)*A + α*B where alpha is a weight between 0 and 1, A is a number on your graph, and B is the target value.
For instance, if you were trying to 'normalize' to 200 and your numbers were 100 120 200 220 400 then plugging in each for A, 200 for B, and .5 for alpha, you would get 150 160 200 210 300
You can choose a different alpha to adjust how much you want to stretch the data towards the target value. Higher numbers like .9 will stretch the data more and lower numbers like .1 will stretch the data less.

I dont know if you are willing to read a little but I found the the scaling tutorial for d3.js framework (http://d3js.org/) is a very solid introduction to the scaling part of visualisation:
http://alignedleft.com/tutorials/d3/scales/

For a zero-based graph : compute the max of your value, then display for each bar :
barHeight[i] = (maxBarHeight*value[i])/maxVal;
If you want your graph to be based on the minimum value and not zero, you might still want the
graph to have a non-zero height for the bar near the min value. So compute the minimum value, and display :
barHeight[i] = minBarHeight +
(maxBarHeight - minBarHeight ) * (value[i] - minVal) / ( maxVal - minVal );
( Rq : if minVal is Zero or 'near' zero, set minVal = minBarHeigth = 0 and you have the first case )

Related

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/

How do I calculate logrithmic labels for a VU meter scale?

I writing a meter widget using canvas and need to calculate the label values for the scale. No problem except when I'm trying to re-create the scale for a VU meter. I understand it's logrithmic, but the values aren't powers of 10 on that type of meter.
see: https://en.wikipedia.org/wiki/VU_meter
The function I have is given the min and max values for the scale. For normal scales, it also is given the step between values. For example, given -20 and 30 with a step of 10, it would produce labels:
-20 -10 0 10 20 30
For a VU meter given -20 and 6, I need to produce labels:
-20 -10 -5 -3 0 3 6
And, the spacing isn't the same on the scale between those values.
I am not asking for actual code examples, but instead for ideas on how to best approach implementing this.
Should I write the function so one of the parameters is a list of labels, then plot them on a logarithmic scale? That doesn't appear to work properly because the numbers do not end up in the right places as seen in the image above of a proper VU meter.
Is there some special formula just for dB levels that isn't a simple log function?
Again, I'm not asking for code examples, just for some help understanding the best approach to use.
Thanks!
I suppose you have a value-to pixel function. What you need to write is the inverse function of that.
When you have the inverse function, you just divide the screen area to N equal parts (in the picture you have 6 regions). One region will be X pixels in width. Now you can use your inverse function to get the value for that pixel-position.
This will not be an integer, it will be something like 3.434 or 11.34 - you need a prettyfier function which will generate the closest "pretty" number (let's say just chop off the parts after the decimal).
Now you take the pretty value and calculate the pixel position for it with your original function.
Some code:
function value2px(value, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin);
var pixelWidth = pxMax - pxMin;
var ratio = pixelWidth / valueWidth;
return ratio * (sigLog(value) - sigLog(valueMin)) + pxMin;
}
function px2value(px, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin);
var pixelWidth = pxMax - pxMin;
var ratio = pixelWidth / valueWidth;
return sigExp((px - pxMin) / ratio + sigLog(valueMin));
}
and the demo:
http://jsfiddle.net/ambcwoLg/1/

Simple algorithm for generating random numbers with bigger/smaller probability

I'm currently working on a game, with scrollable screen and I need to find a simple algorithm for placing obstacles in the game. I have a gameSpeed, that is increased in time (from 1 to 12, increased by 0.005 each 1/60s) and a range of available positions between 200 and 600 (ints). I'd like to achieve a bigger probability of receiving smaller number when the speed is bigger, but it's my 14th hour straight coding and I cannot come up with anything usable and not overcomplicated. I'd like to minimize Math and random functions so that the rendering loop won't take too long. Any help appreciated !
You could square or square-root the random number to shift the density in one direction. Math.random()*Math.random() will have a higher probability to produce smaller numbers (near 0) than higher ones (near 1).
Your formula could be like
var position = Math.pow(Math.random(), gameSpeed / 3) * 400 + 200;
The simplest answer I can think of is to create an array having more lower numbers compared to higher ones, for example, for producing random between [1,5] (both inclusive). So your array may look like [1,1,1,1,1,2,2,2,2,3,3,3,4,4,5]
And when you randomly pick an element from that array you will have a higher chance of picking up low number compared to high one.
Another way might be to have two (or more) percentages:
say, start with 10% of the time we access 90% of the range, and 90% of the time we access the other 10%. Then we gradually flip those numbers as the speed increases. For example,
var lBound = 200,
uBound = 600,
range = uBound - lBound,
gameSpeed = 1,
initialMarker = 0.1,
percentageRange = 1 - 2 * initialMarker,
marker = (gameSpeed - 1) / 11 * percentageRange + initialMarker,
position
Math.random() <= marker ? position = Math.floor(Math.random() * (1 - marker) * range) + lBound
: position = uBound - Math.floor(Math.random() * marker * range)
console.log(position)
Try changing gameSpeed and see what happens. Change initialMarker for a different set of percentages (currently set at 0.1, which means 10% / 90%).

Pie Piece Too Small

I have a dynamic data array that contains 3 ints that are used to build a pie chart. In most cases it works fine IE: [5, 10, 3]. The pie chart renders correctly and you see all the pieces.
However in some cases the numbers can be widely different. IE [1,500,250] or [400,1,2]. When this is the case you will only see the larger of the pie pieces and the smaller ones become so small they can not be seen; or clicked.
I need some way of correcting the data array for these cases. I have the ability to retain the true value while adjusting the display value so the pieces show up. What I am looking for is a check to see if it's necessary and then a relative number to adjust it by based on the other values.
Suggestions?
Well firstly I'd say you aren't so much "correcting" the data as fudging the data to meet your requirements.
Basically, there is a minimum percentage for which a slice of that proportion will be clickable and you will need to bring all pieces up to at least this size.
Of course - this can't work at the most extreme examples. If you had 1,000,000 slices all of the same value then no matter how you scaled them, some of them are going to be too small (or all of them).
You also need to be aware of how scaling certain very small slices will throw out the apparent proportions between other, larger, slices.
But - a very crude way of doing it could be something like...
var minPC = 0.5 , // the minimum %age slice visible
total; // total should be set to the sum of the values of all your slices
var minValue = total / 100 * minPC; // The smallest value visible (given the current total)
for (var slice in slices) { //assuming slices is a standard JS 'array'
if ( slices[slice] < minValue ) slices[slice] = minValue;
}
of course making the slices bigger like this will in turn increase the total - meaning that the small slices will still be less than the minimum visible percentage. You will need to make minPC sufficiently large to cope with this. And of course the more very small slices you have the worse this effect will be. You could account for this be re-scaling the larger slices.
However - I would advise you find a better way of the user interacting with the data by letting them select on/off slices - or by having slices 'explode'.
You seem to want to resize the segments of the pie if they are too small to make them visible/clickable.
May I suggest that instead of solving the problem this way (which would give an invalid
representation of the data), you could instead use labels outside of the pie chart to point at the segments? These labels could then, themselves, be made clickable.
The sum of the values in your array represent the entire "size" of the pie. The percentage of the pie each value has is the visual weight of that piece. You probably want to set a minimum threshold for the percentage size of each piece (the minimum threshold would be related to the diameter of your chart).
ie. [500, 490, 10] -> [500/1000, 490/1000, 10/1000] -> [50%, 49%, 1%]
If any value is less than your minimum threshold, you need to increase it to the minimum threshold and adjust your other values accordingly, so they all add up to 100%
It is related with fact that all points are sum and each value is calculated to pixels.

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