秉着邊學邊寫邊折騰的原則,開始粗糙的工作。真正掌握還是得講解給別人聽。 先給出網課
https://www.icourse163.org/course/BIT-1001871001 Mayavi官方
http://docs.enthought.com/mayavi/mayavi/index.html
(有時候這網站會裝死,一般過幾個小時就會活過來)
mesh
節分成兩段,一段是mesh
的例子開始,第二段講解各個參數
1.mesh
http://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#mesh
先引用官方實例,官方的代碼又有點小問題,已調整。
import numpy as np
from mayavi.mlab import *
pi = np.pi
cos = np.cos
sin = np.sin
#數據處理
dphi, dtheta = pi / 250.0, pi / 250.0
[phi, theta] = np.mgrid[0:pi + dphi * 1.5:dphi, 0:2 * pi + dtheta * 1.5:dtheta]
m = [4,3,2,3,6,2,6,4]
r = sin(m[0] * phi) ** m[1] + cos(m[2] * phi) ** m[3] + \
sin(m[4] * theta) ** m[5] + cos(m[6] * theta) ** m[7]
# 這裏做了座標系變換,需要注意一下
x = r * sin(phi) * cos(theta)
y = r * cos(phi)
z = r * sin(phi) * sin(theta)
mesh(x, y, z, colormap="bone")
show()
這段代碼很關鍵的兩個地方
1.mgrid 將數據全部離散成網格
2.座標系變換mgrid做了什麼呢
這樣可以把 (0,0)–(4,3)離散成20個網格點,網格的分辨率默認爲1,也就是他的間隔
s1,s2的對應位置匹配,就是座標位置s1對應x,s2對應y,s1,s2的維度必然一致。
[phi, theta] = np.mgrid[0:pi + dphi * 1.5:dphi, 0:2 * pi + dtheta * 1.5:dtheta]
案例中的寫法,設定了步長,步長有兩種設定
還有一種設定就是劃分數量
s1在縱向被拆成4段,橫向拆成3段
文檔中,對於.mesh
的描述如下:
For mesh defined by triangles rather than regular implicit
connectivity, see the triangular_mesh function.
也就是說,它用三角形網格進行了繪製,現在我們來放大圖像的細節。
現在我們修改了它的線框爲wireframe
mesh(x, y, z, colormap="bone",representation='wireframe') #representation的默認值是'surface'
也修改代碼的管線部分,在show()
之前我們插入以下代碼片段,關於管線配置的代碼以後會專門講。
scene = gcf()
surface = scene.children[0].children[0].children[0].children[0]
surface.actor.property.representation = 'wireframe'
也可以直接進行配置
三者效果相同,效果如下
這裏就很明顯地看得到繪製的方式,是三角形網格。
有心的朋友注意到這句話,
For simple structures (such as orthogonal grids) prefer the surf
function, as it will create more efficient data structures.
對於簡易的常規結構,如正交網格,儘量用surf
函數,因爲它能生成更高效的數據結構。(原諒我的翻譯)
surf
用於繪製正交網格
那麼現在有兩個問題:
1.如果修改上面的代碼將繪製方式mesh換成surf會不會一樣的效果?會不會效率更高?
2.這個效率問題,怎麼說,(我也不知道別打我,我只能簡單猜一下計算量,以後來填坑)
The connectivity between these points is implied by the connectivity on the arrays. From data points to surfaces.
在
mesh
繪製中,點與點之間的連接關係由向量決定,(數據在向量中的位置來確定連接順序)也就是連通是隱式地表達在array中。這是和triangular_mesh
最大的不同。
2.triangular_mesh
triangular_mesh
比mesh
更具有一般性,triangular_mesh
需要定義連通方式。這是最大的不同
triangular_mesh
的講解分成三部分,第一部分需要說明這種顯性連通方式是什麼,怎麼回事,通過官方的一個實例來說明。第二部分分析它的代碼,它是怎麼實現這種顯式定義的,先分析第一個實例,只展示部分代碼。第三部分就是,最後一個實例,文檔中給出的triangular_mesh
實例,展示全部代碼。
For
mesh
defined by triangles rather than regular implicit connectivity, see thetriangular_mesh
function.
Knowing the positions of data points is not enough to define a surface, connectivity information is also required. With the functionssurf()
andmesh()
, this connectivity information is implicitly extracted from the shape of the input arrays: neighboring data points in the 2D input arrays are connected, and the data lies on a grid. With the functiontriangular_mesh()
, connectivity is explicitly specified. Quite often, the connectivity is not regular, but is not known in advance either. The data points lie on a surface, and we want to plot the surface implicitly defined. The delaunay2d filter does the required nearest-neighbor matching, and interpolation, as shown in the (Surface from irregular data example).相對於隱式連通的網格而言,有些是常規繪製(比如上面的
surf
常爲正交網格),mesh
是用三角網格進行繪製。對於triangular_mesh
的繪製方式而言,僅僅獲得數據點的位置是不足以確定一個曲面的,還需要取得它的連通方式。在surf()
和mesh()
的表達中,連通方式隱含在了2D數組中,相鄰的數據點之間相互連接成爲網格。而在triangular_mesh()
中,數據點的連接方式不再是隱式,而是需要明確規定。而且經常都不是常規的連通方式,甚至預先無法確認。這些數據將以一定方式以曲面呈現,並且以我們期望的隱式連通方式顯示這個曲面。delaunay2d filter(這個屬於管線)確實是需要就近匹配,以及插值,如例子。(後面這兩句話我自己都沒讀懂)
下面將舉出一個例子,爲了防止我翻譯的誤導,我把它原封不動地摘過來,方便閱讀。
例子的網址和 完整代碼(我不寫代碼,我只是代碼的搬運工)An example which shows how to plot a surface from data acquired irregularly.
Data giving the variation of a parameter ‘z’ as a function of two others (‘x’ and ‘y’) is often plotted as a carpet plot, using a surface to visualize the underlying function. when the data has been acquired on a regular grid for parameters ‘x’ and ‘y’, it can simply be view with themlab.surf
function. However, when there are some missing points, or the data has been acquired at random, the surf function cannot be used.
The difficulty stems from the fact that points positionned in 3D do not define a surface if no connectivity information is given. With thesurf
function, this information is implicite from the shape of the input arrays.
In this example, randomly-positionned points in the (x, y) plane are embedded in a surface in the z axis. We first visualize the points usingmlab.points3d
. We then use thedelaunay2d filter
to extract the mesh by nearest-neighboor matching, and visualize it using the surface module.以下的例子將展示如何繪製一個由非常規的數據集繪製的面,數據中給定了變量’z’作爲另外兩個參數’x’,'y’的函數,並將以可視化的三維面展示給定的函數。對於常規網格,給定參數x,y結合
mlab.surf
函數很容易完成可視化。但是,當網格中出現很多缺失的數據點,或者數據的提取方式是隨機的,surf
並不能達到目的。
其核心原因在於,如果沒有給定連通方式,3維座標點是無法確定一個曲面的。而在surf
中,連通方式包含在數組信息裏。
在下面的例子中,選取xoy平面,隨機分佈的座標點將嵌入平面。(這裏翻譯是有問題的,有能力請閱讀上面的英語文獻,告知我的翻譯問題)
首先,我們使用mlab.points3d
呈現這些點,然後我們使用delaunay2d filter通過就近匹配來繪製網格,用面來呈現可視化。
關於delaunay2d filter
上面那個鏈接中的圖像進行一些處理,在原有基礎上,我們設置
representation='wireframe'
可以看到連通方式,一目瞭然,對於nearest-neighboor matching可以有一個直觀的印象。再來一張更全面的圖像,圖像是立體的。
再來一張充滿細節的圖像,所謂的nearest-neighboor matching是怎麼回事
可以自行查看更多細節,每一個點的連接了周圍所有最近的點,這個連通構成了一張網,即所謂的grid,大家應該玩過太空網,只不過這不是一個規則的網格。這張網一旦填充顏色成爲網格更像是具有一定分辨率的多面體,分辨率足夠高的時候看起來就像是曲面了,這跟折線圖是一致的,將相鄰、離散的數據用直線連接起來,只不過這裏用的是平面,以直代曲。以平面代曲面。這就是上面英文文獻所說,需要顯式來明確定義不規則網格數據,irregular data。
然後我們再來看看代碼裏面,它是怎樣給出顯式數據的連通方式的。
pts = mlab.points3d(x, y, z, z, scale_mode='none', scale_factor=0.2)
#繪製點,並把z作爲標量值
mesh = mlab.pipeline.delaunay2d(pts)
surf = mlab.pipeline.surface(mesh)
第1行代碼繪製了點 ,2.3行利用了
pipeline
配置了管線,對於delaunay2d()
方法的解釋如下。此時定義了網格的連通方式,然後在第三行代碼,對這個網格進行了可視化,並且可以觀察到管線中的filters
是有兩項的。當註釋掉2.3行代碼的時候,只能得到數據點,僅註釋第三行,可以通過配置管線來得到這個圖像,也就是說,網格的信息已經被delaunay2d()
方法導入,僅註釋第二行, 修改爲
surf = mlab.pipeline.surface(pts)
會發現Surface
和Glyph
置於同一個filters
,ScalarScatter
之下,而對Glyph
的Actor
將visibility
選項去除掉,將其可視化的點集隱藏,會發現Surface
中是沒有數據的,是空的。如此一對比,結論就是delaunay2d()
處理了pts
的空間點集數據,給定了連接方式,而surface()
方法添加了filter
下面的Surface
可視化模塊,把上面定義連通mesh
呈現出來。delaunay2d:Perform a 2D Delaunay triangulation for the given data.
delaunay3d:Perform a 3D Delaunay triangulation for the given data.將給定的數據進行Delaunay狄式二維三角化處理.另一個是三維。
我們來對比一下。很顯然
delaunay2d
和delaunay3d
有不同的連通方式,這就是爲什麼要顯式來定義,必須明確的指出連通方式。進一步觀察delaunay3d的細節。觀察到連接方式已經不是就近連接了,如果再仔細一點,
delaunay2d
的連接方式是忽略z的座標僅僅連接的是2維空間裏相鄰的點,delaunay3d
是考慮的三維空間裏相鄰的點,連接的線由此構成網格,這兩者難說誰更好,在這裏例子中,2d連接方式更優,不容易遮擋。不過挺有意思的,如果是圖論中的一些問題,很有啓發性。
上面僅僅說明一下連通方式,下面一個例子是
triangular_mesh()
的繪製,終於進入主題了,敲黑板!
代碼這裏,不過官方代碼有點小瑕疵
這裏爲了節約篇幅降低了可讀性,調整之後的代碼如下
import numpy as np
from mayavi.mlab import *
n = 8
t = np.linspace(-np.pi, np.pi, n);z = np.exp(1j * t)
x = z.real.copy();y = z.imag.copy();z = np.zeros_like(x)
triangles = [(0, i, i + 1) for i in range(1, n)]
x = np.r_[0, x];y = np.r_[0, y];z = np.r_[1, z];t = np.r_[0, t]
triangular_mesh(x, y, z, triangles, scalars=t) #這裏是關鍵點
show()
這段代碼最關鍵的地方就是
triangular_mesh(x, y, z, triangles, scalars=t)
我們來看看它的語法triangular_mesh(x, y, z, triangles ...)
,它比mesh
額外要求了一個triangles
參數用來描述連通方式,我們繼續看下去,對於函數的說明如下x, y, z are
arrays
giving the positions of the vertices of the surface.triangles
is a list of triplets (or an array) list the vertices in each triangle. Vertices are indexes by their appearance number in the position arrays.
For simple structures (such as rectangular grids) prefer the surf or mesh functions, as they will create more efficient data structures.給定的x,y,z必須是
array
類型,一組x,y,z代表了平面中的一個點.triangles
參數爲一個3維triplet
或者array
類型,列舉所要繪製的三角面的三個點。列舉規則是,列出他們在x,y,z列表中,他們的index
索引。簡單說一下,比如
x=[1,5,7,4,2];y=[85,74,41,2,65];z=[74,1,45,8,0]
連通的3個點分別是1,4,5,對於索引而言是0,3,4
triplet=(0,3,4)
(1,85,74),(4,2,8),(2,65,0)三個點將會連接成一個面
我們可以通過斷點調試的方式來獲得例子中間量
t被離散成8段,t=[-3.14159265 -2.24399475 -1.34639685 -0.44879895 0.44879895 1.34639685 2.24399475 3.14159265]
此後各種操作之後,最關鍵的我們的triangles
,
這裏給出x
方便對照,x
=[0.00,-1.00,-0.62,0.22,0.90,0.90,0.22,-0.62,-1.00]
triangles
=[(0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 5), (0, 5, 6), (0, 6, 7), (0, 7, 8)]
如(0, 1, 2)這個元組,分別取了xyz的索引(0,0,0)(1,1,1),(2,2,2)
對應:[0.0, 0.0, 1.0], [-1.0, -1.22e-16, 0.0], [-0.62, -0.78, 0.0],三個點構成了一個面
我們可以用point3d()
將這三個點描出來,如下圖:
插入以下代碼片段即可,不再說明了
xp = [x[0],x[1],x[2]]
yp = [y[0],y[1],y[2]]
zp = [z[0],z[1],z[2]]
points3d(xp,yp,zp,scale_factor=0.1)
總結以上,
xyz
裏面存放座標點,由第4個參數來傳遞連通方式,連接成爲三角形的面。
最後提醒一下,
scalars=t
這裏,t
是一個列表傳遞給了scalars
參數,代表每個點的標量值,本例中t的數目爲9,底面8個,頂點一個,如果不設置它,將會以z
的值作爲默認標量進行映射
3 .mesh和triangular_mesh的參數
另外mesh
有很多省略參數,現在一一說明
9個通用參數,見這裏
extent
[xmin, xmax, ymin, ymax, zmin, zmax] Default is the x, y, z arrays extent. Use this to change the extent of the object created.
這個原本以爲只是過濾一些值,但是不是,它修改了原數據。
原圖
對代碼進行一些修改如下:
extent =[-1,1,-0.9,0.8,-2,2]
mesh(x, y, z, representation='wireframe',colormap='Wistia',color=(1,1,0),extent=sph)
outline()
#繪製外框
xlabel('x')
#繪製座標軸
ylabel('y')
.
爲了方便對比。增設xlabel
,ylabel
,outline
做一個外框
增設extent = [-1,1,-0.9,0.8,-2,2]
之後
然後我吃了一驚,extent
應該是在某個範圍裏面進行了整體放縮。瘦身大法好啊
figure
Figure to populate.
這個還沒用過。。。。。。。。
line_width
The width of the lines, if any used. Must be a float. Default: 2.0
線寬,處於Actor下,默認值是2.0,我們來試試0.1線寬效果
mesh(x, y, z, representation='wireframe',colormap='Wistia',line_width = 0.1)
是不是很se.qing,sexy!敲漂亮!蟬翼般的效果。
mode
the mode of the glyphs. Must be ‘2darrow’ or ‘2dcircle’ or ‘2dcross’ or ‘2ddash’ or ‘2ddiamond’ or ‘2dhooked_arrow’ or ‘2dsquare’ or ‘2dthick_arrow’ or ‘2dthick_cross’ or ‘2dtriangle’ or ‘2dvertex’ or ‘arrow’ or ‘axes’ or ‘cone’ or ‘cube’ or ‘cylinder’ or ‘point’ or ‘sphere’. Default: sphere
符號模式,默認值sphere
這個圖不起效果,這是個問題。
representation
the representation type used for the surface. Must be ‘surface’ or ‘wireframe’ or ‘points’ or ‘mesh’ or ‘fancymesh’. Default: surface
這個是設置繪製的樣式,有幾種形態, ‘surface
’ 、 ‘wireframe
’ 、 ‘points
’ 、 ‘mesh
’、 ‘fancymesh
’.
最常用的就是surface
和wireframe
,比較特殊的就是fancymesh
,這個我嘗試過一下,它改變了管線,同時帶來了Glyph
,使mask_points
,mode
,同時起效果了。
mesh(x,y,z,representation='fancymesh',colormap='Wistia',line_width=2,mask_points=100,mode='2ddiamond', name = '修改的是這個位置')
這圖很多地方也長了點’2ddiamond
’,二維鑽石??Emmm
另外一個representation='mesh'
參數的效果是這樣的:
兩者的管線配置是不一樣的,但並非是mask_points
和mode
觸發了Glyph
的建立,兩者同時缺省的時候,Glyph
還是建立了,fancymesh
反而讓它們有了效果。
另外,不推薦用這兩個,很燒顯卡,跑起來很卡。
resolution
The resolution of the glyph created. For spheres, for instance, this is the number of divisions along theta and phi. Must be an integer (int or long). Default: 8
這個參數是用來設置Glyph
分辨率的,後面說points3d
會講到。比如球體的細分數,默認值是8.
引用一個例子
http://docs.enthought.com/mayavi/mayavi/auto/example_flight_graph.html (鏈接有時候會死)sphere = mlab.points3d(0, 0, 0, scale_mode='none', scale_factor=2, color=(0.67, 0.77, 0.93), resolution=50, #注意這個位置 opacity=0.7, name='Earth')
截取上面這段代碼,這段代碼是很有意思的,我大致解釋一下,
points3d
它是在一個點上面畫大洲的線條。只不過這個點很有意思,它有大小的,就是scale_factor=2
,默認值是0.05,它放大了40倍。
我貼兩個圖,自行感受一下resolution
左邊:resolution=5
右邊:resolution=50
右邊的像一個球了,然而並不是,只是近似,它仍然是個多面體。順帶一提,這不是正n面體,正n面體,n只能取得4,6,8,12,20.據說resolution取默認值8的時候,會有82個頂點,所謂細分數,看翻譯應該能獲知一二,如果要計算,可能會用一下拓撲V+F-E=2那個公式,詳細不展開了。
scale_factor
scale factor of the glyphs used to represent the vertices, in fancy_mesh mode. Must be a float. Default: 0.05
這個參數在上面那個例子中用到了,scale_factor=2
將點進行了放大,這個參數就是放大係數,我們嘗試修改一下看看效果。
左圖:scale_factor=3
右圖:scale_factor=2
tube_radius
radius of the tubes used to represent the lines, in mesh mode. If None, simple lines are used.
繼續借用上面的例子,原來的例子中有一項設置,代碼太長,不貼了,只說明這個參數的效果
mlab.plot3d(x, y, z, color=(1, 1, 1),opacity=0.2,tube_radius=None)
#在最後幾行
這裏栗子中使用的值是tube_radius=None
,後者去掉了這個參數
這個設置與否的效果完全不同,一是圖像不同,本身性質也不一樣。
設置之後,放大若干倍,迴歸線和赤道的線不會被放大,它的本質是線,沒有粗細,而不設置,他們的大小會隨着放大而放大,它是管,是有粗細概念的!!
所以當我們要得到的是線的時候,需要增設tube_radius
的參數。
而在管線的配置中,None
的效果使得Stripper
、Tube
兩個層級消失了。
注意一個細節,文檔中提到繪製模式用的是
mesh
,設置representation='wireframe'
之後可以觀察到三角形網格
tube_sides
number of sides of the tubes used to represent the lines. Must be an integer (int or long). Default: 6
設置構成tube的線條數目,默認爲6,有點像resolution
,分辨率。
修改第二條Tube
的tube_sides
也就是赤道那一條的值爲25
,設置爲wireframe
可觀察到如下:
赤道的這條管子分辨率很高25,對比迴歸線的6。
scale_mode
the scaling mode for the glyphs (‘vector’, ‘scalar’, or ‘none’).
http://docs.enthought.com/mayavi/mayavi/auto/example_surface_from_irregular_data.html
然後用這個例子來進行一點簡單的說明,(爲防止打不開,我還是貼一下代碼部分,去掉註釋減小行數)
這段代碼不必太糾結,這裏面涉及了圖像控制函數figure
,管線pipeline
後續都會專門寫,此處只需要留意scale_mode
的效果即可。import numpy as np np.random.seed(12345) x = 4 * (np.random.random(500) - 0.5);y = 4 * (np.random.random(500) - 0.5) def f(x, y): return np.exp(-(x ** 2 + y ** 2)) z = f(x, y) from mayavi import mlab mlab.figure(1, fgcolor=(0, 0, 0), bgcolor=(1, 1, 1)) pts = mlab.points3d(x, y, z, z, scale_mode='scalar', scale_factor=0.2) #scale_mode在這個位置 mesh = mlab.pipeline.delaunay2d(pts) surf = mlab.pipeline.surface(mesh) mlab.view(47, 57, 8.2, (0.1, 0.15, 0.14)) mlab.show()
此時執行效果如下:
觀察管線裏面的Scale mode
配置,對應的是scale_by_scalar
以下是三個參數的對比
管線裏面的對應關係
data_scaling_off
——none
顯示顆粒
scale_by_scalar
——scalar
按照標量值的大小顯示顆粒
scale_by_vector
——vector
按照矢量值的大小顯示顆粒
調過管線的朋友會發現,其實裏面不止三個選項
最後一個scale_by_vector_components
似乎沒有效果,
查詢了一下文檔,可自行閱讀
28 Jun, 2009 (PR):
BUG: Mlab’s barchart uses the scale_by_vector_components which was not exposed by the glyph component leading to update problems reported by Christian Vollmer. This is now fixed along with a simple test case. There are deeper problems with barchart that do need attention though - if a user changes the data inplace and calls the mlab_source.update() nothing updates correctly since the data is really copied over to the vector components. This can be fixed with a callback and will be done later. [23980]
mask_points
If supplied, only one out of ‘mask_points’ data point is displayed. This option is useful to reduce the number of points displayed on large datasets Must be an integer (int or long) or None.
這個用於降採樣,只接受整形、長整型,或者缺省,每N個點取一個,可以增設選取原則爲隨機。
還是用這個圖,對這行代碼追加一個mask_points
參數得到下面的圖。
pts = mlab.points3d(x, y, z, z, scale_mode='scalar', scale_factor=0.2,mask_points=5)
察看管線配置裏面發生的變化
以mask_points=5
爲例,增設之後的變化就是Mask input points
被自動勾選了,On ratio
被設置好了,意爲每N個點取一個,其次需要注意的是藍色框Random mode
選項也被自動勾選了,選取的點是隨機的。
scalars
optional scalar data.
爲座標點設置標量,座標點的長度和scalars
被傳遞的列表長度應該相同。這個值不設置,默認採用z的值作爲標量值。
mask
boolean mask array to suppress some data points. Note: this works based on colormapping of scalars and will not work if you specify a solid color using the color keyword.
這個沒查到相關實例,只有surf
和mesh
含有這個參數。如果誰知道這個有什麼效果記得告訴我一下,還有上面的
scalars
。(已解決)
這篇小文快結束了,順帶說一下手動設置幾個小細節讓圖完整一點
1.一般會添加一個
outline()
放在最外面和IsoSurface
處於一個層級,做個外框,方便看值域範圍
2.會添加Legend
在右邊,並且對這個bar
設置一定的透明度、title
的大小的樣式以及標量值的步長。
3.在圖像中再添加xlabel
,ylabel
,zlabel
進去把值也標定
.colorbar
和.scalarbar
可以實現相同的效果。後期會講設置一個可移動的平面來獲得各個面上的值,作爲輔助觀察手段。哦對,順帶一說,那個bar是可以移動的。
2.2會完整地講管線裏面的所有設置
今天10.07,明天要上課,有空會繼續添加例子。
.
.
.
.
.
填坑區:
1.多圖顯示可以嘗試一下,分屏還是一屏多圖,
分屏的話不容易,一屏多圖可以實現,配置多個數據源即可。
2.
mesh
和surf
的效率怎麼解釋?
3.reset_zoom()
上面舉例的時候的一個報錯問題
4.mask
、scalars
的效果不知
scalars
參數已補充
更新(18.10.6已更完)
2018.09-30.——寫到reset_zoom
停下
2018.10-02.——補充參數reset_zoom
和transparent
的例子
———————文末的bar
小技巧
2018.10.06. ——補充參數scale_factor
、resolution
、mask_points
、scale_mode
、tube_radius
、tube_sides
的例子
2018.10.07.——大幅度調整,去掉了color
,colormap
,line_width
,name
,opacity
,reset_zoom
,transparent
,vmax
,vmin
,共9個通用參數部分。通用參數獨立成一篇,增加triangular_mesh
部分。
2018.10.08.——triangular_mesh
未更完,缺少triangular_mesh
的文檔翻譯和例子的說明、需要再補充實例、必要需要補充網格知識點插入1.0-2.0直接的VTK數據集解說
2018.10.09.——triangular_mesh
未更完,補充了顯式連通的實例,做部分翻譯,補充triangular_mesh
的實例,對比delaunay2d
、delaunay3d
2018.10.09.——triangular_mesh
更完,補充翻譯,補充scalars
參數。