I'm trying create a gantt chart with highcharts and I need to put the data in the JSON format. I'm getting real close, but the problem i'm having is that the data I am pushing is being surrounded by quotes. I'm guessing there is just something that I am doing wrong, but I can't figure it out.
I can tell that the issue is with quotes being added because i have some static data that works just fine and I printed the object in the firebug console for the static data and my dynamic data.
So here is the very basic of my options var:
var options = {
series : [],
test : [ {
data : [ {
low : Date.UTC(2012, 0, 1),
y : Date.UTC(2012, 0, 15)
}, {
low : Date.UTC(2012, 0, 10),
y : Date.UTC(2012, 4, 28)
} ]
}
}
Then I have this function which gets called at load time:
function loadData() {
var chartData = $('#hiddenDate').val();
console.log('hiddenDate = '+chartData);
var goodData = chartData.split('|');
console.log('goodData = '+goodData);
var series = {
data : []
};
try {
$.each(goodData, function(index, value) {
var goodData2 = value.split(",");
var startYear = goodData2[0].substr(0, 4);
var endYear = goodData2[1].substr(0, 4);
var startMonth = goodData2[0].substr(5, 2);
var endMonth = goodData2[1].substr(5, 2);
var startDay = goodData2[0].substr(8, 2);
var endDay = goodData2[1].substr(8, 2);
/*series.data.push({
low : 'Date.UTC('+startYear+','+startMonth+','+startDay+')',
y : 'Date.UTC('+endYear+','+endMonth+','+endDay+')'
});*/
var start = "{low : Date.UTC("+startYear+","+startMonth+","+startDay+")";
var end = "y : Date.UTC("+endYear+","+endMonth+","+endDay+")}";
series.data.push(start);
series.data.push(end);
//series.data.y.push('Date.UTC('+endYear+','+endMonth+','+endDay+')');
console.log('series.data = '+series.data.toSource());
console.log('options.test = '+options.test.toSource());
});
options.series.push(series);
console.log('options.series = '+options.series.toSource());
} catch (err) {
console.log("ERROR ..." + err.description + ' message:'+ err.message);
}
}
And here is the firebug output where I can see that the quotes are causing an issue for options.series:
series.data = ["{low : Date.UTC(2011,05,27)", "y : Date.UTC(2011,02,17)}", "{low : Date.UTC(2011,07,05)", "y : Date.UTC(2010,12,23)}"]
options.test = [{data:[{low:1325376000000, y:1326585600000}, {low:1326153600000, y:1338163200000}]}]
options.series = [{data:["{low : Date.UTC(2011,05,27)", "y : Date.UTC(2011,02,17)}", "{low : Date.UTC(2011,07,05)", "y : Date.UTC(2010,12,23)}"]}]
shouldn't your start and end variables be object literals instead of strings?
Related
I'm using Javascript and D3.js to create a Custom Widget in Thingsboard. I've managed to make a Chart work that plots a line from a given datasource. But I'm facing an issue when changing the datasource.
When user clicks on a new datasource, it should replaced the data on the graph. My D3.js chart takes data from an Array of point objects, with X and Y coordinates, that's generated from the datasource.
But I'm having the following issue: The dataset array gets the data correctly only the first time that it gets the points pushed. Whenever I try to clear the array or remove the dataset, and reapply the points, it acts as if the points were already there, but hiden. The problem will be clearer if you look at the Console log output.
Notice that the Array acts as if it was always the same/It contained the same points, even when I renew it with:
dataset = [];
I'm new to Javascript so this could be a very dumb problem, but I cannot find any similar issues nor know how to look for the issue.
My dataset is coded in a string like this:
"25,351,-442,0,112,3447,28,45,..."
Here's the code of my updating function:
var dataset = [];
function addDataPoint (value) {
//widget = this;
widget.string = value + ''; //Prevents compile error from .split()
var pointsArray = [];
var pointsArray = widget.string.split(',');
var newList = []; //As dataset is referenced by the D3.js chart, I wanted to test with an Unreferenced array to check if it had something to do with the reference.
console.log("PointsArrayLength " + pointsArray.length);
for (var index = 0; index < pointsArray.length; index++){
var number = parseInt(pointsArray[index],10);
var point = {
x: index % self.ctx.settings.xRangeMax,
y: number
};
if (widget.lastX && widget.lastX > point.x) {
//widget.data.length = 0;
}else{
if(!isNaN(number)){
widget.lastX = point.x;
newList.push(point);
dataset.push(point);
}
}
}
console.log("UnreferencedList Length: " +newList.length + " Index: "+index);
console.log("Referenced length: " + dataset.length);
//Redraw the graph
widget.line.attr('d', widget.lineGenerator);
}
//The function that gets called when the dataset changes.
self.onDataUpdated = function() {
var xValueString;
try{
var xValueString = self.ctx.defaultSubscription.data[0].data[0][1];
console.log("Size of data: " + xValueString.length);
dataset = [];//NOTE
/* I've tried several methods here to renew the Array.
dataset.length = 0 ; a while loop with dataset.pop() until length = 0, etc.
None of the methods make a difference*/
addDataPoint(xValueString);
console.log("Size of data: " + dataset.length);
} catch(err){
//For other debugging purposes
//console.log(err);
}
And here's the output from the Console Log:
//First run on dataset number 1:
Size of data: 55411
PointsArrayLength 3001
UnreferencedList Length: 3000 Index: 3001
Referenced length: 3000
Size of data: 3000
//First run on dataset Number 2:
//Note: Dataset Number 2 contains dataset number 1, and adds 12879 more points
Size of data: 69021
PointsArrayLength 15879
UnreferencedList Length: 12879 Index: 15879
Referenced length: 12879
Size of data: 12879
//Second Run on dataset number 1:
Size of data: 55411
PointsArrayLength 3001
UnreferencedList Length: 0 Index: 3001
Referenced length: 0
Size of data: 0
//Second Run on dataset Number 2:
Size of data: 69021
PointsArrayLength 15879
UnreferencedList Length: 1 Index: 15879
Referenced length: 1
Size of data: 1
I think that you are having scope issues. Define newlist as a global var.
let dataset = [];
let newlist = [];
function addDataPoint (value) {
//widget = this;
widget.string = value + ''; //Prevents compile error from .split()
let workArray = []
let pointsArray = [];
pointsArray = widget.string.split(',');
console.log("PointsArrayLength " + pointsArray.length);
for (var index = 0; index < pointsArray.length; index++){
var number = parseInt(pointsArray[index],10);
var point = {
x: index % self.ctx.settings.xRangeMax,
y: number
};
if (widget.lastX && widget.lastX > point.x) {
//widget.data.length = 0;
}else{
if(!isNaN(number)){
widget.lastX = point.x;
newList.push(point);
//dataset.push(point);
workArray.push(point);
}
}
}
console.log("UnreferencedList Length: " +newList.length + " Index: "+index);
console.log("Referenced length: " + dataset.length);
//Redraw the graph
widget.line.attr('d', widget.lineGenerator);
return workArray;
}
//The function that gets called when the dataset changes.
self.onDataUpdated = function() {
try{
let xValueString = self.ctx.defaultSubscription.data[0].data[0][1];
console.log("Size of data: " + xValueString.length);
//dataset = [];//NOTE
/* I've tried several methods here to renew the Array.
dataset.length = 0 ;
None of the methods make a difference*/
dataset = addDataPoint(xValueString);
console.log("Size of data: " + dataset.length);
} catch(err){
}
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
Working off the example here, I'm using my own dataset in a csv to attempt to display a simple line graph. However, no matter how I create the 'groups' for the lineChart, it won't show any actual line on the graph, nor any y values on the axis. I'm parsing the time correctly because the brush works as expected on the graph and the x axis has the proper time labels.
d3.csv('weatherLogMod.csv', function(data) {
var parseDate = d3.time.format("%Y/%m/%d %H:%M");
data.forEach(function(d) {
d.absHumidity = ((6.112 * Math.exp((17.67 * +d.Temperature)/(+d.Temperature + 243.5)) * 2.1674 * +d.Humidity.replace(/[",%]/g, ''))/(273.15 + +d.Temperature));
d.date = parseDate.parse(d.Time);
d.warmth = +d.Temperature;
});
var instance = crossfilter(data);
var dateDim = instance.dimension(function(d) { return d.Time; });
var tempGroup = dateDim.group().reduceSum(function(d) {return d.warmth;});
var minDate = dateDim.bottom(1)[0].date;
var maxDate = dateDim.top(1)[0].date;
var tempChart = dc.lineChart("#chart-line-hitsperday");
tempChart
.width(500).height(200)
.dimension(dateDim)
.group(tempGroup)
.x(d3.time.scale().domain([minDate,maxDate]));
dc.renderAll();
});
I can't find what I'm doing wrong; in the console, doing tempGroup.all() gives me an array full of temperature-date value:keys, so it seems like it should be working?
Here's a screenshot of my problem.
After some trial and error I figured it out;
var dateDim = instance.dimension(function(d) { return d.Time; });
should be:
var dateDim = instance.dimension(function(d) { return d.date; });
and it works fine.
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).
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, ",")