Python動態可視化入門—簡單繪圖、動圖和交互式繪圖

使用Python製作基本動畫和交互式繪圖

有時,您想創建一個動態圖形,該圖形可以隨時間變化,例如視頻,或者根據交互式用戶輸入進行調整。這些可視化在真正顯示輸出如何隨輸入變化方面做了大量工作。在本文中,我將提供與靜態圖,動畫和交互式圖相同的數據。我要繪製的數據將來自固態物理學中使用最廣泛的方程式之一:費米-狄拉克分佈,它描述了固體中電子的佔有率。該方程如下所示,該方程將在能量E下佔據的狀態分數與費米能量和溫度的函數聯繫起來。

Python動態可視化入門—簡單繪圖、動圖和交互式繪圖

靜態圖

我們的第一個圖將是一個靜態圖,其中在不同溫度下將具有f(E)曲線。首先,我們導入所需的庫:

<code># Import packages
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.widgets import Slider
import numpy as np/<code>

由於我們將多次計算費米-狄拉克分佈,因此我們應該編寫一個函數為我們進行此計算:

<code># Fermi-Dirac Distribution
def fermi(E: float, E_f: float, T: float) -> float:
    k_b = 8.617 * (10**-5) # eV/K
    return 1/(np.exp((E - E_f)/(k_b * T)) + 1)/<code>

現在我們可以開始繪製數據了!首先,我將編輯一些常規繪圖參數:

<code># General plot parameters
mpl.rcParams['font.family'] = 'Avenir'
mpl.rcParams['font.size'] = 18

mpl.rcParams['axes.linewidth'] = 2
mpl.rcParams['axes.spines.top'] = False
mpl.rcParams['axes.spines.right'] = False

mpl.rcParams['xtick.major.size'] = 10
mpl.rcParams['xtick.major.width'] = 2
mpl.rcParams['ytick.major.size'] = 10
mpl.rcParams['ytick.major.width'] = 2/<code>

我們創建圖並向其中添加axes對象:

<code># Create figure and add axes
fig = plt.figure(figsize=(6, 4))
ax = fig.add_subplot(111)/<code>

為了將變化的溫度數據提供給我們的Fermi-Dirac函數,我們使用以下命令生成了一個介於100 K和1000 K之間的值的數組numpy.linspace:

<code># Temperature values
T = np.linspace(100, 1000, 10)/<code>

對於每個溫度值,我們需要將不同的顏色映射到其結果曲線。我們將從coolwarm顏色版生成顏色,因為我們實際上是在處理溫度的變化,而且我們已經生成了上面的10個溫度值,所以我們將從coolwarm 顏色版中提取10種顏色。

<code># Get colors from coolwarm colormap
colors = plt.get_cmap('coolwarm', 10)/<code>

繪製數據的最簡單方法是遍歷所有溫度值並每次繪製對應的曲線。為了生成x軸值,我們再次使用numpy.linspace創建一個數組,該數組包含一個介於0和1之間的100個均勻間隔的值。此外,我們對所有計算都使用0.5 eV的固定費米能量值。

<code># Plot F-D data
for i in range(len(T)):
    x = np.linspace(0, 1, 100)
    y = fermi(x, 0.5, T[i])
    ax.plot(x, y, color=colors(i), linewidth=2.5)/<code>

我們的繪圖需要的最後一個元素是一種區分不同色溫曲線的方法。為此,我們將通過首先創建標籤列表,然後將其傳遞給axes.legend方法來創建圖例。

<code># Add legend
labels = ['100 K', '200 K', '300 K', '400 K', '500 K', '600 K', '700 K', '800 K', '900 K', '1000 K']
ax.legend(labels, bbox_to_anchor=(1.05, -0.1), loc='lower left', frameon=False, labelspacing=0.2)/<code>

labelspacing—圖例條目之間的垂直間距(默認為0.5)

最後,在添加軸標籤之後,我們將看到以下圖:

Python動態可視化入門—簡單繪圖、動圖和交互式繪圖

費米能量值為0.5 eV時費米-狄拉克分佈的溫度依賴性

生成動圖

現在說我們想提供與上述相同的數據,但作為視頻呈現—我們將如何做?事實證明,我們可以很容易地做到這一點matplotlib!我們必須導入以下內容以使我們可以使用此功能:

<code>from matplotlib.animation import FuncAnimation/<code>

如果我們使用的是Jupyter Notebook,我們還應該更改matplotlib用於渲染其圖形的後端,以便進行交互式繪圖。

<code># Change matplotlib backend
%matplotlib notebook/<code>

對於我們的動畫,我們需要執行以下操作:

(1)將對繪製曲線的參考存儲為變量

(2)使用帶有此變量的函數調用來不斷更新繪圖數據

我們將首先繪製空數組並將其存儲為名為f_d的變量。另外,我們將添加一個文本註釋以顯示當前圖顯示的溫度,因此我們還將存儲對此的變量引用。們將文本註釋的右上角對齊到axis對象的右上角。

<code># Create variable reference to plot
f_d, = ax.plot([], [], linewidth=2.5)

# Add text annotation and create variable reference
temp = ax.text(1, 1, '', ha='right', va='top', fontsize=24)/<code> 

現在,我們的動畫的主力—動畫函數,該函數將獲取索引的輸入,i並在每次調用時更新圖。它還將使用當前溫度更新文本註釋,並且基於顏色圖中的相同顏色來更改繪圖和文本的coolwarm顏色。

<code># Animation function
def animate(i):
    x = np.linspace(0, 1, 100)
    y = fermi(x, 0.5, T[i])
    f_d.set_data(x, y)
    f_d.set_color(colors(i))
    temp.set_text(str(int(T[i])) + ' K')
    temp.set_color(colors(i))/<code>

set_data(x, y)—為繪圖設置新的x和y數據。

我們使用以下代碼行:

<code># Create animation
ani = FuncAnimation(fig, animate, frames=range(len(T)), interval=500, repeat=True)/<code>

fig—將圖形傳遞給動畫函數

func —繪圖的動畫函數

frames—一個從0開始的數組,代表動畫的幀。在這種情況下,我們傳遞的長度等於要設置動畫的溫度的數量(這也是傳遞給func的索引i))。

interval —幀之間的延遲(以毫秒為單位)

repeat—是否在結束時重複播放動畫

Python動態可視化入門—簡單繪圖、動圖和交互式繪圖

費米能量為0.5 eV時,費米-狄拉克分佈的溫度依賴性動畫

現在,如果您的軸標籤或部分繪圖被切除,則可以嘗試添加以下代碼行,以確保所有元素都在圖中。

<code># Ensure the entire plot is visible
fig.tight_layout()/<code>

現在,要保存動畫,我們使用以下內容:

<code># Save and show animation
ani.save('AnimatedPlot.gif', writer='ImageMagick', fps=2)/<code>

writer—動畫編寫器程序—生成.gif文件,我使用ImageMagick

fps —動畫的每秒幀數(由於我們只有10幀,因此我使用fps值為2來模擬500 ms之前的間隔延遲)

互動圖

最後,如果我們想讓用戶使用輸入參數來觀察它們在輸出上的變化,我們可以製作一個交互式圖。我們首先導入所需的庫。

<code>from matplotlib.widgets import Slider/<code>

我們再次從創建圖形和軸對象開始以保存繪圖。但是,這一次,我們調整圖的大小以為要添加的滑塊騰出空間。

<code># Create main axis
ax = fig.add_subplot(111)
fig.subplots_adjust(bottom=0.2, top=0.75)/<code>

figure.subplots_adjust()接受頂部、底部、左側和右側的輸入,以指示在何處繪製軸邊框的四個角。在本例中,我們要確保頂部不超過0.75,這樣才能將滑塊放置在繪圖區的頂部。

滑塊就像其他任何軸對象一樣開始。在這裡,我們把兩個都加到圖上(一個用來改變費米能量,一個用來改變溫度)。此外,由於我們更改了全局圖設置以刪除右側和頂部,所以我們將把它們添加回這裡作為滑塊。

<code># Create axes for sliders
ax_Ef = fig.add_axes([0.3, 0.85, 0.4, 0.05])
ax_Ef.spines['top'].set_visible(True)
ax_Ef.spines['right'].set_visible(True)

ax_T = fig.add_axes([0.3, 0.92, 0.4, 0.05])
ax_T.spines['top'].set_visible(True)
ax_T.spines['right'].set_visible(True)/<code>

現在,我們必須將這些軸對象變成滑塊:

<code># Create sliders
s_Ef = Slider(ax=ax_Ef, label='Fermi Energy ', valmin=0, valmax=1.0, valinit=0.5, valfmt=' %1.1f eV', facecolor='#cc7000')
s_T = Slider(ax=ax_T, label='Temperature ', valmin=100, valmax=1000, valinit=300, valfmt=' %i K', facecolor='#cc7000')/<code>

ax —將軸對象轉換為滑塊

label —滑塊左側的滑塊標籤

valmin —滑塊的最小值

valmax —滑塊的最大值

valfmt—要顯示為滑塊值的字符串,位於右側。%1.1f是具有1個小數點的浮點數,並且%i是整數

facecolor —填充滑塊的顏色

現在,我們已經創建了滑塊,讓我們繪製“默認”數據集,該數據集將在首次加載圖形時顯示(0.5 eV的費米能量和300 K的溫度):

<code># Plot default data
x = np.linspace(-0, 1, 100)
Ef_0 = 0.5
T_0 = 300
y = fermi(x, Ef_0, T_0)
f_d, = ax.plot(x, y, linewidth=2.5)/<code>

就像在動圖中一樣,我們現在將定義update函數,該函數將在更新滑塊時更改數據。此update函數獲取滑塊的當前值,更改繪圖中的數據,然後重新繪製圖形。

<code># Update values
def update(val):
    Ef = s_Ef.val
    T = s_T.val
    f_d.set_data(x, fermi(x, Ef, T))
    fig.canvas.draw_idle()

s_Ef.on_changed(update)
s_T.on_changed(update)/<code>

Slider.on_changed(func)func更改滑塊值時調用更新。

Python動態可視化入門—簡單繪圖、動圖和交互式繪圖

費米-狄拉克分佈的溫度依賴性交互式圖

結論

希望本文能夠展示如何利用動圖和交互式滑塊使數據可視化動態化。


分享到:


相關文章: