I need to add commas to numbers in a ChartJS graph. Ex. Data points might be 1032.05, 4334.75, 8482.46 and I need it to display as 1,032.05, 4,334.75, 8,482.46.
Here is the link to a development site with current code: http://investingcalculator.azurewebsites.net/
I am currently passing in the values as an array on calculate and since arrays are comma delimitated, I am not sure how to change the data points to have commas.
My calculate code is as follows. Please note that I am using requires:
define(['jquery', 'chartjs'], function ($) {
var investCalc = {
calculate: function () {
var currentbalance = $("#currentbalance");
var interestrate = $("#interestrate");
var yearscontributing = $("#yearscontributing");
var monthlycontribution = $("#monthlycontribution");
var year = [];
var yearlybalance = [];
$('#calculate').on('click', function () {
var P = parseFloat(currentbalance.val());
var r = parseFloat(interestrate.val());
var t = parseFloat(yearscontributing.val());
var add = parseFloat(monthlycontribution.val());
var addtotal = add * 12;
if (isNaN(P) || isNaN(r) || isNaN(t) || isNaN(add)) {
alert('All Inputs Must Be Numbers');
return;
}
// Loop to provide the value per year and push them into an array for consumption by the chart
for (var i = 0; i < t; i++) {
// Convert int of interest rate to proper decimal (ex. 8 = .08)
var actualrate = r / 100;
var A = (P + addtotal) * (1 + actualrate);
var P = A;
// Convert the loop from starting at 0 to print the actual year
startyear = i + 1;
actualyear = "Year " + startyear;
// Format the number output to 2 decimal places
formattedValue = A.toFixed(2);
endBalance = P.toFixed(2);
// Push the values in the array
year.push(actualyear);
yearlybalance.push(formattedValue);
}
$("#endingbalance").val(endBalance);
// Bar chart
var barChartData = {
labels: year,
datasets: [
{
label: "Investing Results",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: yearlybalance
}
]
}
var ctx = $("#canvas").get(0).getContext("2d");
// This will get the first returned node in the jQuery collection.
newBarChart = new Chart(ctx).Bar(barChartData, {
responsive: true
});
$('#calculate').hide();
var chartjs = Chart.noConflict();
});
// Reset values and page
$('#reset').on( 'click', function () {
location.reload();
});
}
};
return investCalc;
});
You can add "multiTooltipTemplate" or "tooltipTemplate" to your chart options. Below is a copy of your code with "multiTooltipTemplate" added as an option. I have a small function that I use to add commas, I've included that below also.
newBarChart = new Chart(ctx).Bar(barChartData, {
responsive: true,
multiTooltipTemplate: "$<%=addCommas(value)%>"
});
function addCommas(nStr){
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
I hope this helps, we use it for our tooltips in Chart.js and it works great.
I recommend this regex in a replace function to add commas in. Like this:
endBalance = P.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")
Related
I have existing charts that displays data for a full day 12:00am - 12:00am.
Now required to change one chart forward to display 4:00am - 4:00am.
I have managed to shift the x axis labels (.add(4, 'hours')) but the chart data is still in the same position.
How do I shift the charted data forward 4 hours?
Limited scope to change global variables as this will impact other charts.
var getChartSeries = function(response, chart_series_data) {
var lines = response.graph_data.lines;
for (var i=0; i<lines.length; i++) {
var series = lines[i];
var dateFormat = graphDateFormat;
if (chartIntraday) dateFormat = 'HH:mm:ss';
var currSeriesData = [];
for (var j=0; j<series.data.length; j++) {
var row = series.data[j];
var yValue = parseFloat(row[1]);
var point = {
x: moment(row[0], dateFormat).add(4, 'hours').valueOf(),
y: yValue,
displayValue: row[3]
};
currSeriesData.push(point);
}
// Set the series name, legend label, and the line identifier
var name = formatLegendLabel(series.display_name, response);
var label = response.label;
if (response.display_name != undefined && response.display_name != '') label = series.display_name + ' : ' + label;
By default chart adjusts extremes to the provided data. To display these few hours before the first point use xAxis.min property.
Live demo: http://jsfiddle.net/kkulig/xqdqooh9/
API reference: https://api.highcharts.com/highcharts/xAxis.min
I have the following code:
http://jsfiddle.net/eM2Mg/7027/
g = new Dygraph(
// containing div
document.getElementById("graphdiv"),
// CSV or path to a CSV file.
("Response Time,Loop\n" +
"09/02/2015,175\n" +
"09/04/2015,170\n" +
"09/06/2015,180\n" +
"09/08/2015,177\n" +
"09/11/2015,179\n"+
"09/30/2015,165\n"),
{
strokeWidth: 3,
}
);
Is it possible in dygraphs to set the same distance between x-axis values?
I want to set the same line length among all points no matter of the date time space.
I doubt you can get it to fully work as your requirement is against how data is arranged on graphs, but you can use parse & format callbacks to come close:
var i = 0;
var labels = [];
g = new Dygraph(
// containing div
document.getElementById("graphdiv"),
// CSV or path to a CSV file.
("Response Time,Loop\n" +
"09/02/2015,175\n" +
"09/04/2015,170\n" +
"09/06/2015,180\n" +
"09/08/2015,177\n" +
"09/11/2015,179\n" +
"09/30/2015,165\n"), {
strokeWidth: 3,
xValueParser: function (str) {
console.log(str);
labels[++i] = str;
return i;
},
axes: {
x: {
valueFormatter: function (i) {
return labels[i];
},
axisLabelFormatter: function (i) {
return labels[i];
}
}
}
});
See fiddle
I am creating a scattered Graph using NVD3 using the code they have provided in their limited documentation. I have created a Scatter graph function that loops over a JSON and pushes the values to the data array.
Now I have 2 values for x axis in my Json , x and run Number. What i want is that the graph should be plotted for the value "x" (which have equal gaps) but it should display values of Run Number on the x axis (which have unequal gaps). We want to do this to make the graph more symmetric, as it is not important for us to display the gaps in graph accurately.
What i did was create a new Array xAxisValue and push the Run Numbers onto it while we loop the JSON to get values. values for x are pushed onto the data array ,
Then using
chart.xAxis.axisLabel('Run No.').tickFormat(d3.format('0d')).tickValues(
xAxisValue);
I set the Tick Values to the xAxisValue (run Number) and then pass the data variable to the draw chart function
d3.select('#chart svg').datum(myData).call(chart);
But this does not seem to work. My Axis is blank and hovering over a value displays the tool tip displays values of x instead of run number.
Because we are dynamically updating the graph i have separated the add Graph and upgrade graph function
Here is the code
function addGraph() {
var jsons = [];
chart = nv.models.scatterChart().showDistX(true).showDistY(true)
.transitionDuration(350).color(d3.scale.category10().range());
chart.tooltipContent(function(key) {
return '<h3>' + key + '</h3>';
});
chart.scatter.onlyCircles(false);
var myData = scatterData(2, 11, jsons);
d3.select('#chart svg').datum(myData).call(chart);
// add zoom handler
nv.utils.windowResize(chart.update);
return chart;
}
Upgrade Graph Function
function upgradeGraph() {
minValue = 1000000, maxValue = 0, minValueY = 100000000, maxValueY = 0;
var jsons = [];
d3.select('svg').text('');
if ($("#check2").is(':checked')) {
jsons.push("charge_ONTk_Barrel_L2_mpv.json");
}
if ($("#check1").is(':checked')) {
jsons.push("charge_ONTk_Barrel_L1_mpv.json");
}
if ($("#check3").is(':checked')) {
jsons.push("charge_ONTk_Barrel_L3_mpv.json");
}
var myData = scatterData(2, 11, jsons);
chart.xAxis.axisLabel('Run No.').tickFormat(d3.format('0d')).tickValues(
xAxisValue);
chart.yAxis.axisLabel('S/N (mpv)').tickFormat(d3.format('.04f'));
for (var i = 0; i < xAxisValue.length; i++) {
console.log("Run Number: " + xAxisValue[i]);
}
console.log("Min Y: " + minValueY + " Max Y " + maxValueY);
chart.forceX([ minValue - 2, maxValue + 2 ]);
chart.forceY([ minValueY - 3, maxValueY + 3 ]);
d3.select('#chart svg').datum(myData).call(chart);
// add zoom
addZoom({
xAxis : chart.xAxis,
yAxis : chart.yAxis,
yDomain : chart.yDomain,
xDomain : chart.xDomain,
redraw : function() {
chart.update();
},
svg : chart.svg
});
nv.utils.windowResize(chart.update);
return chart;
}
And the ScatterData Function
function scatterData(groups, points, jsons) {
var data = [];
data.push({
key : 'Error',
values : [],
color : '#FBEC5D'
});
data.push({
key : 'Bin Content ',
values : [],
color : '#0D4F8B'
});
for (var i = 0; i < jsons.length; i++) {
xAxisValue = [];
var jsonURL = jsons[i];
var xmlhttp = new XMLHttpRequest();
var url = "alljsons/" + jsons[i];
var parameters = location.search;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var myArr = JSON.parse(xmlhttp.responseText);
var jsonName = jsonURL.split(".");
var temp = jsonName[0];
var value = myArr[temp];
// $(".title" + loop).html(temp);
for ( var i in value) {
if (value[i].run > maxValue) {
maxValue = value[i].x;
}
if (value[i].run < minValue) {
minValue = value[i].x;
}
if (value[i].y > maxValueY) {
maxValueY = value[i].y;
}
if (value[i].y < minValueY) {
minValueY = value[i].y;
}
xAxisValue.push(value[i].run);
data[1].values.push({
x : value[i].x,
y : value[i].y,
size : 6 // Configure the size of each scatter point
,
shape : "circle"
});
var err = value[i].y - value[i].yErr;
if (err < 0) {
err = 0;
console.log("error: " + err);
}
data[0].values.push({
x : value[i].x,
y : err,
size : 6 // Configure the size of each scatter point
,
shape : "triangle-down"
});
}
}
};
xmlhttp.open("GET", url, false);
xmlhttp.send();
}
return data;
}
Here is the Output i am getting
If I understand your question correctly:
For the x-axis ticks, I would use D3's axis.tickformat function. You could create a function mapXToRunNumber(x) that takes an x value and returns a run number (you seem to be close to having this already). Then, you would use: chart.xAxis.tickFormat(mapXtoRunNumber);
For the tooltip to also show the same value as the x-axis, you would use the nvD3 function chart.interactiveLayer.tooltip.headerFormatter(mapXToRunNumber).
SOLUTION: I realized that the current Regional Setting of test environment is set to Turkish, and it uses comma for decimal symbol. In my local, it is set to UK, and that's the reason that the code works in my local and doesn't work in test. I guess I'll replace all commas with dots beforehand. Thanks for all the replies.
I'm trying to fill a bar chart with following data:
var oneToTen = [0,1,2,3,4,5,6,7,8,9,10];
var ticks = [[0, 'Atmosfer'],[1, 'Servis'],[2, 'Yemeklerimiz']];
var labels = ['Atmosfer','Servis','Yemeklerimiz'];
var mainQuest_d1 = 8,16666666666667;
var mainQuest_d2 = 7,95833333333333;
var mainQuest_d3 = 8,125;
var d_main_quest_bar = [[0, 8,16666666666667],[1, 7,95833333333333],[2, 8,125]];
I get this error:
Uncaught SyntaxError: Unexpected number
I can't see what's wrong the code above. It works fine in localhost, but when I publish it to the test server, it gives this error.
Complete code that's not yet rendered by Razor:
int i = 0;
int j = 0;
int m = 0;
#Html.Raw("var oneToTen = [0,1,2,3,4,5,6,7,8,9,10];");
#Html.Raw("var ticks = [");
if (Model.MainQuestionsRatingList != null)
{
foreach (var item in Model.MainQuestionsRatingList)
{
j++;
#Html.Raw("["+(j-1)+", '"+item.QuestionText+"']")
if (j != Model.MainQuestionsRatingList.Count) { #Html.Raw(","); }
}
}
#Html.Raw("];");
#Html.Raw("var labels = [");
if (Model.MainQuestionsRatingList != null)
{
foreach (var item in Model.MainQuestionsRatingList)
{
m++;
#Html.Raw("'"+item.QuestionText+"'")
if (m != Model.MainQuestionsRatingList.Count) { #Html.Raw(","); }
}
}
#Html.Raw("];");
if (Model.MainQuestionsRatingList != null)
{
foreach (var item in Model.MainQuestionsRatingList)
{
i++;
#Html.Raw("var mainQuest_d" + i + " = " + item.Avg + ";");
}
}
i = 0;
#Html.Raw("var d_main_quest_bar = [");
if (Model.MainQuestionsRatingList != null)
{
foreach (var item in Model.MainQuestionsRatingList)
{
i++;
#Html.Raw("[" + (i-1) + ", "+item.Avg+"]");
if (i != Model.MainQuestionsRatingList.Count) { #Html.Raw(","); }
}
}
#Html.Raw("];");
}
data.push({
label: labels,
data: d_main_quest_bar,
bars: {
show: true,
barWidth: 0.2,
order: 1
}
});
EDIT: I ran the same code in my local, and figured out that the commas are automatically replaced with dots and that's why it works in my local as #T.J. Crowder said. But it doesn't happen when I run it in test. How is that possible?
You can't use localized decimal separator characters in JavaScript source code. You must use .:
var mainQuest_d1 = 8.16666666666667;
var mainQuest_d2 = 7.95833333333333;
var mainQuest_d3 = 8.125;
See What is the decimal separator symbol in JavaScript?
It should be obvious that , has another meaning already. How many elements do you expect the array
[0, 8,16666666666667]
to contain?
You shouldn't use commas in your numbers. Use a decimal place instead. Commas are special characters reserved for other uses, such as separators in arrays and function parameters.
For example:
8,16666666666667
should be
8.16666666666667
You have a few instances so here is the full code written correctly:
var oneToTen = [0,1,2,3,4,5,6,7,8,9,10];
var ticks = [[0, 'Atmosfer'],[1, 'Servis'],[2, 'Yemeklerimiz']];
var labels = ['Atmosfer','Servis','Yemeklerimiz'];
var mainQuest_d1 = 8.16666666666667;
var mainQuest_d2 = 7.95833333333333;
var mainQuest_d3 = 8.125;
var d_main_quest_bar = [[0, 8.16666666666667],[1, 7.95833333333333],[2, 8.125]];
(there are 6 changes in total across the last 4 lines)
You shouldn't use commas for integers:
<script type="text/javascript">
var oneToTen = [0,1,2,3,4,5,6,7,8,9,10];
var ticks = [[0, 'Atmosfer'],[1, 'Servis'],[2, 'Yemeklerimiz']];
var labels = ['Atmosfer','Servis','Yemeklerimiz'];
var mainQuest_d1 = 8.16666666666667;
var mainQuest_d2 = 7.95833333333333;
var mainQuest_d3 = 8.125;
var d_main_quest_bar = [[0, 8.16666666666667],[1, 7.95833333333333],[2, 8.125]];
</script>
Source: http://en.wikipedia.org/wiki/JavaScript_syntax#Number
This is incorrect:
var mainQuest_d1 = 8,16666666666667;
var mainQuest_d2 = 7,95833333333333;
var mainQuest_d3 = 8,125;
You can't use commas there.
I have the following code in a .js file:
$.extend(KhanUtil, {
// takes a number and returns the sign of that number
steveSign: function(num){
num = parseFloat(num)
if (num>=0){return 1}
else{return -1}
},
// takes a function, a lower bound for a zero,an upper bound for a zero, and locates
// that zero by iteratively halving the interval.
steveRoot: function(f,xmin,xmax){
var l = xmin
var r = xmax
var z = 0
for (i=0;i<6;i++){
z = (l + r)/2
if (KhanUtil.steveSign(f(l)) === KhanUtil.steveSign(f(z))){ l = z}
else{r = z}
}
return z
},
});
In my html file I define var f = function(x){return x**2 - 2} and run steveRoot(f,1,2), but my browser craps out. Why is this happening?
EDIT:
I am posting the entirety of my code, because it was requested in the comments. thanks a bunch for trying to help me out guys. The weird thing is the code runs fine 9 times out of ten. It is just occasionally that it "craps out". There are a lot of random variables in here, but I can't imagine why steveRoot would care about getting a slightly different function. The code works totally fine and never craps out when I don't include a variable which calls steveRoot.
The HTML file:
<!DOCTYPE html>
<html data-require="math graphie graphie-helpers play polynomials steveMath">
<head>
<title>Piecewise-defined function</title>
<script src="../khan-exercise.js"></script>
</head>
<body>
<div class="exercise">
<div class="vars">
<var id = "n">randRange(2,4)</var>
<var id = "abscissas">makeXList()</var>
<var id = "ordinates">makeYList(-9,9,abscissas.length)</var>
<var id = "points">makeCoordinates(abscissas,ordinates)</var>
<var id = "f">(function(x){return niceFunction(x,points)})</var>
<var id = zeros>steveRoot(f,-10,10)</var>
</div>
<div class="problems">
<div id="problem-type-or-description">
<p class="problem">You are going to have to answer 5</p>
<p class="question">Answer 5</p>
<div class="graphie" id="grid">
graphInit({
range: 10,
scale: 20,
tickStep: 1,
axisArrows: "<->"
});
a =style({
stroke: "red",
strokeWidth: 2
}, function() {
plot( function( x ) { return niceFunction(x,points);
}, [ -10, 10 ] );
});;
a.plot();
</div>
<p class="solution">5</p>
</div>
</div>
<div class="hints">
<!-- Any hints to show to the student. -->
</div>
</div>
</body>
The .js file:
$.extend(KhanUtil, {
//randomLines is a piecewise linear function in x, where the partition points are given by list_of_points.
//list_of_points is an array of arrays, for example [[1,5],[2,-1],[3,4]] would indicate the points (1,5), (2,-1), and (3,4)
//are on the curve. The points must be arranged in order of increasing abscissa.
randomLines: function(x,list_of_points)
{
for (i=0;i<list_of_points.length-1;i++)
{
var x_1 = list_of_points[i][0]
var y_1 = list_of_points[i][1]
var x_2 = list_of_points[i+1][0]
var y_2 = list_of_points[i+1][1]
var m = (y_2-y_1)/(x_2-x_1)
var y = m*(x - x_1) + y_1
if (x > x_1 && x <= x_2){return y}
}
if (x<=list_of_points[0][0]){return 0}
if (x>list_of_points[list_of_points.length-1][0]){return 0}
},
//randomLinesFunc: function(list_of_points){
// var f = function(x){
// return randomLines(x,list_of_points)
// }
//
// return f
//},
numInt: function(f,x){
var delta = .01
var sum = 0
var i = 0
while ((delta*i-10)<=x)
{sum = sum+delta*f(-10+i*delta)
i++
}
return sum
},
peace: function(x){return 2},
////////////////////////////////////////////////
//randRangeNZCU takes (min,max,n) and returns an array of nonzero numbers between max and min
//with successive numbers being distinct. For example [-1,2,-1] could show up, but [2,2,5] will not.
// NZCU stands for NonZeroConsecutiveUnique.
randRangeNZCU: function(min,max,n){
excluded = [0]
array = [KhanUtil.randRangeExclude(min,max,excluded)]
for (i=1;i<n;i++){
excluded = [0,array[i-1]]
array.push(KhanUtil.randRangeExclude(min,max,excluded))
}
return array
},
// makeCoordinates takes two arrays of the same length and returns the array of ordered pairs.
// Example: makeCoordinates([1,2,3],[4,5,6]) = [[1,4],[2,5],[3,6]]
makeCoordinates: function(array1,array2){
array = []
for (i=0;i<array1.length;i++){
array.push([array1[i],array2[i]])
}
return array
},
steveCubic: function(x){return -Math.pow(x,3)/2+3*x/2},
//niceFunction is a C^1 function which connects the points in "points". It is designed to be used
//in my "curveSketchingIntuition" exercise. Every point in the list will have 0 slope, except the first and last point.
niceFunction: function(x,points){
len = points.length
var x1 = points[0][0]
var x2 = points[1][0]
var y1 = points[0][1]
var y2 = points[1][1]
var k = (y1 - y2)/Math.pow(x1-x2,2)
if (x<x2){return k*Math.pow(x-x2,2)+y2}
for (i=1;i<len-2;i++){
var x1 = points[i][0]
var x2 = points[i+1][0]
var y1 = points[i][1]
var y2 = points[i+1][1]
xNew = (x-x1)*2/(x2-x1)-1
yNew = (KhanUtil.steveCubic(xNew)+1)*(y2-y1)/2+y1
if (x>=x1 && x<x2){return yNew}
}
var x1 = points[len-2][0]
var x2 = points[len-1][0]
var y1 = points[len-2][1]
var y2 = points[len-1][1]
var k = (y2 - y1)/Math.pow(x1-x2,2)
if (x>=x1){return k*Math.pow(x-x1,2)+y1}
},
makeXList: function(){
array = [-10]
i=0
while(array[i]<10){
x = array[i]+3*KhanUtil.randRange(1,3)
if (x<10){array.push(x)}
i=i+1
}
array.push(10)
return array
},
makeYList:function(min,max,n){
excluded = [0]
array = [KhanUtil.randRangeExclude(min,max,excluded)]
excluded.push(array[0])
array.push[KhanUtil.randRangeExclude(min,max,excluded)]
excluded = [0]
for (i=1;i<n;i++){
if (array[i-2]<array[i-1]){
array.push(KhanUtil.randRangeExclude(min,array[i-1]-1,excluded))
}
else{array.push(KhanUtil.randRangeExclude(array[i-1]+1,max,excluded))}
}
return array
},
newtonRoot: function(f,a){
var z = a
var m = (f(z+.01)-f(z-.01))/.02
for(i=0;i<2;i++){
z = z-f(z)/m
m = (f(z+.01)-f(z-.01))/.02
}
return z
},
steveSign: function(num){
num = parseFloat(num)
if (num>=0){return 1}
else{return -1}
},
steveRoot: function(f,xmin,xmax){
var l = xmin
var r = xmax
var z = 0
for (i=0;i<6;i++){
z = (l + r)/2
if (KhanUtil.steveSign(f(l)) === KhanUtil.steveSign(f(z))){ l = z}
else{r = z}
}
return z
},
locateZeros: function(f,points){
var len = points.length
var list = []
for(i=0;i<len-1;i++){
var x0 = points[i][0]
var x1 = points[i+1][0]
var y0 = points[i][1]
var y1 = points[i+1][1]
// var m = (y1-y0)/(x1-x0)
// var a = -y0/m+x0
// var z = KhanUtil.steveRoot(f,1,2)
list.push(KhanUtil.steveSign(f(x0)))
}
return list
},
});
In javascript x**2 is not valid. (SyntaxError: Unexpected token *)
You need to run KhanUtil.steveRoot(f,1,2); not just steveRoot(f,1,2);.