Related
my below code extracts data from google-sheets via tabletop.js as input to the chart.js. the problem is im unable to make the x-axis show. the chart simply displays the y-values itself as x-label. any help, please?
var publicSpreadsheetUrl = 'https://docs.google.com/spreadsheets/d/1BFPjROVypCGNeLxhk5_PW6PoOb4FDzJsL3DEOEdW_Rc/edit?usp=sharing';
function init() {
Tabletop.init({
key : publicSpreadsheetUrl,
callback : showPlot,
simpleSheet : true
});
}
function showPlot(data, tabletop) {
var xValues = [];
var yValues = [];
for (var i = 0; i < data.length; i++) {
if (xValues.indexOf(data[i].x) === -1) {
xValues.push(data[i].y);
}
if (yValues.indexOf(data[i].x) === -1) {
yValues.push(data[i].y);
}
}
var x = 0;
var y = 0;
for (i = 0; i < data.length; i++) {
x = xValues.indexOf(data[i].x);
y = yValues.indexOf(data[i].y);
}
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type : 'line',
data : {
labels : xValues,
datasets : [{
label : "Revenues",
fill : false,
backgroundColor : '#3498DB',
borderColor : '#3498DB',
data : yValues,
}
],
}
});
}
init();
I'm very sorry for any troubles caused,
It was a typo that caused the error.... Managed to spot it.
for (var i = 0; i < data.length; i++) {
if (xValues.indexOf(data[i].x) === -1) {
xValues.push(data[i].y); // this should be x and not y.!
Thanks for those who responded..!
I have been working for the last months with dygraphs. It is a incredible library and I have got great results but I´m having some problems to find the way of interpolating data from different signals to be shown in the same chart.
The data I received from different sensors have not the same timestamp for the different samples, so for the most of the points of the x axe timestamps I have only the value of one signal. The chart is plotted perfectly, but I would like to see the interpolated value of the rest of the signals in that x point I am pointing over. Below I have the chart I get.
Reading on the dygraph documentation I have seen that when you have independent series, it is possible to see at least the value "undefined" for the signals without data in that point of the x axe.
The csv I use to plot the data is shown below. It has the same structure indicated in the dygraph documentation but I don´t get this undefined label neither.
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
Thanks in advance.
This is an approach that does not add any data to your csv data and still provides interpolated values for all the columns as you move your mouse around. It adds a listener to the mousemove event within dygraph and interpolates the closest points for all of the data. At the moment I have simply shown it in an extra DIV that is after the graph but you can display it however you like:
function findNextValueIndex(data, column, start) {
var rows = data.length;
for (var i = start; i < rows; i++) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function findPrevValueIndex(data, column, start) {
for (var i = start; i >= 0; i--) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return (v0 + (tmid - t0) / (t1 - t0) * (v1 - v0));
}
function showValues(headers, colors, vals) {
var el = document.getElementById("info");
var str = "";
for (j = 1; j < headers.length; j++) {
str += '<p style="color:' + colors[j] + '";>' + headers[j] + ": " + vals[j] + "</p>";
}
el.innerHTML = str;
document.getElementById("hiddenDiv").style.display = "none";
}
function movecustom(event, dygraph, point) {
var time = dygraph.lastx_;
var row = dygraph.lastRow_;
var vals = [];
var headers = [];
var colors = [];
var cols = dygraph.rawData_[0].length;
// draw a line on the chart showing the selected location
var canvas = dygraph.canvas_;
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0,200,200,0.1)";
ctx.moveTo( dygraph.selPoints_[0].canvasx, 0);
ctx.lineTo( dygraph.selPoints_[0].canvasx, 1000);
ctx.stroke();
for (var j = 1; j < cols; j++) {
colors[j] = dygraph.colors_[j - 1];
if (dygraph.rawData_[row][j] == null) {
var prev = findPrevValueIndex(dygraph.rawData_, j, row - 1);
var next = findNextValueIndex(dygraph.rawData_, j, row + 1);
if (prev < 0)
vals[j] = dygraph.rawData_[next][j];
else if (next < 0)
vals[j] = dygraph.rawData_[prev][j];
else {
vals[j] = interpolate(dygraph.rawData_[prev][0], dygraph.rawData_[next][0], time, dygraph.rawData_[prev][j], dygraph.rawData_[next][j]);
}
} else {
vals[j] = dygraph.rawData_[row][j];
}
}
headers = Object.keys(dygraph.setIndexByName_);
showValues(headers, colors, vals);
}
window.onload = function() {
new Dygraph(
document.getElementById('graph'), document.getElementById('csvdata').innerHTML, {
connectSeparatedPoints: true,
drawPoints: true,
labelsDiv: "hiddenDiv",
interactionModel: {
'mousemove': movecustom
}
}
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:120px;"></div>
<div id="info"></div>
<div id="hiddenDiv" style="display:none"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
It seems that the best way to do this is to massage the data before submitting it to the dygraph call. This means the following steps:
1) parse the csv file into an array of arrays.
2) go through each line of the array to find where the holes are
3) interpolate to fill those holes
4) modify the constructed arrays to be displayed by dygraph
5) call dygraph
Not the most attractive code, but seems to work...
function findNextValueIndex(data, column, start) {
var rows = data.length;
for(var i=start;i<rows;i++) {
if(data[i][column].length>0) return(i);
}
return(-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return((v0 + (tmid-t0)/(t1-t0) * (v1-v0)).toString());
}
function parseCSV(string) {
var data = [];
// first get the number of lines:
var lines = string.split('\n');
// now split the first line to retrieve the headings
var headings = lines[0].split(",");
var cols = headings.length;
// now get the data
var rows=0;
for(var i=1;i<lines.length;i++) {
if(lines[i].length>0) {
data[rows] = lines[i].split(",");
rows++;
}
}
// now, fill in the blanks - start by finding the first value for each column of data
var vals = [];
var times = [];
for(var j=1;j<cols;j++) {
var index = findNextValueIndex(data,j,0);
vals[j] = parseFloat(data[index][j]);
}
// now put those start values at the beginning of the array
// there is no way to calculate the previous value of the sensor missing from the first sample
// so we use the first reading and duplicate it
for(var j=1;j<cols;j++) {
data[0][j] = vals[j].toString();
times[j] = parseInt(data[0][0]);
}
// now step through the rows and interpolate the missing values
for(var i=1;i<rows;i++) {
for(var j=1;j<cols;j++) {
if(data[i][j].length>0) {
vals[j] = parseFloat(data[i][j]);
times[j] = parseInt(data[i][0]);
}
else {
var index = findNextValueIndex(data,j,i);
if(index<0) // no more data in this column
data[i][j] = vals[j].toString();
else
data[i][j] = interpolate(times[j],parseInt(data[index][0]),parseInt(data[i][0]),vals[j],data[index][j]);
}
}
}
// now convert from strings to integers and floats so dygraph can handle it
// I've also changed the time value so that it is relative to the first element
// it will be shown in milliseconds
var time0 = parseInt(data[0][0]);
for(var i=0;i<rows;i++) {
data[i][0] = parseInt(data[i][0]) - time0;
for(var j=1;j<cols;j++) {
data[i][j] = parseFloat(data[i][j]);
}
}
var obj = {
labels: headings,
data: data
}
return(obj);
}
window.onload = function () {
var data_obj = parseCSV(document.getElementById('csvdata').innerHTML);
new Dygraph(
document.getElementById('graph'), data_obj.data,
{
labels: data_obj.labels,
connectSeparatedPoints: true,
drawPoints: true
}
);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:200px;"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
Does
connectSeparatedPoints: true
Not do what you need?
I'm trying to make my List to fill my jquery Datatable but I'm unable to do so, at the moment im writing my list to a file to access it by datatable in my view-model is my approach the correct one?
This is my code:
List<string> list = new List<string>();
foreach (var item in db.Pos)
{
var total = 0;
decimal costo = 0;
for (int i = 1; i <= 31; i++)
{
var value = 0;
if (item.Fecha.Day == i) { value = item.Cantidad; costo = costo + item.Total; }
total += value;
}
list.Add(item.Descripcion);
list.Add(item.Pdv);
list.Add(item.Rid);
list.Add(((costo / (total + 1)).ToString("C")));
for (int i = 1; i <= 31; i++)
{
var value = 0;
list.Add(value.ToString());
int month = item.Fecha.Month;
if (item.Fecha.Day == i) { value = item.Cantidad; list.Add(value.ToString()); }
}
list.Add(total.ToString());
list.Add((((costo / (total + 1)) * total).ToString("C")));
}
var json = JsonConvert.SerializeObject(new List<object>() { list });
System.IO.File.WriteAllText(#"\path.txt", json);
And my Datatable Ajax Call:
$(document).ready(function () {
var table = $('#pftable_hdr').DataTable({
ajax: {
url: "/path.txt",
dataSrc: ""
},
scrollY: "500px",
scrollX: true,
scrollCollapse: true,
fixedColumns: {
leftColumns: 3
}
});
});
Part of my Txt File Output:
[["ENS FRUTAS","REST","CENAS","$26.50","0","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","1","$26.50","CAFE AMER ILIMIT","REST","CENAS","$11.50","0","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","1","$11.50","QUESADILLAS TRAD (2)","REST","CENAS","$25.50","0","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","1","$25.50"]]
How can I fill my Jquery datatable with my list? My text file should have [] before and after the $data but I can't make that happen only at the first of the file and in the end.
Your backend code should look something like this. By doing this it will build a JSON string that is looking like this: [["","",""...],["","",""...],["","",""...]]
List<List<string>> list = new List<List<string>>();
foreach (var item in db.Pos)
{
List<string> listItem = new List<string>();
var total = 0;
decimal costo = 0;
for (int i = 1; i <= 31; i++)
{
var value = 0;
if (item.Fecha.Day == i) { value = item.Cantidad; costo = costo + item.Total; }
total += value;
}
listItem.Add(item.Descripcion);
listItem.Add(item.Pdv);
listItem.Add(item.Rid);
listItem.Add(((costo / (total + 1)).ToString("C")));
for (int i = 1; i <= 31; i++)
{
var value = 0;
listItem.Add(value.ToString());
int month = item.Fecha.Month;
if (item.Fecha.Day == i) { value = item.Cantidad; listItem.Add(value.ToString()); }
}
listItem.Add(total.ToString());
listItem.Add((((costo / (total + 1)) * total).ToString("C")));
list.Add(listItem);
}
var json = JsonConvert.SerializeObject(list);
System.IO.File.WriteAllText(#"\path.txt", json);
Try like this
list.Add("[");
list.Add(item.Descripcion);
// rest code....
list.Add((((costo / (total + 1)) * total).ToString("C")));
list.Add("]");
Will this work for your case ? Let know your comment
var json = JsonConvert.SerializeObject(new List<object>() { list });
In the above line list is already an object, then why you are creating a new object and assigning "list" to that object.
Try like below,
var json = JsonConvert.SerializeObject(list);
This will provide you the required result
I have created box plot chart dynamically but would like to add a tooltip to the box plot chart so that when user mouse over the box plot series, the box plot series values will be displayed out in tooltip.
This is my code to create box plot chart:
Chart Chart1= new Chart();
Chart1.DataSource = dt;
Chart1.Width = 800;
Chart1.Height = 490;
Chart1.Series.Add(new Series());
Chart1.Series[0].ChartType = SeriesChartType.BoxPlot;
Chart1.Series.Add(new Series());
Chart1.Series[1].ChartType = SeriesChartType.Point;
List<object> List1 = dt.AsEnumerable().ToList<object>();
int Chart1_AVG = 0;
int Chart1_POINTINDEX = 0;
foreach (DataRow row in dt.Rows)
{
Chart1_AVG = (int)row["AVG"];
Chart1.Series[0].Points.AddXY(row["CUSTOMER"], new object[] { row["MIN"], row["MAX"], row["25TH_PCT_NUMBER"], row["75TH_PCT_NUMBER"], row["50TH_PCT_NUMBER"], row["AVG"] });
Chart1_POINTINDEX = Chart1.Series[1].Points.AddXY(row["CUSTOMER"], new object[] { row["AVG"] });
if ((Chart1_AVG >= AvgMinColorGreen) && (Chart1_AVG <= AvgMaxColorGreen))
{
Chart1.Series[1].Points[Chart1_POINTINDEX].MarkerColor = Color.Green;
}
else if ((Chart1_AVG >= AvgMinColorYellow) && (Chart1_AVG <= AvgMaxColorYellow))
{
Chart1.Series[1].Points[Chart1_POINTINDEX].MarkerColor = Color.Orange;
}
else if ((Chart1_AVG >= AvgMinColorRed) && (Chart1_AVG <= AvgMaxColorRed))
{
Chart1.Series[1].Points[Chart1_POINTINDEX].MarkerColor = Color.Red;
}
}
Chart1.Series[0]["BoxPlotShowMedian"] = "false"; //hide the average point
//create chartareas
ChartArea ca= new ChartArea();
//databind
Chart1.DataBind();
Chart1.Visible = true;
panel.Controls.Add(Chart1);
Please help me on this, thanks.
Use this
Chart1.Series[0].ToolTip = "#VAL"
Other possible tooltips are LegendToolTip, LabelToolTip ...
For keywords see https://msdn.microsoft.com/de-de/library/vstudio/dd456687%28v=vs.110%29.aspx
I am trying to draw a Google visualization pie chart based on below JSON. I am having issues since Google takes numerical data, instead of just plain objects.
For example, I want a pie chart based on UseCase. Pie chart will list VDI,Upgrade,DEMO and show its proportion related to total. Please help.
Here is the JSON example
[{"Id":0,"ProcessedTime":"2012/01","Approver":"zoo","POC":"POC1","UseCase":"VDI"},{"Id":0,"ProcessedTime":"2012/02","Approver":"zoo","POC":"POC1","UseCase":"Upgrade"},{"Id":0,"ProcessedTime":"2012/03","Approver":"zoo","POC":"POC2","UseCase":"DEMO"},{"Id":0,"ProcessedTime":"2012/04","Approver":"victor","POC":"POC2","UseCase":"DEMO"},{"Id":0,"ProcessedTime":"2012/05","Approver":"victor","POC":"POC3","UseCase":"VDI"},{"Id":0,"ProcessedTime":"2012/06","Approver":"victor","POC":"POC3","UseCase":"Upgrade"},{"Id":0,"ProcessedTime":"2012/05","Approver":"tom","POC":"POC3","UseCase":"VDI"},{"Id":0,"ProcessedTime":"2012/06","Approver":"tom","POC":"POC3","UseCase":"Upgrade"}]
// Full source
google.setOnLoadCallback(drawChart);
function drawChart() {
$.get('/Home/GetData', {},
function (data) {
var tdata = new google.visualization.DataTable();
tdata.addColumn('string', 'UseCase');
tdata.addColumn('int', 'Count');
// Reservation based on UseCase
var ReservationByUseCase = [];
for (var i = 0; i < data.length; i++) {
var d = data[i];
// If not part of array.. Add it
if ($.inArray(d.UseCase, ReservationByUseCase) === -1)
{
var UseCaseValue = d.UseCase;
var UseCaseCountValue = 1;
ReservationByUseCase.push({ UseCase: UseCaseValue, UseCaseCount: UseCaseCountValue });
}
// If part of the array.. Increase count
if ($.inArray(d.UseCase, ReservationByUseCase) !== -1) {
var cUseCase = ReservationByUseCase[$.inArray(d.UseCase, ReservationByUseCase)];
cUseCase.UseCaseCount = cUseCase.UseCaseCount + 1;
ReservationByUseCase[$.inArray(d.UseCase, ReservationByUseCase)] = cUseCase
}
}
for (var i = 0; i < ReservationByUseCase.length; i++) {
tdata.addColumn(ReservationByUseCase[i].UseCaseValue, ReservationByUseCase[i].UseCaseCountValue)
alert(ReservationByUseCase[i].UseCaseValue);
alert(ReservationByUseCase[i].UseCaseCountValue);
}
var options = {
title: "Reservations"
};
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(tdata, options);
});
}
You just need to loop through the data and add up each UseCase:
var ndata = {}
var data = [{"Id":0,"ProcessedTime":"2012/01","Approver":"zoo","POC":"POC1","UseCase":"VDI"},{"Id":0,"ProcessedTime":"2012/02","Approver":"zoo","POC":"POC1","UseCase":"Upgrade"},{"Id":0,"ProcessedTime":"2012/03","Approver":"zoo","POC":"POC2","UseCase":"DEMO"},{"Id":0,"ProcessedTime":"2012/04","Approver":"victor","POC":"POC2","UseCase":"DEMO"},{"Id":0,"ProcessedTime":"2012/05","Approver":"victor","POC":"POC3","UseCase":"VDI"},{"Id":0,"ProcessedTime":"2012/06","Approver":"victor","POC":"POC3","UseCase":"Upgrade"},{"Id":0,"ProcessedTime":"2012/05","Approver":"tom","POC":"POC3","UseCase":"VDI"},{"Id":0,"ProcessedTime":"2012/06","Approver":"tom","POC":"POC3","UseCase":"Upgrade"}];
for (i = 0; i < data.length; i++) {
var d = data[i];
if (ndata[d["UseCase"]] == null) {
ndata[d["UseCase"]] = 1
} else {
ndata[d["UseCase"]] = ndata[d["UseCase"]] + 1
}
}
console.log(ndata);
Here's a fiddle: http://jsfiddle.net/znj0kLsg/
This is what I've came up with... Will this work?
// Reservation based on UseCase
var ReservationByUseCase = [];
for (var i = 0; i < data.length; i++) {
var d = data[i];
// If not part of array.. Add it
if ($.inArray(d.UseCase, ReservationByUseCase) === -1)
{
var UseCaseValue = d.UseCase;
var UseCaseCountValue = 1;
ReservationByUseCase.push({ UseCase: UseCaseValue, UseCaseCount: UseCaseCountValue });
}
// If part of the array.. Increase count
if ($.inArray(d.UseCase, ReservationByUseCase) !== -1) {
var cUseCase = ReservationByUseCase[$.inArray(d.UseCase, ReservationByUseCase)];
cUseCase.UseCaseCount = cUseCase.UseCaseCount + 1;
ReservationByUseCase[$.inArray(d.UseCase, ReservationByUseCase)] = cUseCase
}
}