Plotly.js双Y轴零刻度线对齐问题求助
问题
需要绘制多条散点折线图,其中部分数据值范围为0-10000,另一部分为-1到1,且不同场景下数值范围不固定,无法设置固定值。此前参考过相关问题,但第二个Y轴存在负值时,rangemode='tozero'无法生效,希望实现双Y轴的y=0刻度线与X轴处于同一位置。以下是完整代码示例:
HTML代码
<head> <!-- Load plotly.js into the DOM --> <script src='https://cdn.plot.ly/plotly-2.16.1.min.js'></script> </head> <body> <div id='ts' class='ts' style="width:1200px; height:800px; background-color: aliceblue"></div> </body>
JavaScript代码
var data_all = { "b02": { "min_value": 562, "max_value": 1007, "values": [ { "date": "2018-07-01 00:00:00", "value": "587" }, { "date": "2018-07-04 00:00:00", "value": "562" }, { "date": "2018-07-16 00:00:00", "value": "794" }, { "date": "2018-07-19 00:00:00", "value": "966" }, { "date": "2018-07-24 00:00:00", "value": "1007" } ] }, "b04": { "min_value": 1091, "max_value": 2549, "values": [ { "date": "2018-07-01 00:00:00", "value": "1091" }, { "date": "2018-07-04 00:00:00", "value": "1175" }, { "date": "2018-07-16 00:00:00", "value": "1553" }, { "date": "2018-07-19 00:00:00", "value": "2409" }, { "date": "2018-07-24 00:00:00", "value": "2549" } ] }, "evi": { "min_value": 0, "max_value": 1, "values": [ { "date": "2018-07-01 00:00:00", "value": "1" }, { "date": "2018-07-04 00:00:00", "value": "1" }, { "date": "2018-07-16 00:00:00", "value": "0" }, { "date": "2018-07-19 00:00:00", "value": "0" }, { "date": "2018-07-24 00:00:00", "value": "0" } ] }, "ndvi": { "min_value": 0, "max_value": 1, "values": [ { "date": "2018-07-01 00:00:00", "value": "1" }, { "date": "2018-07-04 00:00:00", "value": "0" }, { "date": "2018-07-16 00:00:00", "value": "0" }, { "date": "2018-07-19 00:00:00", "value": "0" }, { "date": "2018-07-24 00:00:00", "value": "0" } ] } } var unpack = function(rows, key) { return rows.map(function(row) { return row[key]; }) }; var layout = { autosize: false, width: 1000, height: 420, margin: { l:50, r:150, b: 50, t: 50, pad: 4 }, xaxis: {title: 'Datum', type: 'date', tickformat: '%d-%m-%y'}, yaxis: {title: 'Wert', side: 'left'}, yaxis2: { title: 'yaxis2 title', overlaying: 'y', side: 'right', }, legend: { x: 1.1, y: 0 } } var plotly_config = { displaylogo: false, showSendToCloud: true, }; var traces = []; for (var key1 in data_all){ var idx_data = data_all[key1]['values']; var dates = unpack(idx_data,'date').map(n => n.substr(0,10)); var values_dates = unpack(idx_data,'value').map(n => parseFloat(n)); if (key1.substr(0,1) !== 'b') { var cur_col = 'red'; var trace = { x: dates, y: values_dates, name: key1, xaxis: 'x', yaxis: 'y2', type: 'scatter' }; traces.push(trace); }else { var cur_col = 'blue'; var trace = { x: dates, y: values_dates, name: key1, xaxis: 'x', yaxis: 'y', type: 'scatter' }; traces.push(trace); } } Plotly.newPlot('ts', traces, layout, plotly_config); $('.ts')[0].on('plotly_hover', function(data){ if(data.points[0].data.yaxis=='y'){ layout.yaxis.linewidth = 5; }else if (data.points[0].data.yaxis == 'y2'){ layout.yaxis2.linewidth = 5; } Plotly.update('ts',{},layout); }); $('.ts')[0].on('plotly_unhover', function(data){ layout.yaxis.linewidth = 1; layout.yaxis2.linewidth = 1; Plotly.update('ts',{},layout); });
解决方案
要实现双Y轴的y=0刻度与X轴对齐,核心是让两个Y轴的0点在垂直方向上处于同一位置。可以通过自动计算数据极值并调整轴范围来实现,步骤如下:
1. 统计双Y轴的极值
遍历所有数据,分别获取左侧Y轴(b开头的数据集)和右侧Y轴(非b开头的数据集)的最小值、最大值:
// 初始化极值变量 let yMin = Infinity, yMax = -Infinity; let y2Min = Infinity, y2Max = -Infinity; // 遍历数据计算极值 for (var key1 in data_all){ const values = unpack(data_all[key1]['values'], 'value').map(n => parseFloat(n)); if (key1.substr(0,1) !== 'b') { y2Min = Math.min(y2Min, ...values); y2Max = Math.max(y2Max, ...values); } else { yMin = Math.min(yMin, ...values); yMax = Math.max(yMax, ...values); } }
2. 调整轴范围确保0点对齐
根据极值情况调整两个Y轴的范围,让0点在垂直方向位置一致:
// 确保左侧Y轴包含0点(如果原最小值大于0) if (yMin > 0) yMin = 0; const yRange = yMax - yMin; let newY2Min = y2Min; let newY2Max = y2Max; // 当右侧Y轴存在负值,且左侧Y轴以0为下限,按比例缩放右侧负值范围 if (yMin === 0 && y2Min < 0) { const positiveRatio = yRange / (y2Max > 0 ? y2Max : 1); newY2Min = -Math.abs(y2Min) * positiveRatio; } // 当左侧Y轴包含负值,计算0点的相对比例,确保右侧Y轴0点位置匹配 if (yMin < 0) { const yZeroRatio = (0 - yMin) / yRange; const y2Range = y2Max - y2Min; // 保持右侧Y轴极值,强制开启零刻度线对齐 newY2Min = y2Min; newY2Max = y2Max; }
3. 更新Layout配置
将计算后的范围应用到布局,并开启零刻度线:
layout.yaxis = { title: 'Wert', side: 'left', range: [yMin, yMax], zeroline: true, zerolinewidth: 2, zerolinecolor: '#333' }; layout.yaxis2 = { title: 'yaxis2 title', overlaying: 'y', side: 'right', range: [newY2Min, newY2Max], zeroline: true, zerolinewidth: 2, zerolinecolor: '#333' };
4. 完整修改后的代码
将上述逻辑插入到原代码中,替换原有的layout定义和Plotly.newPlot调用部分即可。修改后无论数据范围如何变化,双Y轴的0刻度都会自动与X轴对齐。
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

