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
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 am using plotly.js to create charts. Some charts have long text inside legend, so these text make legend unnecessary bigger. I want to give legend fixed width and if a length of text is long, I want it to be wrapped.
I have been trying to do this by manipulating svg element on DOM, but since legend is svg:g tag, I can not really do much. I also try give textLength to <text>, but it does wrap text but it does not make a new line.
Is there a way to give legend fixed width?
Perhaps just adding </br> to the legend text would be an easy solution to get a fixed width?
You could use any text wrapping trick in Javascript to do so, e.g.
for (i = 0; i < data.length; i += 1) {
data[i].name = data[i].name.replace(/([\w\s,]{13,}?)\s?\b/g, "$1</br>");
}
var numbers = [];
var total = 10000;
var i = 0;
var data = [];
for (i = 0; i < total; i++) {
numbers[i] = ((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()) - 3) / 3;
}
data.push({
x: numbers,
name: "that's a histogram with lots of points, it therefore needs lots of text as well",
type: 'histogram',
marker: {color: 'blue'}
});
numbers = [];
for (var i = 0; i < total; i++) {
numbers[i] = 0.25 + ((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()) - 3) / 3;
}
data.push({
x: numbers,
name: "that's yet another histogram with lots of points, it therefore needs lots of text as well, like for example that it was shifted by 0.25",
type: 'histogram',
marker: {color: 'red'}
});
for (i = 0; i < data.length; i += 1) {
data[i].name = data[i].name.replace(/([\w\s,]{13,}?)\s?\b/g, "$1</br>");
}
Plotly.newPlot('myDiv', data, {showlegend: true});
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"></div>
Maximilian's answer almost works with the current version of Plotly.js. There doesn't seem to be a property for setting the width of the legend, but you can rig it by inserting breaks (</br>) into the legend text manually. For some reason Plotly seems to mishandle the first break in the text, however; to get around this, you can add a "ghost" break at the beginning of the text. For instance:
// Rudimentary function to break a string on spaces
// attempting to get no more than `maxChars` characters in a line
const breakString = (str, maxChars) => {
if (str.length > maxChars && str.includes(' ')) {
let index = str.lastIndexOf(' ', maxChars);
if (index === -1) index = str.indexOf(' ', maxChars + 1);
return str.substr(0, index) + '</br>' + breakString(str.substr(index + 1), maxChars);
} else {
return str;
}
}
const original_text = "Respondents who think Tenet is Christopher Nolan's most interesting movie";
const final_text = '</br>' + breakString(original_text, 20);
The color symbols next to each legend entry by default are aligned to the center of the corresponding text; with multiline legend text, you'll probably want to change the symbols to be aligned to the top of the text. To do that, add this to your layout:
legend: {
valign: 'top',
}
This works for me using Plotly with javascript.
title: 'first part' + '<br>' + 'Second part'
eg
yaxis2: {
domain: [0.7, 1],
title: 'Sea Surface' + '<br>' + 'Temperature',
showgrid: true,
showline: true,
titlefont: {color: 'blue'},
tickfont: {color: 'blue'},
side: 'right',
anchor: 'free',
position: 0.91
},
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, ",")
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?