You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:38:07