簡體   English   中英

在 matplotlib 上縮放兩個不同 y 軸的問題

[英]Problem with scaling two different y-axis on matplotlib

我想 plot 一個 x 軸和兩個 y 軸( eVnm )上的數據集。 兩個 y 軸通過以下等式連接在一起: nm = 1239.8/eV

從我的圖片 output 可以看出,這些值不在正確的位置。 例如,在eV = 0.5我需要有nm = 2479.6 ,在eV = 2.9nm = 423 ,等等......

我怎樣才能解決這個問題?

我的data.txt

number eV nm
1 2.573 481.9
2 2.925 423.9
3 3.174 390.7
4 3.242 382.4
5 3.387 366.1

我正在使用的代碼:

#!/usr/bin/env python3

import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.ticker as tck

# data handling

file = "data.txt"

df = pd.read_csv(file, delimiter=" ")  # generate a DataFrame with data

no = df[df.columns[0]]
eV = df[df.columns[1]].round(2)  # first y-axis
nm = df[df.columns[2]].round(1)  # second y-axis

# generate a subplot 1x1

fig, ax1 = plt.subplots(1,1)

# first Axes object, main plot (lollipop plot)

ax1.stem(no, eV, markerfmt=' ', basefmt=" ", linefmt='blue', label="Gas")

ax1.set_ylim(0.5,4) 
ax1.yaxis.set_minor_locator(tck.MultipleLocator(0.5))
ax1.set_xlabel('Aggregation', labelpad=12)
ax1.set_ylabel('Transition energy [eV]', labelpad=12)

# adding second y-axis

ax2 = ax1.twinx()
ax2.set_ylim(2680,350)  # set the corresponding ymax and ymin, 
                        # but the values are not correct anyway
ax2.set_yticklabels(nm)
ax2.set_ylabel('Wavelength [nm]', labelpad=12)

# save

plt.tight_layout(pad=1.5)
plt.show()

生成的 plot 如下。 我只是想通過將第一個軸除以 1239.8 來獲得第二個軸,我不知道還要尋找什么!

企圖陰謀

您可以使用ax.secondary_yaxis ,如本示例中所述。 有關您的問題的實現,請參見下面的代碼。 我只包含了與第二個 y 軸相關的代碼部分。

# adding second y-axis
def eV_to_nm(eV):
    return 1239.8 / eV

def nm_to_eV(nm):
    return 1239.8 / nm

ax2 = ax1.secondary_yaxis('right', functions=(eV_to_nm, nm_to_eV))
ax2.set_yticks(nm)
ax2.set_ylabel('Wavelength [nm]', labelpad=12)

請注意,我也使用set_yticks而不是set_yticklabels 此外,如果您刪除set_yticks ,matplotlib 將自動確定 y 刻度位置,假設 y 刻度呈線性分布。 然而,因為nmeV成反比,這將導致(很可能)不希望的 y 刻度分布。 您可以使用set_yticks中的一組不同值手動更改這些值。

我想出了如何解決這個問題( 這里的提示來源)。

因此,對於任何需要一個數據集具有一個 x 軸但有兩個 y 軸(一個在數學上與另一個相關)的人,報告了一個可行的解決方案。 基本上,問題在於與主 y 軸具有相同的刻度,但根據它們的數學關系(即,在這種情況下, nm = 1239.8/eV )按比例更改它們。 以下代碼已經過測試並且可以正常工作。

如果您有兩個 x 軸和 1 個共享 y 軸等,這種方法當然有效。

重要提示:您必須定義一個 y 范圍(或 x 范圍,如果您想要相反的結果),否則您可能會遇到一些縮放問題。

#!/usr/bin/env python3

import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.ticker as tck
from matplotlib.text import Text

# data

file = "data.txt"

df = pd.read_csv(file, delimiter=" ")  # generate a DataFrame with data

no = df[df.columns[0]]
eV = df[df.columns[1]].round(2)  # first y-axis
nm = df[df.columns[2]].round(1)  # second y-axis

# generate a subplot 1x1

fig, ax1 = plt.subplots(1,1)

# first Axes object, main plot (lollipop plot)

ax1.stem(no, eV, markerfmt=' ', basefmt=" ", linefmt='blue', label="Gas")

ax1.set_ylim(0.5,4) 
ax1.yaxis.set_minor_locator(tck.MultipleLocator(0.5))
ax1.set_xlabel('Aggregation', labelpad=12)
ax1.set_ylabel('Transition energy [eV]', labelpad=12)

# function that correlates the two y-axes

def eV_to_nm(eV):
    return 1239.8 / eV

# adding a second y-axis

ax2 = ax1.twinx()  # share x axis
ax2.set_ylim(ax1.get_ylim())  # set the same range over y
ax2.set_yticks(ax1.get_yticks())  # put the same ticks as ax1
ax2.set_ylabel('Wavelength [nm]', labelpad=12)

# change the labels of the second axis by apply the mathematical 
# function that relates the two axis to each tick of the first
# axis, and then convert it to text
# This way you have the same axis as y1 but with the same ticks scaled

ax2.set_yticklabels([Text(0, yval, f'{eV_to_nm(yval):.1f}') 
                     for yval in ax1.get_yticks()])

# show the plot

plt.tight_layout(pad=1.5)
plt.show()

data.txt同上:

number eV nm
1 2.573 481.9
2 2.925 423.9
3 3.174 390.7
4 3.242 382.4
5 3.387 366.1

Output 圖像在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM