highchart with numberformat (unit) - javascript

I'm using Highcharts to generate a line chart.
And I'm having a problem with numberFormat:
var test = 15975000;
numberFormat(test, 0,',','.');
the result is: 15.975.000
But I want to transform 1000 to 1k, 100000 to 100k, 1000000 to 1m like this.
How can I deal with this problem?

numberFormat is available in Highcharts object.
Highcharts.numberFormat(test, 0,',','.');
Example http://jsfiddle.net/DaBYc/1/
yAxis: {
labels: {
formatter: function () {
return Highcharts.numberFormat(this.value,0);
}
}
},

Write your own formatter (see this example).
formatter: function() {
result = this.value;
if (this.value > 1000000) { result = Math.floor(this.value / 1000000) + "M" }
else if (this.value > 1000) { result = Math.floor(this.value / 1000) + "k" }
return result;
}
See also: How to format numbers similar to Stack Overflow reputation format

You just need to do that:
labels: {
formatter: function() {
return abbrNum(this.value,2); // Need to call the function for each value shown by the chart
}
},
Here is the Function used to transform the data to be inserted on javascript:
function abbrNum(number, decPlaces) {
// 2 decimal places => 100, 3 => 1000, etc
decPlaces = Math.pow(10,decPlaces);
// Enumerate number abbreviations
var abbrev = [ "k", "m", "b", "t" ];
// Go through the array backwards, so we do the largest first
for (var i=abbrev.length-1; i>=0; i--) {
// Convert array index to "1000", "1000000", etc
var size = Math.pow(10,(i+1)*3);
// If the number is bigger or equal do the abbreviation
if(size <= number) {
// Here, we multiply by decPlaces, round, and then divide by decPlaces.
// This gives us nice rounding to a particular decimal place.
number = Math.round(number*decPlaces/size)/decPlaces;
// Handle special case where we round up to the next abbreviation
if((number == 1000) && (i < abbrev.length - 1)) {
number = 1;
i++;
}
// Add the letter for the abbreviation
number += abbrev[i];
// We are done... stop
break;
}
}
return number;
}
Hope this works =)

In case you want to format a Highstock chart:
tooltip: {
pointFormatter: function() {
var result = this.y;
let header = '<table>';
let body = '<tr><td style = "color: ' + this.series.color + ';padding:0">'
+ this.series.name + ': </td><td style = "padding:0"><b>';
if (result > 1000000) {
result = Math.floor(result / 1000000) + "M"
}
else if (result > 1000) {
result = Math.floor(result / 1000) + "k"
}
return header + body + result + '</b></td></tr></table>';
}
},
I had trouble finding a way of adding Millions and Thousands while not hampering the data grouping functionality or the date.

Related

How to use the sum of values in an array inside FOR loop Node Js

My problem is that I want to get the total sum of SplitValue that has the SplitType of RATIO and use it inside the FOR loop to calculate the ratio of split. i.e. 3 + 2 = 5.
The comments I made in each line of my code below explain my troubles, I'm getting a loop of 3 and 5 instead of just 5. Thanks
var details = {
"Amount": 1396.8000000000002,
"SplitInfo": [{
"SplitType": "RATIO",
"SplitValue": 3
},
{
"SplitType": "RATIO",
"SplitValue": 2
}
]
};
var conRatioSumArr = 0;
var balance = details.Amount;
for (var i = 0; i < details.SplitInfo.length; i++) {
// I want to Get the total sum of SplitValue that has the SplitType of RATIO
// 3 + 2 = 5
// Here is what I've tried
splitTypeArr = details.SplitInfo[i].SplitType;
splitValueArr = details.SplitInfo[i].SplitValue;
if (splitTypeArr === "RATIO") {
conRatioSumArr += splitValueArr;
console.log(conRatioSumArr); // This gives me a loop of 3 & 5. I only need the total value which is 5 instead of both 3 and 5. Note that if I put this outside the for loop, I get only the total which is 5, but I want to use the sum inside of this for loop not outside the for loop to enable me calculate the ratio below.
splitAmount = (balance * (splitValueArr / 5)); // The total above is expected to replace the 5 here, but I'm getting a loop of 3 & 5 instead.
// Like this
// splitAmount = (balance * (splitValueArr / conRatioSumArr));
// splitAmount is expected to give: 838.08 and 558.7200000000001 split respectively
console.log(splitAmount);
}
}
I think you are making it too complicated.
All you need to do is get the total amount of parts in the ratio, and then do the (simple) math.
var details = {
amount: 1396.8000000000002,
splitInfo: [
{
type: "RATIO",
value: 3,
},
{
type: "RATIO",
value: 2,
},
],
};
let totalParts = 0;
for (const split of details.splitInfo) {
if (split.type == "RATIO") totalParts += split.value;
}
for (const split of details.splitInfo) {
if (split.type == "RATIO") {
let amountForSplit = details.amount * (split.value / totalParts);
console.log(amountForSplit);
}
}
This code is simple to understand and modify I hope to your liking. Using the array method reduce.
var details = {
"Amount": 1396.8000000000002,
"SplitInfo": [{
"SplitType": "RATIO",
"SplitValue": 3
},
{
"SplitType": "RATIO",
"SplitValue": 2
}
]
};
var result = details.SplitInfo.reduce(function(agg, item) {
if (item.SplitType == "RATIO") {
agg.sum = (agg.sum || 0) + item.SplitValue
agg.count = (agg.count || 0) + 1
}
return agg;
}, {})
console.log(result)
console.log("average is " + result.sum / result.count)

How to dynamically select pre-defined variables in a JS for-if loop?

I have a JSON object that contains Forex trades each with the following key:values
[...]
orderType: 0
orderLots: "1.00"
orderSymbol: "AUDCAD"
[...]
I now want to define a loop that iterates over each object and returns both the traded short and long volume for the major currencies (EUR|GBP|AUD|CHF|JPY|USD|CAD).
Each trade consists of a base currency in the example given: AUD and a counter currency in the example given: CAD
Each trade is either long (orderTypes 0, 2, 4) or short (orderTypes 1, 3, 5)
Each trade has a trade volume expressed in orderLots where 1.00 equals 100.000 traded units
Now the idea for the loop is as follows:
Check if it is a currency pair that contains two major currencies (e.g. EURUSD, AUDCAD, etc.)
If so, calculate the traded volume for the base and counter currency
If not, calculate the traded volume either for the base or counter currency, depending on which one is the major
My issue (see at the bottom of the code snippet) is that I don't know how to pick the pre-defined variables dynamically as needed. Otherwise I will have to set up dozens of else if statements.
// define variables
var eurVolumeBought = 0
var eurVolumeSold = 0
var usdVolumeBought = 0
var usdVolumeSold = 0
[...]
var chfVolumeBought = 0
var chfVolumeSold = 0
// iterate each trade in returned JSON object
for (var i = 0; i < tradesTotal; i++) {
symbol = trades[i].fields.orderSymbol
// returns e.g. AUD/CAD
symbolBase = symbol.slice(0, 3)
// returns e.g. AUD
symbolCounter = symbol.slice(3, 6)
// returns e.g. CAD
lots = trades[i].fields.orderLots
// returns e.g. 1.00
orderType = trades[i].fields.orderType
// orderTypes 0, 2, 4 are long trades and 1, 3, 5 are short trades accordingly
// check for main pairs where that contain two major currencies
if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) && symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/){
// Create logic for long trades
if (orderType == '0' || orderType == '2' || orderType == '4') {
// >>>> here i run into issues <<<<
// In the example given, we have a AUDCAD long trade of 100.000 units.
// Thus, I want to dynamically pick the audVolumeBought and cadVolumeSold variables
// to increase them accordingly. My foolish approach right now is as follows:
symbolBase = symbolBase.toLowerCase()
(symbolBase + 'volumeBought') = lots * 100.000 // I try to grab audVolumeBought variable here
}
}
Edit to #kastenbutts comment:
The resulting variable's values will be pushed in a chart.JS chart.
So for each trade object there will be either one or two calculations and that's it.
Using
result[symbolBase + 'volumeBought'] = result[symbolBase + 'volumeBought'] + (lots * 100.000)
returns NaN
As a first step you could collect all trades for each currency in an object:
let result = {}; // Each key in this object will correspond to a currency
for (var i = 0; i < tradesTotal; i++) {
symbol = trades[i].fields.orderSymbol
symbolBase = symbol.slice(0, 3)
symbolCounter = symbol.slice(3, 6)
lots = trades[i].fields.orderLots
orderType = trades[i].fields.orderType
if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) && symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/){
if (orderType == '0' || orderType == '2' || orderType == '4') {
symbolBase = symbolBase.toLowerCase()
if(result.hasOwnProperty(symbolBase + 'volumeBought')) {
result[symbolBase + 'volumeBought'] += lots * 100.000
}
else {
result[symbolBase + 'volumeBought'] = lots * 100.000
}
}
// ... handle short case
}
As a next step you need to transform the data into a chart object as required by ChartJs. If you want a simple bar chart you would do it like this:
let data = [];
let label = [];
for(let cur in result) {
label.push(cur);
data.push(result[cur]);
}
let barChart = {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: data
}]
}
}
Note: I'm not sure if that exactly fits the logic you require. But it might be a good starting point.
Here is a solution with just three if expressions:
var ma=['EUR','GBP','AUD','CHF','JPY','USD','CAD'];
var volumeBought={}, volumeSold={};
var jo=[
{fields:{orderType: 0,orderLots: "1.00",orderSymbol: "AUDCAD"}},
{fields:{orderType: 1,orderLots: "0.80",orderSymbol: "USDEUR"}},
{fields:{orderType: 2,orderLots: "1.40",orderSymbol: "EURAUD"}},
{fields:{orderType: 3,orderLots: "2.20",orderSymbol: "AUDCAD"}},
{fields:{orderType: 4,orderLots: "1.10",orderSymbol: "CADDKK"}},
{fields:{orderType: 5,orderLots: "1.30",orderSymbol: "GBPUSD"}},
{fields:{orderType: 0,orderLots: "3.04",orderSymbol: "DKKCAD"}},
{fields:{orderType: 1,orderLots: "1.10",orderSymbol: "USDCHF"}},
{fields:{orderType: 2,orderLots: "0.90",orderSymbol: "JPYEUR"}},
{fields:{orderType: 3,orderLots: "0.40",orderSymbol: "AUDJPY"}},
{fields:{orderType: 4,orderLots: "2.30",orderSymbol: "CHFGBP"}},
{fields:{orderType: 5,orderLots: "3.10",orderSymbol: "EURUSD"}},
{fields:{orderType: 0,orderLots: "4.25",orderSymbol: "AUDNGN"}},
{fields:{orderType: 1,orderLots: "0.60",orderSymbol: "USDGBP"}},
{fields:{orderType: 2,orderLots: "1.70",orderSymbol: "GBPEUR"}}
];
jo.forEach(({fields})=>{
if (!(fields.orderType%2)) {
var sld=fields.orderSymbol.substr(0,3),
bgt=fields.orderSymbol.substr(3,6),
lots=fields.orderLots*100000;
if (ma.indexOf(sld)>-1)volumeSold[sld]=(volumeSold[sld]||0) + lots
if (ma.indexOf(bgt)>-1)volumeBought[bgt]=(volumeBought[bgt]||0) + lots
}
});
console.log('sold:',JSON.stringify(volumeSold))
console.log('bought:',JSON.stringify(volumeBought))
Most of the above code deals with generating some sample data. The actual work happens in just a few lines at the bottom. I collect the "sold" and "bought" quantities whenever the given conditions ("long trade" and "major currency") are fulfilled. The result is displayed as a JSON string, but it really is available as a JS object which of course can be used in many different ways.
The expression volumeSold[sld]=(volumeSold[sld]||0) + lots will add the value of lots to the object's property, regardless of whether it existed before or not (in that case it is initialised with "0" first).
I finally got a working solution. For the sake of completeness, find it below:
let resultBought = {}
let resultSold = {}
for (var i = 0; i < tradesTotal; i++) {
symbol = trades[i].fields.orderSymbol
// returns e.g. EUR/USD
symbolBase = symbol.slice(0, 3)
// returns e.g. EUR
symbolCounter = symbol.slice(3, 6)
// returns e.g. USD
lots = trades[i].fields.orderLots
// returns e.g. 1.00
orderType = trades[i].fields.orderType
// orderTypes 0, 2, 4 are long trades, 1, 3, 5 shorts accordingly
// check for major pairs where XXX/YYY = defined currencies
if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) && symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/)) {
// Long Trades Major Pairs
if (orderType == '0' || orderType == '2' || orderType == '4') {
// Base currency
if(resultBought.hasOwnProperty(symbolBase + 'VolumeBought')) {
resultBought[symbolBase + 'VolumeBought'] += lots * 100.000
}
else {
resultBought[symbolBase + 'VolumeBought'] = lots * 100.000
}
// Counter currency
if(resultSold.hasOwnProperty(symbolCounter + 'VolumeSold')) {
resultSold[symbolCounter + 'VolumeSold'] += lots * 100.000
}
else {
resultSold[symbolCounter + 'VolumeSold'] = lots * 100.000
}
// Short Trades Major Pairs
} else if (orderType == '1' || orderType == '3' || orderType == '5') {
// Base currency
if(resultSold.hasOwnProperty(symbolBase + 'VolumeSold')) {
resultSold[symbolBase + 'VolumeSold'] += lots * 100.000
}
else {
resultSold[symbolBase + 'VolumeSold'] = lots * 100.000
}
// Counter currency
if(resultBought.hasOwnProperty(symbolCounter + 'VolumeBought')) {
resultBought[symbolCounter + 'VolumeBought'] += lots * 100.000
}
else {
resultBought[symbolCounter + 'VolumeBought'] = lots * 100.000
}
}
// consider the non major pairs
} else if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) || symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/)) {
if (orderType == '0' || orderType == '2' || orderType == '4') {
if(resultBought.hasOwnProperty(symbolBase + 'VolumeBought')) {
resultBought[symbolBase + 'VolumeBought'] += lots * 100.000
}
else {
resultBought[symbolBase + 'VolumeBought'] = lots * 100.000
}
} else if (orderType == '1' || orderType == '3' || orderType == '5') {
if(resultSold.hasOwnProperty(symbolBase + 'VolumeSold')) {
resultSold[symbolBase + 'VolumeSold'] += lots * 100.000
}
else {
resultSold[symbolBase + 'VolumeSold'] = lots * 100.000
}
}
}
}

Round function and add "$"

I have searched and tried several times but still can't get it. How do I prepend "$" and round the value to the nearest 100th of a decimal. Example: $100.00
<script>
$.get("https://api.coinmarketcap.com/v1/ticker/", function(data, status) {
for (var i = 0; i < data.length - 1; i++) {
if (data[i].id == "unit") {
$("#unit").html(parseFloat(data[i].price_usd) * 500000);
}
}
});
</script>
Use Number.prototype.toFixed() to make fixed number of decimals, concatinate strings as usual, because toFixed returns string:
function toCurrency(value = 0, symbol = '$', onEnd = false) {
if (onEnd) {
return Number(value).toFixed(2) + symbol;
}
return symbol + Number(value).toFixed(2);
}
console.log(toCurrency(123.7483));
console.log(toCurrency(123));
console.log(toCurrency(123, ' USD', true));

jqxChart with relative values

I was playing around with the waterfall series of the jqxChart.
According to its API, the following piece of code defines the values of the axis, in this case it's the y-axis:
valueAxis:
{
title: {text: 'Population<br>'},
unitInterval: 1000000,
labels:
{
formatFunction: function (value) {
return value / 1000000 + ' M';
}
}
}
Is it possible to define the intervals not with absolute values, but with relative values. So that the interval are e.g. 10% and the overall value is 100%?
Simply doing unitInterval: '10%' doesn't work.
This is how it should look like:
Here is a fiddle.
I think you're looking for these options :
logarithmicScale: true,
logarithmicScaleBase: 1.10,
Example:
valueAxis:
{
title: {text: 'Population<br>'},
logarithmicScale: true,
logarithmicScaleBase: 1.10,
labels:
{
formatFunction: function (value) {
return value / 1000000 + ' M';
}
}
},
Edit:
var accuracy = 2;
var first = data[0].population;
var last = data[data.length - 2].population;
var unit = (100 / last);
// convert raw data to differences
for (var i = 0; i < data.length - 2; i++)
data[i].population = (data[i].population * unit).toFixed(accuracy);

Greedy Algorithm in JavaScript

Here is the question that I need to consult for help:
Write a greedy algorithm to make change with the fewest coins possible
using the Greedy Algorithm. You are given an array of coin values and
an amount: computeChange(coins, amount). Return an array with the
counts of each coin.
For example: computeChange([50, 25, 10, 5, 1], 137) should return
the array [2, 1, 1, 0, 2] which indicates how many of each coin: 2
50-cent pieces, 1 quarter (25 cents), 1 dime (10 cents), no nickels (5
cents), and 2 pennies (1 cent), which add up to 137 cents.
The array you return from computeChange should be the same length as
the first argument (coins). Assume that coins contains the values of
different coin types in decreasing order.
The greedy algorithm says that you repeatedly look for the largest
coin less than or equal to the remaining amount of money, then
subtract that coin from the remaining amount. When the remaining
amount reaches zero (or less), return the counts of coins used. (This
algorithm is not always optimal.)
You can change the variables COINS, which gives the values of the
different coins you can use to make change, and AMOUNT, which is the
total value of the change to make. Changing these values might be
useful for debugging your program.
Here is my code which I did but it did not display the standard change for 36 cents. Can anyone help me? Thank you.
<html>
<head>
<title>The Greedy Algorithm</title>
<script>
// ======== Here is the problem to be solved: ========
COINS = [50, 25, 10, 5, 1];
AMOUNT = 137
coincount = [0,0,0,0,0];
// ======== Here is where your solution begins: ========
// define the function named computeChange here:
function computeChange(coins, amount) {
var i = 0; var creminder = AMOUNT; var ccoin;
while( i < COINS.length )
{
while ( COINS[i] <= creminder )
{
creminder = creminder - COINS[i];
ccoin = coincount [i] ;
ccoin += 1;
coincount [i] = ccoin ;
}
i++;
}
return coincount;
}
// ===================================================================
// ======== Everything below here simply displays your output ========
// ======== Do NOT change anything below this line ===================
// ===================================================================
function rightJustify(s, w) {
// return a string of width w with s in the rightmost characters and
// at least one space on the left. For simplicity, assume w < 20.
var slen = s.length;
var blanks = " "
return blanks.substr(0, Math.min(20, Math.max(1, w - slen))) + s;
}
function makeChange() {
// compute change as an array: each element of change tells
// how many of the corresponding value in COINS to give. The
// total value should equal AMOUNT.
var change = computeChange(COINS, AMOUNT);
// now format the results. Output should look like:
// NUMBER VALUE
// 1 50
// 0 25
// 1 10
// 1 5
// 3 1
// TOTAL AMOUNT: 68 (total is correct)
//
// First, we'll do some type checking in case change is not of the
// expected type.
change = [].concat(change); // force whatever it is to be an array
// it should be an array of numbers, so let's check
for (i = 0; i < change.length; i++) {
if (typeof(change[i]) != 'number') {
return "Error: the function computeChange did not return " +
"an array of numbers.";
}
}
if (change.length > COINS.length) {
return "Error: the function computeChange returned an array " +
"longer than the length (" + COINS.length + ") of COINS.";
}
if (change.length < COINS.length) {
return "Error: the function computeChange returned an array " +
"shorter than the length (" + COINS.length + ") of COINS.";
}
var output = "<pre>NUMBER VALUE\n"
var sum = 0;
for (i = 0; i < change.length; i++) {
sum += change[i] * COINS[i];
var n = change[i].toString();
var a = COINS[i].toString();
output += rightJustify(n, 4) + rightJustify(a, 9) + "\n";
}
output += "TOTAL AMOUNT: " + sum + " (total is ";
output += (sum == AMOUNT ? "correct" :
"incorrect, should be " + AMOUNT) + ")\n";
return output;
}
function runSolution()
{
parent.console.log('loaded, calling runSolution()\n');
parent.console.log('answer: ' + document.getElementById('answer').toString());
document.getElementById('answer').innerHTML = makeChange();
}
</script>
</head>
<body>
<!-- the output is displayed using HTML -->
<!-- the ? will be replaced with the answer -->
<div id = "answer">?</div></p>
<br>
<script>runSolution();</script>
</body>
</html>
Thoughts:
After reading the replys, first at thought is that this may be used to other codes that we didn't see here, so we need to make the function sufficient to solve the question by input, not using the GLOBAL VALUES like AMOUNT, COINS and coincount, instead, use params given like coins and amount, and return a self created coincount.
I'll explain this directly use comments in the codes
function computeChange(coins, amount) {
// Create a array that is used to return the final result, instead of the global one.
var coincount = [];
// use the given `amount` to set `creminder ` rather than `AMOUNT` which may not be accessible if your code is called otherplace rather than here.
var i = 0; var creminder = amount; var ccoin;
while( i < coins.length )
{
// Lazily init the used coin for coin type i to 0.
coincount[i] = 0;
while ( coins[i] <= creminder )
{
creminder = creminder - coins[i];
ccoin = coincount[i];
ccoin += 1;
coincount[i] = ccoin;
}
i++;
}
return coincount;
}
Your origin version's creminder is determined by AMOUNT, so no matter I call computeChanges(COINS, AMOUNT) or computeChanges(COINS, 37), the result will be the same, because the 37 in the second example is not used, ignored and creminder is still set to AMOUNT. Both Nina Scholz and I do is to make that given amount account, so it matters when your function generates a result set.
While the answers above are very correct, I think one could also think of the solution to this particular problem in a different way.
With the example of computeChange([50, 25, 10, 5, 1], 137), a single loop could be used to get the required solution.
function computeChange(changeArray, amount) {
const result = [];
for (let i = 0; i < changeArray.length; i++) {
let changeAmount = Math.floor(amount / changeArray[i]);
amount -= (changeArray[i] * changeAmount);
result.push(changeAmount);
}
return result;
}
computeChange([50, 25, 10, 5, 1], 137); //  [2, 1, 1, 0, 2]
Some remarks:
You get values for coins and amount. The original function access
COINSand AMOUNT even if there is a local copy of this values.
creminder is not necessary, because you have amount.
ccoin is not necessary, because you can directly subtract the value of the selected coin from the amount.
var COINS = [50, 25, 10, 5, 1],
AMOUNT = 36; //137
function computeChange(coins, amount) {
var i = 0,
coincount = coins.map(function () { return 0; }); // returns an array and for each element of coins zero
while (i < coins.length) {
while (coins[i] <= amount) {
amount -= coins[i];
coincount[i]++;
}
i++;
}
return coincount;
}
out(JSON.stringify(computeChange(COINS, AMOUNT), null, 4), true);
function out(s, pre) {
var descriptionNode = document.createElement('div');
if (pre) {
var preNode = document.createElement('pre');
preNode.innerHTML = s + '<br>';
descriptionNode.appendChild(preNode);
} else {
descriptionNode.innerHTML = s + '<br>';
}
document.getElementById('out').appendChild(descriptionNode);
}
<div id="out"></div>
function cc(c, a) {
for (var ra=[],i=0,r=a; i<c.length; ra[i] = (r/c[i])|0, r -= ra[i]*c[i], i++);
return ra;
}
function cc2(c, a) {
return c.map((c, i) => { var t = (a/c)|0; a -= c*t; return t; })
}
cc([50, 25, 10, 5, 1], 137); // [2, 1, 1, 0, 2]
cc2([50, 25, 10, 5, 1], 137); // [2, 1, 1, 0, 2]

Categories

Resources