2017-03-17 22 views
2

我一直在用dygraphs工作过去的几个月。这是一个令人难以置信的库,我得到了很好的结果,但是我有一些问题需要找到从不同信号中插入数据的方式来显示在同一个图表中。是否可以使用dygraphs显示插值数据?

我从不同的传感器收到的数据对于不同的样本有不同的时间戳,所以对于xax时间戳的大部分点,我只有一个信号的值。图表完美地绘制出来,但是我希望看到我指向的x点中其余信号的内插值。下面我有我得到的图表。

enter image description here

阅读上dygraph documentation我所看到的,当你有独立的系列,可以看到在x斧头的那点至少在信号没有数据值“不确定”。

我用来绘制数据的csv如下所示。它在dygraph文档中有相同的结构,但我没有得到这个未定义的标签。

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

在此先感谢。

回答

1

这是一种不会将任何数据添加到您的csv数据并在您移动鼠标时为所有列提供插值的方法。它向dygraph中的mousemove事件添加侦听器,并为所有数据插入最接近的点。目前,我只是表明它在一个额外的DIV是图之后,但可以显示它,只要你喜欢:

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>

+0

非常感谢@fmacdee,非常感谢您的帮助。现在我非常忙于项目的另一部分,但我会尽快回答你的答案,让我知道我的意见,并在给我适用的情况下给你有效的答案;) –

1

看来最好的办法是在提交给dygraph调用之前按摩数据。这意味着以下步骤: 1)将csv文件解析为一个数组数组。 2)经过所述阵列的每一行,以找到其中孔是 3)内插以填充那些孔洞 4)修改构造阵列由dygraph 5)呼叫dygraph

不是最有吸引力的代码被显示,但似乎工作...

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>

+0

这么多的感谢@fmacdee。主要的问题是我有每一个数百万数据值的信号。所以假设我有5个信号,并且不同信号的大部分值不共享时间戳,那么我将不得不在每个信号中插入x5值数据,并且每个信号有5个数据值的5个新信号。这将意味着图表和浏览器的大量过载。我正在试图找到一个ad-hoc解决方案,它只能计算在特定时刻选择的时间戳上的插值。 –

+0

你会考虑生成第二个图表,它是第一个图表的窗口吗?这应该允许您只对位于放大区域中的点的子集进行插值... – fmacdee

+0

或者,你也许可以用一般一个插件... https://rstudio.github.io/dygraphs/gallery-plugins.html – fmacdee

0

是否

connectSeparatedPoints: true 

不做你所需要的?

+0

谢谢@尼克。我实际上正在使用该设置。实际上,如果您检查我发布的图表和csv,则信号值中存在间隙,但在图表中,图表无间隙地显示。我面临的问题(除插值之外)是当没有值时它不会显示未定义的标签。 –

相关问题