echarts has multiple y-axes. The data has negative numbers, causing the 0 tick mark to be misaligned.

before fixing:

let y1Data = [2.0, 4.9, 7.0, 23.2, 25.6, -76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
let y2Data = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
let rowNum = 6;
let max1 = y1Data.length != 0 ? Math.max(...y1Data) : 1;
let max2 = y2Data.length != 0 ? Math.max(...y2Data) : 1;
let min1 = y1Data.length != 0 ? Math.min(...y1Data) : 1;
let min2 = y2Data.length != 0 ? Math.min(...y2Data) : 1;

First read the maximum and minimum values of the two arrays respectively. If the length of the array is 0, set the value to 1 for subsequent calculations.
rowNum is the ideal number of segments, and the actual number is not really this.

let inter1 = Math.ceil((max1 - min1) / rowNum) || 1;
let inter2 = Math.ceil((max2 - min2) / rowNum) || 1;

Then calculate separately the actual number of intervals inter for each array under the ideal number of segments.

if (y1Data.length != 0) {<!-- -->
  min1 = Math.floor(min1 / inter1) * inter1;
  max1 = Math.ceil(max1 / inter1) * inter1;
}
if (y2Data.length != 0) {<!-- -->
  min2 = Math.floor(min2 / inter2) * inter2;
  max2 = Math.ceil(max2 / inter2) * inter2;
}

Then recalculate the maximum and minimum numbers based on the calculated actual number of segment intervals.
The purpose is to make the maximum and minimum numbers exactly proportional to the segment intervals. At this time, the maximum and minimum numbers are based on the interval ratio.

if (y2Data.length != 0 & amp; & amp; y1Data.length != 0) {<!-- -->
  let maxNum1 = Math.floor(Math.abs(max1) / inter1)
  let minNum1 = Math.floor(Math.abs(min1) / inter1)
  let maxNum2 = Math.floor(Math.abs(max2) / inter2)
  let minNum2 = Math.floor(Math.abs(min2) / inter2)
  if (maxNum1 > maxNum2) {<!-- -->
    if (maxNum2 == 0) {<!-- -->
      max2 = maxNum1 * inter2 * 1
    } else {<!-- -->
      max2 = maxNum1 * inter2 * ((max2 || 1) / (Math.abs(max2) || 1))
    }
  } else if (maxNum1 < maxNum2) {<!-- -->
    if (maxNum1 == 0) {<!-- -->
      max1 = maxNum2 * inter1 * 1
    } else {<!-- -->
      max1 = maxNum2 * inter1 * ((max1 || 1) / (Math.abs(max1) || 1))
    }
  }
  if (minNum1 > minNum2) {<!-- -->
    if (minNum2 == 0) {<!-- -->
      min2 = minNum1 * inter2 * -1
    } else {<!-- -->
      min2 = minNum1 * inter2 * ((min2 || 1) / (Math.abs(min2) || 1))
    }
  } else if (minNum1 < minNum2) {<!-- -->
    if (minNum1 == 0) {<!-- -->
      min1 = minNum2 * inter1 * -1
    } else {<!-- -->
      min1 = minNum2 * inter1 * ((min1 || 1) / (Math.abs(min1) || 1))
    }
  }
}

First calculate the maximum number proportion and the minimum number proportion of each column, and then compare them respectively. For small numbers, fill in the number according to the segment interval to ensure that the maximum number of numbers and the minimum number of numbers on both sides are the same, and you can maintain Consistent column scaling

yAxis: [
    {<!-- -->
      type: 'value',
      min: min1,
      max: max1,
      interval: inter1,
      splitNumber: rowNum,
    },
    {<!-- -->
      type: 'value',
      min: min2,
      max: max2,
      interval: inter2,
      splitNumber: rowNum,
    }
  ],

Finally, set the properties calculated above on yAxis

The complete code is as follows: (For chart rendering, just refer to the configuration of yAxis

let y1Data = [2.0, 4.9, 7.0, 23.2, 25.6, -76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
let y2Data = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
let rowNum = 6;
let max1 = y1Data.length != 0 ? Math.max(...y1Data) : 1;
let max2 = y2Data.length != 0 ? Math.max(...y2Data) : 1;
let min1 = y1Data.length != 0 ? Math.min(...y1Data) : 1;
let min2 = y2Data.length != 0 ? Math.min(...y2Data) : 1;
let inter1 = Math.ceil((max1 - min1) / rowNum) || 1;
let inter2 = Math.ceil((max2 - min2) / rowNum) || 1;
if (y1Data.length != 0 & amp; & amp; inter1 != 0) {
  min1 = Math.floor(min1 / inter1) * inter1;
  max1 = Math.ceil(max1 / inter1) * inter1;
}
if (y2Data.length != 0 & amp; & amp; inter2 != 0) {
  min2 = Math.floor(min2 / inter2) * inter2;
  max2 = Math.ceil(max2 / inter2) * inter2;
}
if (y2Data.length != 0 & amp; & amp; y1Data.length != 0) {<!-- -->
  let maxNum1 = Math.floor(Math.abs(max1) / inter1)
  let minNum1 = Math.floor(Math.abs(min1) / inter1)
  let maxNum2 = Math.floor(Math.abs(max2) / inter2)
  let minNum2 = Math.floor(Math.abs(min2) / inter2)
  if (maxNum1 > maxNum2) {<!-- -->
    if (maxNum2 == 0) {<!-- -->
      max2 = maxNum1 * inter2 * 1
    } else {<!-- -->
      max2 = maxNum1 * inter2 * ((max2 || 1) / (Math.abs(max2) || 1))
    }
  } else if (maxNum1 < maxNum2) {<!-- -->
    if (maxNum1 == 0) {<!-- -->
      max1 = maxNum2 * inter1 * 1
    } else {<!-- -->
      max1 = maxNum2 * inter1 * ((max1 || 1) / (Math.abs(max1) || 1))
    }
  }
  if (minNum1 > minNum2) {<!-- -->
    if (minNum2 == 0) {<!-- -->
      min2 = minNum1 * inter2 * -1
    } else {<!-- -->
      min2 = minNum1 * inter2 * ((min2 || 1) / (Math.abs(min2) || 1))
    }
  } else if (minNum1 < minNum2) {<!-- -->
    if (minNum1 == 0) {<!-- -->
      min1 = minNum2 * inter1 * -1
    } else {<!-- -->
      min1 = minNum2 * inter1 * ((min1 || 1) / (Math.abs(min1) || 1))
    }
  }
}

if (y1Data.length == 0) {
  max1 = 1
  min1 = 0
}
if (y2Data.length == 0) {
  max2 = 1
  min2 = 0
}

option = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'cross',
      crossStyle: {
        color: '#999'
      }
    }
  },
  toolbox: {
    feature: {
      dataView: { show: true, readOnly: false },
      magicType: { show: true, type: ['line', 'bar'] },
      restore: { show: true },
      saveAsImage: { show: true }
    }
  },
  legend: {
    data: ['Evaporation', 'Precipitation']
  },
  xAxis: [
    {
      type: 'category',
      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
      axisPointer: {
        type: 'shadow'
      }
    }
  ],
  yAxis: [
    {
      type: 'value',
      name: 'Precipitation',
      min: min1,
      max: max1,
      interval: inter1,
      splitNumber: rowNum,
      axisLabel: {
        formatter: '{value}ml'
      }
    },
    {
      type: 'value',
      name: 'Evaporation',
      min: min2,
      max: max2,
      interval: inter2,
      splitNumber: rowNum,
      axisLabel: {
        formatter: '{value} °C'
      }
    }
  ],
  series: [
    {
      name: 'Evaporation',
      type: 'bar',
      tooltip: {
        valueFormatter: function (value) {
          return value + 'ml';
        }
      },
      data: y1Data
    },
    {
      name: 'Precipitation',
      type: 'line',
      tooltip: {
        valueFormatter: function (value) {
          return value + 'ml';
        }
      },
      data: y2Data
    }
  ]
};

final effect