用Plot做圖時,覺得雙Y軸對齊會好看多了,但是網路上沒有令人滿意的正解,最接近的是找到這一篇《Python - dual y axis chart, align zero》。
仔細詳讀,可能是個人理解能力衰退了,也不明白是如何運算,直接套用也會讓部分數據被新設的最大值或最小值被切掉。
回到數學,要左右Y軸對齊在某點上,首先要讓第一軸的V1點對到第二軸的V2點出發,之後再做延伸。
接下來,選一軸(通常是AX1)為主,依照AX1對應V1的比例,以V2為中心點,以AX1的比例延伸直到涵蓋AX2的原範圍,確保數據能不被切除。
不過,在此情況下,V1對到AX1最大或最小值,調整AX2會是無解的。此時換成去調整AX1。若再調整AX1也無解,可能是無法對齊或是不需要對齊。
最後,若V1不在AX1內,圖表的Y軸當然不會顯示V1,自然也無法對齊。所以在計算之前,得先確保V1與V2都出現在AX1與AX2內。
def align_yaxis(ax1, v1, ax2, v2):
# 取得AX1和AX2的範圍
miny1 , maxy1 = ax1.get_ylim()
miny2 , maxy2 = ax2.get_ylim()
print("調整前", miny1, maxy1, miny2, maxy2)
# 確保 v1 一定出現在AX1
if v1 > maxy1: maxy1 = v1
elif v1 < miny1: miny1 = v1
# 確保 v2 一定出現在AX2
if v2 > maxy2: maxy2 = v2
elif v2 < miny2: miny2 = v2
# 與V上下距離
upy1 = abs(maxy1 - v1)
downy1 = abs(v1 - miny1)
upy2 = abs(maxy2 - v2)
downy2 = abs(v2 - miny2)
print("調整中", miny1, maxy1, miny2, maxy2)
# 有解
if upy1 > 0 and downy1 > 0:
up_ratio = upy2 / upy1
down_ratio = downy2 / downy1
# 調整AX2
if up_ratio > down_ratio: # 如果上方需延伸較多,則對齊最大值,依上方比例去調整最小值。
miny2 = v2 - downy1 * up_ratio
elif down_ratio > up_ratio:
maxy2 = v2 + upy1 * down_ratio
else:
pass
# 調整AX2無解,則調整AX1。注意比例是AX2/AX1,故調整AX1時,調整比例需要變成倒數。
elif upy2 > 0 and downy2 > 0:
#因為upy1或downy2為0才會來到這裡,若除其中一項將會發生除零的錯誤。
up_ratio = upy1 / upy2
down_ratio = downy1 / downy2
if up_ratio > down_ratio:
miny1 = v1 - downy2 * up_ratio
elif down_ratio > up_ratio:
maxy1 = v1 + upy2 * down_ratio
else:
pass
# 調整AX1與AX2都無解,則不調整
else:
print("無法調整或不需調整")
pass
# 重新調整AX1和AX2
print("調整後",miny1, maxy1, miny2, maxy2)
ax1.set_ylim(miny1, maxy1)
ax2.set_ylim(miny2, maxy2)
return None