如何用服务器新数据更新Plotly.js图表?解决restyle函数失效问题
Plotly.js实时更新散点图问题解决
我尝试通过服务器SSE推送的数据实时更新Plotly.js图表,图表包含两个共享X轴的散点图。首次加载数据时图表显示正常,但后续新数据到来时,用restyle函数无法更新图表。不清楚该如何正确给restyle传参,或者是否需要用其他函数?
原实现代码
var source = new EventSource("http://old.iolab.sk/evaluation/sse/sse.php"); source.onmessage = function(event) { count++; if(count == 1){ // only on first data from server var layout = {title: "Website graph"}; var trace1 = { x: [event.data.match(/\d+/g)[0]], y: [(event.data.match(/\d+/g)[2] + "." + event.data.match(/\d+/g)[3])], // y1 from server name: "hehe", type: 'scatter' }; var trace2 = { x: [event.data.match(/\d+/g)[0]], y: [(event.data.match(/\d+/g)[5] + "." + event.data.match(/\d+/g)[6])], // y2 from server name: "hehe", type: 'scatter' }; Plotly.newPlot("websiteGraph", [trace1, trace2], layout); return; } if(!isClicked){ // keeps updating the chart with data from the server until the button is clicked trace1 = {'x': [[event.data.match(/\d+/g)[0]]], 'y': [[(event.data.match(/\d+/g)[2] + "." + event.data.match(/\d+/g)[3])]]}, trace2 = {'x': [[event.data.match(/\d+/g)[0]]], 'y': [[(event.data.match(/\d+/g)[5] + "." + event.data.match(/\d+/g)[6])]]}; Plotly.restyle("websiteGraph", trace1+trace2); } return; }
服务器返回数据格式
id: 0 data: { data: "x": "0", data: "y1": "0.05", data: "y2": "1.03" data: } id: 1 data: { data: "x": "1", data: "y1": "0.077452406437284", data: "y2": "1.0998476951564" data: } id: 2 data: { data: "x": "2", data: "y1": "0.1048994967025", data: "y2": "1.0893908270191" data: } id: 3 data: { data: "x": "3", data: "y1": "0.13233595624294", data: "y2": "1.0086295347546" data: }
问题分析与修复
变量作用域错误
第一个if块内的trace1和trace2是局部变量,外部无法访问。后续重新赋值的全局trace1/trace2和Plotly实例中的轨迹无关联,这不是正确的更新逻辑。restyle用法错误
不能用trace1+trace2拼接对象,这会把对象强制转为字符串后拼接,完全不符合Plotly的API要求。restyle需要指定轨迹索引或批量更新参数,且实时追加数据场景下,extendTraces比restyle更适配。数据解析方式脆弱
用match(/\d+/g)提取数据容错性极差,服务器返回格式稍有变动就会失效。应先将服务器返回的非标准数据转换为合法JSON。
修复后的完整代码
var source = new EventSource("http://old.iolab.sk/evaluation/sse/sse.php"); var count = 0; var isClicked = false; // 确保变量已定义 source.onmessage = function(event) { count++; // 处理服务器返回的非标准JSON格式 const rawData = event.data.replace(/^data: /gm, '').trim(); const fixedData = rawData.replace(/data: }$/, '}').replace(/,\s*$/, ''); const parsedData = JSON.parse(fixedData); const xVal = parsedData.x; const y1Val = parseFloat(parsedData.y1); const y2Val = parseFloat(parsedData.y2); if(count === 1){ const layout = {title: "Website graph"}; const trace1 = { x: [xVal], y: [y1Val], name: "Series 1", type: 'scatter' }; const trace2 = { x: [xVal], y: [y2Val], name: "Series 2", type: 'scatter' }; Plotly.newPlot("websiteGraph", [trace1, trace2], layout); return; } if(!isClicked){ // 用extendTraces追加新数据,第二个参数指定要更新的轨迹索引 Plotly.extendTraces("websiteGraph", { x: [[xVal], [xVal]], y: [[y1Val], [y2Val]] }, [0, 1]); } }
关键说明
extendTraces的参数中,x和y为二维数组,每个子数组对应一个轨迹的新数据。[0,1]表示更新第0和第1个轨迹(即初始创建的trace1和trace2)。- 数据解析部分做了格式修复,适配服务器返回的非标准JSON,避免解析报错。
- 修改了轨迹名称,方便区分两个散点图。
内容的提问来源于stack exchange,提问作者zajsky
相关产品推荐
相关产品推荐

