Traited VTK (tvtk) の概要

作者:Prabhu Ramachandran
連絡先:prabhu@enthought.com
Copyright:2004-2020, Enthought, Inc.

はじめに

tvtkモジュール(TVTKとも呼ばれる)は VTKtraits 対応バージョンを提供します.TVTKオブジェクトはVTKオブジェクトをラップしますが,さらに traits をサポートし,便利なPython APIを提供します.TVTKは主に純粋なPythonで実装されています(小さな拡張モジュールを除く).現在の機能は次のとおりです.

  • すべてのVTKクラスがラップされます.
  • クラスは,インストールされたプラットフォームでインストール時に生成されます.
  • traits のサポート.
  • 要素pickleのサポート.
  • Pythonicな雰囲気.
  • 数値配列/Pythonリストを透過的に処理します.
  • パイプラインブラウザ, ivtk ,高レベルの mlab のようなモジュールのサポート.
  • tvtkシーンとパイプラインブラウザのプラグインを想定しています.
  • tvtkはBSDスタイルのライセンスのフリーソフトウェアです.

要件

tvtkを実行するための要件を次に示します.

  • Python-2.3以降.
  • Pythonはzlibサポートでビルドされ,ZIPファイルのインポートをサポートしている必要があります.
  • VTK-5.x,VTK-4.4またはVTK-4.2.VTK-3.xでは動作しない可能性があります.
  • Traits.
  • numpy -- 最近のバージョンであれば問題ありません.
  • ivtk.pymlab を使用するには, pyface をインストールする必要があります.
  • プラグインを使用するには,Envisageをインストールする必要があります.

インストール

TVTKは mayavi パッケージの一部としてインストールされます.Mayaviマニュアルのインストールガイドを参照してください.

このドキュメントでは,mayavi_repositoryのチェックアウト内からのTVTKの構築と使用についてのみ説明します.tvtkモジュールは tvtk の内部にあります.tvtkモジュールを構築し, mayavi ソースの内部から使用するには,mayaviソースツリーのベースから以下を行います(ここでは,これが /home/user/src/lib/mayavi にあると仮定します.):

$ pwd
/home/user/src/lib/mayavi
$ python setup.py build

コード生成には少し時間がかかります.450 MHzのPentiumIIIマシンでは,コードの生成に約1分かかります.コード生成が成功すると,tvtkディレクトリに tvtk_classes.zip というZIPファイルと拡張モジュールが表示されます.

これでインストールは完了です.ビルドをテストするには, tests/ ディレクトリでテストを実行します.これはビルドされたコードをテストします.

$ pwd
/home/user/src/lib/mayavi
$ python -m nose.core -v tvtk/tests
[...]

テストが正常に実行されれば,ビルドは正常です. tests ディレクトリには,実行可能な他のテストもあります.

ドキュメントは 'docs/' ディレクトリにあります. 'examples/' ディレクトリには,tvtkの動作を示す簡単な例がいくつかあります.

基本的な使用法

tvtkの使用例を次に示します.

>>> from tvtk.api import tvtk
>>> cs = tvtk.ConeSource()
>>> cs.resolution = 36
>>> m = tvtk.PolyDataMapper()
>>> m.set_input_data(cs.output)
>>> a = tvtk.Actor()
>>> a.mapper = m
>>> p = a.property
>>> p.representation = 'w'
>>> print(p.representation)
'wireframe'

または同等に:

>>> from tvtk.api import tvtk
>>> cs = tvtk.ConeSource(resolution=36)
>>> m = tvtk.PolyDataMapper(input=cs.output)
>>> p = tvtk.Property(representation='w')
>>> a = tvtk.Actor(mapper=m, property=p)

オブジェクトのプロパティは,インスタンス化時に設定できます.

tvtkをインポートするには:

from tvtk.api import tvtk

これは少し不便かもしれませんが,tvtkはすべてのVTKクラスにアクセスできることに注意してください.これは vtk パッケージの動作と同じです.

VTK-Pythonに慣れているなら,上の例から明らかなように,tvtk はVTKに似ているように "感じ" ますが,もっとPython的です.最も重要な違いは次のとおりです.

  1. tvtkクラス名は基本的にVTKクラスに似ていますが,前面に迷惑な 'vtk' がない点が異なります.唯一難しいのは,数字で始まるクラスです.たとえば, 'vtk3DSImporter' は '3DSImporter' になります.これはPythonでは不正であるため,使用されるクラス名は 'ThreeDSImporter' です.したがって,最初の文字が数字の場合,対応する非数字文字列に置き換えられます.このようなクラスはほとんどないので,大したことではありません.
  2. tvtkメソッド名は enthought 形式の名前であり,CamelCaseではありません.つまり,VTKメソッドが AddItem と呼ばれる場合,同等のtvtk名は add_item となります.これは, enthought パッケージで使用される名前との一貫性を保つためです.
  3. 多くのVTKメソッドは,便利なプロパティーに置き換えられています.上記の例では, m.SetInput(cs.GetOutput())p.SetRepresentationToWireframe() などではなく m.input = cs.outputp.representation = 'w' を使用しています.これらのプロパティのいくつかは,実際には traits です.
  4. VTKオブジェクトとは異なり,tvtkオブジェクトのプロパティーを設定するには,オブジェクトを初期化するときに,クラスのインスタンス化時にオブジェクトのプロパティー (trait) をキーワード引数として渡します.たとえば, cs = tvtk.ConeSource(radius=0.1, height=0.5) です.

VTKに慣れているのであれば,慣れるのに少し時間がかかるかもしれません.ただし,これらの変更はすべてのtvtkで一貫しています.そうでない場合は,バグです.矛盾があれば教えてください.

基礎となるVTKオブジェクトが別のVTKオブジェクトを返す場合,これは適切にtvtkオブジェクトとしてラップされます.同様に,tvtkメソッドに関連するすべてのパラメータはtvtkオブジェクトでなければなりません.これらは透過的にVTKオブジェクトに変換されます.

高度な使用法

tvtkには,上記以外にもいくつかの重要な新機能があります.tvtkオブジェクトは基本的にVTK-Pythonオブジェクトをラップし,VTKオブジェクトにtraitを有効にしたAPIを提供します.これらの新機能について議論する前に,tvtkオブジェクトの "basic state" または "state" が何を意味するかの概念を理解することが重要です.これを定義し,新機能を詳細に論じました.

tvtkオブジェクトの "basic state" の定義

tvtkでは,traitとして表現され,値として単純なPython型 (int/float/string) または特別な値(色を指定するタプルのように)を持つVTKオブジェクトのすべてのプロパティのセットが状態を定義します.

tvtkの実装では, <Property>On<Property>OffSet<Property> To<Value>Set/Get<Property> (戻り値の型はint/float/string/tupleです.)の形式を持つメソッドを使って設定できるVTKオブジェクトの任意のプロパティがtraitとして表現されます.これらのプロパティーは,tvtkオブジェクトの "basic state" を表すと言われています.

基礎となるC++オブジェクトの完全な状態は,Pythonの世界では表現できないことに注意してください.これは,通常,他のC++オブジェクトへのさまざまなポインタが含まれるためです.

また,オブジェクトのアイデンティティがVTKの挙動に従って保存されることを考慮することも重要である.たとえば,次のコードでは, GetLines() のVTK実装によって作成されるデフォルトオブジェクトは,どのvtkPolyDataでも同じです.

>>> data1 = vtk.vtkPolyData()
>>> data2 = vtk.vtkPolyData()
>>> data1.GetLines()
(vtkCellArray)0x103b52e30
>>> data2.GetLines()
(vtkCellArray)0x103b52e30

同等のtvtkコードも同様に動作します.

>>> data1 = tvtk.PolyData()
>>> data2 = tvtk.PolyData()
>>> data1.lines
<tvtk.tvtk_classes.cell_array.CellArray at 0xe11e570>
>>> data2.lines
<tvtk.tvtk_classes.cell_array.CellArray at 0xe11e570>

ラップされたVTKオブジェクト

通常,ユーザはこれを知るべきではありません(これに頼るしかない!)が,tvtkオブジェクトがラップした基礎となるVTKオブジェクトにアクセスする方法を知っておくと役に立つことがあります.推奨される方法は, to_vtk 関数を使用することです.例

>>> pd = tvtk.PolyData()
>>> pd_vtk = tvtk.to_vtk(pd)

VTKオブジェクトからtvtkオブジェクトを作成する逆のプロセスは,以下のように to_tvtk 関数を使用することです.

>>> pd1 = tvtk.to_tvtk(pd_vtk)
>>> print(pd1 == pd)
True

pd1 == pd に注目してください.TVTKは既存のtvtkオブジェクトの内部キャッシュを維持し, to_tvtk メソッドにVTKオブジェクトが与えられると,特定のVTKオブジェクトのためにキャッシュされたオブジェクトを返します.これは,次のような場合に特に便利です.

>>> cs = tvtk.ConeSource()
>>> o = cs.output
>>> m = tvtk.PolyDataMapper()
>>> m.input = o
>>> # ...
>>> print(m.input == o)
True

tvtkオブジェクトがPythonでスコープ外になると,ガベージコレクションされることに注意してください.ただし,その基礎となるVTKオブジェクトは,VTKパイプライン内にまだ存在している可能性があります.このオブジェクトにアクセスすると,新しいtvtkラッパーオブジェクトが作成されます.以下にその例を示します.

>>> cs = tvtk.ConeSource()
>>> o = cs.output
>>> m = tvtk.PolyDataMapper()
>>> m.input = o
>>> print(hash(o))
1109012188
>>> print(hash(m.input))
1109012188
>>> del o
>>> print(hash(m.input))
1119694156

したがって, o がガベージコレクションされた後, m.input はもはや元のtvtkオブジェクトを参照せず,新しいものが作成されます.これはVTKの動作とよく似ています.この動作を変更するのは難しく,現在のところこれを変更する計画はありません.

tvtkとtrait

すべてのtvtkオブジェクトは traits.HasStrictTraits から派生します.前述したように,基本的な状態関連メソッドはすべてtvtkの特性として表されます.これが,次の操作を実行できる理由です.

>>> p = a.property
>>> p.representation = 'w'
>>> print(p.representation)
'wireframe'
>>> # OR do this:
>>> p = tvtk.Property(opacity=0.5, color=(1,0,0), representation='w')

また, set メソッドを使用して,tvtkオブジェクトの多くのプロパティを一度に設定することができることにも注意してください.例:

>>> p = tvtk.Property()
>>> p.trait_set(opacity=0.5, color=(1,0,0), representation='w')

tvtkオブジェクトは,自動的にtraitedクラスの基本機能を提供します.したがって,どんなtvtkオブジェクトに対しても,ごく簡単に標準のGUIエディターをポップアップすることができます.例えば, pycrust を使っているか, gui_thread ( SciPy がインストールされている場合は,このモジュールを使用できます.)か ipython -wthread を使っているなら,これは簡単にできます:

>>> p = tvtk.Property()
>>> p.edit_traits()
>>> # OR
>>> p.configure_traits() # This should work even without gui_thread

この時点でGUIエディタがポップアップ表示されます.traitに加えられた変更は,自動的に配下のVTKオブジェクトに伝播されることに注意してください.最も重要なのは,その逆も正しいということです.つまり,他のオブジェクトがラップされたVTKオブジェクトの基本状態を変更すると,traitは自動的に更新されます.例:

>>> p = tvtk.Property()
>>> print(p.representation)
'surface'
>>> p_vtk = tvtk.to_tvtk(p)
>>> p_vtk.SetRepresentationToWireframe()
>>> print(p.representation)
'wireframe'

また,インタープリターでオブジェクトのプロパティーを変更し,同時にGUIエディターを使用している場合,オブジェクトが変更されると,GUIエディターが自動的に更新されます.

tvtkオブジェクトには厳密な特性があることに注意してください.したがって,クラスでまだ定義されていない属性を設定するとエラーになります.これを次の例に示します.

>>> cs = tvtk.ConeSource()
>>> cs.foo = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TraitError: Cannot set the undefined 'foo' attribute of a 'ConeSource' object.

サブクラス化tvtkクラス

tvtkクラスをサブクラス化することもできますが,以下の点に注意してください.

  1. すべてのtvtkクラスは HasStrictTraits から派生します.
  2. 必ずスーパークラスの __init__ を正しく呼び出してください.
  3. __del__ メソッドをオーバーライドする必要がある場合は,スーパークラスの __del__ メソッドを呼び出す 必要 があります.

tvtkオブジェクトの選択

tvtkオブジェクトは単純な形式のピクルをサポートしています.tvtkオブジェクトのstate_はpickle化されている可能性があります.オブジェクトが保持する他のVTKオブジェクトへの参照は,選択 できません .例

>>> import cPickle
>>> p = tvtk.Property()
>>> p.representation = 'w'
>>> s = cPickle.dumps(p)
>>> del p
>>> p = cPickle.load(s)
>>> print(p.representation)
'wireframe'

ここでも,オブジェクトの state だけがpickleされます.内部参照はありません.そのため,VTKパイプラインの構築は促進されないだろう.例えば, Basic Usage セクションで与えられた例からアクターをpickleした場合, ConeSourcePolyDataMapper などはピクルスされません. Matrix4x4 のようなtvtkクラスの中には,より良いpickleを可能にする特別なコードを持っているものもあります.

ライブオブジェクトの状態を設定することもできます.通常, pickle.load は新しいオブジェクトを作成します.しかし, __setstate__ を直接使用することで,オブジェクトの state を更新するだけで済みます.例えば:

>>> p = tvtk.Property()
>>> p.interpolation = 'flat'
>>> d = p.__getstate__()
>>> del p
>>> p = Prop()
>>> p.__setstate__(d)

ここで, __setstate__ が呼ばれた後,オブジェクトの状態だけが更新されます.新しいオブジェクトは作成されません.

Docstrings

すべてのtvtkメソッドとtraitは,VTKのdocstringを使って文書化されています.クラス名とメソッド名は, Basic Usage セクションで述べられているように,適切に変更されます.これらのdocstringは自動的に生成されるので,多少の誤りがあるかもしれません.tvtkオブジェクトのすべてのメソッドは,docstring内のメソッドシグネチャ情報も提供します.

ユーザ定義コード

すべてのtvtkラッパークラスは自動的に生成されます.特定のクラスをカスタマイズして,デフォルトの代わりにそのクラスを使用したい場合があります.これを行う最も簡単な方法は, tvtk_classes.zip ファイルから関連するクラスをコピーし,それを適切に変更し(もちろんファイル名やクラス名は変更せずに),そしてこのファイルを tvtk/custom ディレクトリに追加することです.ここにあるファイルは,ZIPファイル内のデフォルトをオーバーライドします.

Collections

Collection (例: vtkCollection)から派生したオブジェクトは,適切なPythonシーケンスのように動作します.次に例を示します.

>>> ac = tvtk.ActorCollection()
>>> print(len(ac))
0
>>> ac.append(tvtk.Actor())
>>> print(len(ac))
1
>>> for i in ac:
...    print(i)
...
[...]
>>> ac[-1] = tvtk.Actor()
>>> del ac[0]
>>> print(len(ac))
0

現在, Collection のサブクラスだけがこのように振る舞います.

配列の処理

すべての DataArray サブクラスはPython配列のように振る舞い, __getitem____setitem____repr__appendextend などに加えて反復プロトコルをサポートします.さらに,配列の値をnumpy配列かPythonリスト( from_array メソッドの使用)のいずれかを使って設定することができます.配列に格納されたデータを数値配列にすることもできます( to_array メソッドの使用).同様に, Points クラスと IdList クラスもこれらの機能をサポートしています. CellArray クラスは from_array および to_array メソッドのみを提供し,直列型プロトコルは提供しません.これは,ラップされた vtkCellArray クラスの特性によるものです.

非常に便利な機能の1つは, DataArrayPointsIdList ,または CellArray インスタンスを受け入れるほとんどすべてのtvtkメソッド/プロパティが,多数の配列またはPythonリストを透過的に受け入れることです.次に,これらを示す簡単な例を示します.

>>> ########################################
>>> from tvtk.api import tvtk
>>> import numpy as np
>>> data = np.array([[0,0,0,10], [1,0,0,20],
...                      [0,1,0,20], [0,0,1,30]], 'f')
>>> triangles = np.array([[0,1,3], [0,3,2],
...                            [1,2,3], [0,2,1]])
>>> points = data[:,:3]
>>> temperature = data[:,-1]
>>> mesh = tvtk.PolyData()
>>> mesh.points = points
>>> mesh.polys = triangles
>>> mesh.point_data.scalars = temperature

>>> ########################################
>>> # Array's are Pythonic.
>>> import operator
>>> reduce(operator.add, mesh.point_data.scalars, 0.0)
80.0
>>> print(mesh.point_data.scalars)
[10.0, 20.0, 20.0, 30.0]
>>> print(mesh.points)
[(0.0, 0.0, 0.0), (1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)]

>>> ########################################
>>> # Demo of from_array/to_array
>>> pts = tvtk.Points()
>>> pts.from_array(points)
>>> print(pts.to_array())
[[ 0.  0.  0.]
 [ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]

このように, DataArrayPoints ,または CellArray インスタンスを作成する必要はありません.Pythonタプルは暗黙的に変換され ない ことに注意してください.渡されたアレイからVTKアレイへの変換は,透過的かつ非常に効率的に処理されます.この唯一の例外は,変換が非効率的な IdList クラスです.ただし, IdList クラスは一般的には使用されません.

CellArray は,ポリゴンデータの接続リストを指定するために使用され,いくつかの特殊性があります. CellArray は,セル接続リストを使用して初期化する必要があります.これは,いくつかの方法のいずれかで指定できます.

  1. 1 DリストのPythonリスト.各1 Dリストには,1つのセル接続リストを含めることができます.これは非常に遅く,効率性に問題がない場合にのみ使用します.
  2. セル接続リストを持つ2 D数値配列.
  3. 2 D数値配列のPythonリスト.各数値配列は異なる形を持つことができます.これにより,異なる種類のセルを有するセル配列を容易に生成することができます.

この変換は,渡された数値配列の型コードが tvtk.array_handler.ID_TYPE_CODE の場合に最も効率的です.それ以外の場合は型キャストが必要で,これには余分なコピーが必要になります.変換中は,入力データは 常にコピー されます.次に,これらのさまざまなアプローチを説明する例を示します.

>>> a = [[0], [1, 2], [3, 4, 5], [6, 7, 8, 9]]
>>> cells = tvtk.CellArray()
>>> cells.from_array(a)
>>> a = np.array([[0,1,2], [3,4,5], [6,7,8]], int)
>>> cells.from_array(a)
>>> l_a = [a[:,:1], a[:2,:2], a]
>>> cells.from_array(a)

セルごとに異なるポイント数を持つ任意の接続リストを使用する別の方法は,次の方法を使用することです.

>>> ids = np.array([3, 0,1,3,
...                 3, 0,3,2,
...                 3, 1,2,3,
...                 3, 0,2,1])
>>> # The list is of form [npts,p0,p1,...p(npts-1), ...]
>>> n_cell = 4
>>> cells = tvtk.CellArray()
>>> cells.set_cells(n_cell, ids)
>>> print(cells.data)
[3.0, ..., 1.0], length = 16

これは非常に効率的に行われ,入力データをコピーしません.詳細については,次のサブセクションで説明します.

また, DataArray オブジェクトは以前と同様にこれらのメソッドに渡すことができることに注意してください.たとえば,これも同じくらい簡単にできます.

>>> points = tvtk.Points()
>>> points.from_array(data[:,:3])
>>> temperature = tvtk.FloatArray()
>>> temperature.from_array(data[:,-1])
>>> cells = tvtk.CellArray()
>>> cells.set_cells(n_cell, ids)
>>> mesh = tvtk.PolyData()
>>> mesh.points = points
>>> mesh.polys = cells
>>> mesh.point_data.scalars = temperature

重要な考慮事項

次に説明する内容を明確にするために,2つの異なる形式の配列処理を区別します.

  1. 明示的な変換 -- これは,ユーザがtvtk配列オブジェクトを作成していて,これを数値配列またはPythonリストから初期化するときに発生します.以下のようになります:

    >>> f = tvtk.FloatArray()
    >>> a = np.array([1,2,3], int)
    >>> f.from_array(a)
    
  2. 暗黙的変換 -- これは, DataArrayPointsIdList ,または CellArray インスタンスを想定しているtvtkメソッドに配列またはリストを渡すときに発生します.

tvtkの配列処理機能を使用する際に注意すべき点がいくつかあります.可能な場合,tvtkは渡されたnumpy配列のビューを使用し,そこに格納されているデータのコピーを作成しません.つまり,VTKデータ配列またはnumpy配列への変更は,もう一方の配列にも反映されます.例:

>>> f = tvtk.FloatArray()
>>> a = np.array([1,2,3], 'f')
>>> f.from_array(a)
>>> a[0] = 10.0
>>> print(f)
[10.0, 2.0, 3.0]
>>> f[0] = -1.0
>>> print(a)
[-1.  2.  3.]

注意すべき重要な点は,numpy配列への参照を削除してもまったく安全だということです.なぜなら,この配列は実際には安全にキャッシュされ,厄介な問題を回避できるからです.このメモリは,VTKアレイがガベージコレクションされると解放されます.numpy配列への参照を保存すると,numpy配列のサイズを変更できなくなります(これは破滅的な影響を及ぼす可能性がある).

しかし,numpy配列の "views" を使用するこの動作には例外があります. DataArray クラスとそのサブクラス,および Points クラスは,次の状況でのみ,指定されたデータのコピーを作成します.

  1. Pythonリストがデータとして与えられます.
  2. 連続しないnumpy配列が与えられます.
  3. 配列をVTK配列に変換する必要があるメソッドは, vtkBitArray インスタンスを想定しています.
  4. 予想されるVTK配列と渡されたnumpy配列の型は,互いに等価ではありません.例えば,渡された配列の型コードが 'i' で,tvtkメソッドが FloatArray を期待している場合です.

ほとんどのメソッドは特定のサブクラスではなく DataArray インスタンスを受け入れるため,ケース3および4が暗黙的な変換で発生することは非常にまれです.ただし,これらのケースは明示的な変換で発生する可能性があります.

CellArray常に アサインされたデータのコピーを作成します.例えば:

>>> ca = tvtk.CellArray()
>>> triangles = np.array([[0,1,3], [0,3,2],
...                       [1,2,3], [0,2,1]])
>>> ca.from_array(triangles)

これにより,常にコピーが作成されます.しかし,もし set_cells メソッドを使うなら, DataArrayPoints クラスに対して上で指定したのと同じ状況でコピーが作られます.コピーが作成されない場合,セルデータはnumpy配列の "view" になります.したがって,次の例ではコピーは作成されません.

>>> ids = np.array([3, 0,1,3,
...                 3, 0,3,2,
...                 3, 1,2,3,
...                 3, 0,2,1], int)
>>> ca.set_cells(4, ids)

idの値を変更したり,セルの数を変更することは推奨 されず ,未定義の動作になります.また,セル接続性データは,タイプコード tvtk.array_handler.ID_TYPE_CODE (これは実際にはVTKのビルドとプラットフォームに応じて動的に計算されます.)を有する配列で渡すのが最良であることに留意されたい.

IdList はまた,渡されたデータのコピーを 常に 作成します.

留意すべきもう1つの問題は,VTKのデータ配列がサイズ変更されると常にメモリーを再割り当てすることです.これを次の例に示します.

>>> d = tvtk.DoubleArray()
>>> a = np.array([1,2,3], 'd')
>>> d.from_array(a)
>>> a[0] = 10
>>> d.append(4.0)
>>> a[0] = 1
>>> print(a)
[ 1.   2.   3.]
>>> print(d)
[10.0, 2.0, 3.0, 4.0]
>>> # Notice that d[0] == 10.0

この場合, a はリサイズされませんが, d はリサイズされます.ここで, d は実際に a のコピーを作成し, d または a への変更は他方には反映されません.この事例は小さな問題も示している. da のメモリを一切使用しませんが, a への参照を内部的に保持します.幸い, d がガーベッジ・コレクションされると, a が占有していたメモリーが解放されます.したがって,この問題は深刻ではありませんが,覚えておく価値はあるでしょう.

問題の概要

前のサブセクションの考察を要約するために,以下のことに留意さしてください.

  1. ほとんどの場合, DataArrayPoints オブジェクトは多くのデータのコピーを作りません.例外は上記のとおりです.つまり,tvtkオブジェクトまたは配列に対する変更は,もう一方に反映されます.
  2. 変換された配列オブジェクトへの参照を削除しても安全です.ただし,numpy配列のサイズは変更できません.
  3. CellArray は常に割り当て時にデータをコピーします.ただし, set_cells を使用した場合の動作は, DataArray オブジェクトの場合と同様です.この場合,接続IDとセル数を変更しないでください.また, CellArray の場合は, tvtk.array_handler.ID_TYPE_CODE のタイプコードを持つ多数の配列の形式でデータを渡すのが最適であることにも注意してください) .そうでなければ,型キャストのために余分なコピーが発生します.
  4. IdList は常にデータのコピーを作成します.このクラスはほとんど使用されません.
  5. tvtk配列オブジェクトは,サイズ変更時に 常に データをコピーします.これにより,状況によってはメモリ使用量が増加する可能性があります.ただし,これはメモリリークでは ありません

これらの機能の結果として,配列変換は速度とメモリの点で非常に効率的になります.

その他のユーティリティモジュール

tvtk パッケージには,他にもいくつかのユーティリティモジュールが付属しています.これらについては,以降のセクションで簡単に説明します.

その他

TVTKデータセットを指定してVTKデータファイルを書き出す必要がある場合. tvtk.api.write_data 機能が役に立つはずです.例:

>>> from tvtk.api import tvtk, write_data
>>> pd = tvtk.PolyData()
>>> # ...
>>> write_data(pd, 'file_name')

これは,ベース名が file_name のXMLファイルを書き出します. .vtk 拡張子を指定する場合は,次のようになります.

>>> write_data(pd, 'file_name.vtk')

古いスタイルのASCIIファイルを書き出します.詳細については,docstringを参照してください.

VTK-Pythonではいくつかの便利な色が定義されており,TVTKで使用できるようになっています.例:

>>> from tvtk.api import colors
>>> colors.alice_blue
(0.9412, 0.9725, 1.0)

これにより,色を名前で簡単に参照できます.

pipeline.browser

PipelineBrowser クラスは,VTKパイプラインのビューをツリーとして表します.任意のノードをダブルクリックすると,traitシートエディタでオブジェクトのプロパティを編集できます.traitパッケージの TreeEditor は,ビューを表すために使用されます.このパイプラインブラウザはMayaVi_の (1.x) パイプラインブラウザに似ていますが,MayaVi_のパイプラインブラウザよりも洗練されています.VTKパイプラインを変更すると,ほとんどの場合,ブラウザーは自動的に更新されます.表示されない場合は,任意のノードを右クリックして更新をクリックします.

ツリー内のオブジェクトを生成するアルゴリズムを変更できます.ユーザは TreeGenerator をサブクラス化して,代わりにそれを使うかもしれません.実装の詳細については,コードとdocstringを参照してください.

tools.ivtk

PythonインタプリタからVTK/TVTKを簡単に使用できるようにするユーティリティー・モジュール.モジュールは tvtk.scene モジュールを使用してwxPythonウィジェットを提供します.ivtkは基本的に,このシーンをオプションのPythonインタープリター(PyCrust経由)およびオプションのパイプラインブラウザービューとともに提供します.

スタンドアロンのアプリケーションでは,モジュールを実行するだけでよい. IPython (with-wthreadを指定した場合)でこれを使うためには, viewer() ヘルパー関数を使います.例:

>>> from tvtk.tools import ivtk
>>> from tvtk.api import tvtk
>>> # Create your actor ...
>>> a = tvtk.Actor()
>>> # Now create the viewer.
>>> v = ivtk.viewer()
>>> v.scene.add_actors(a)  # or v.scene.add_actor(a)

ivtkには,PyFaceまたはwxPythonから使用できるいくつかの便利なクラス -- IVTKIVTKWithCrustIVTKWithBrowser ,および IVTKWithCrustAndBrowser が用意されています.ivtkの使用例は examples/ivtk_example.py にもあります.

tools.mlab

Matlabのような3 D可視化機能を提供するモジュール.一般的なアイデアは,恥知らずにも Octaviz が提供する 高水準 API から盗用されています.いくつかのテストケースやデモもそこから翻訳されています!

ここで提供される実装はオブジェクト指向であり,各視覚化機能は特性を持つクラスとして実装されます.したがって,これらはそれぞれ設定可能です.各表示クラスは, (最終的には) MLabBaseから派生します.MLabBaseは,レンダウィンドウにアクターを追加または削除する役割を果たします.すべてのクラスで,RenderWindowが tvtk.scene.Scene インスタンス(この制約は後で必要に応じて緩和することができる)であることが必要です.

このモジュールは,次の幅広い機能クラスを提供します.

Figure
これは基本的に,レンダリングされるすべてのオブジェクトを管理します.Matlabのような環境でのフィギュアのように. figure と呼ばれる便利な関数を使用して,素敵なFigureインスタンスを作成することができます.
Glyphs
このクラスとそのサブクラスは,入力として指定された点にグリフを配置します.サブクラスは: Arrows, Cones, Cubes, Cylinders, Spheres, および Points です.
Line3
初期化時に指定した点の間に線分を描画します.
Outline
含まれるオブジェクトのアウトラインを描画します.
Title
図形全体のタイトルを描画します.
LUTBase
ルックアップテーブルとそのスカラバー (凡例) を管理します.これはLUTを必要とするすべてのクラスによってサブクラス化されます.
SurfRegular
MayaVi1の imv.surf に似た機能で,x (1 D) ,y (1 D) ,z (または呼び出し可能)配列が指定されたサーフェスをプロットします.
SurfRegularC
等高線もプリントされます.
TriMesh
三角形の接続性と点を指定して,それらのメッシュをプロットします.
FancyTriMesh
管と球体を使用してメッシュをプロットし,より華やかさを増します.
Mesh
numpy.mgrid から生成されたx, yとそれに付随するzを与えます.オプションのスカラーとともに.このクラスは,三角形の接続(x, yが numpy.mgrid のものであると仮定する)を構築し,メッシュを構築して表示します.
FancyMesh
メッシュに似ていますが,チューブと球体を使用してメッシュを表示します.
Surf
Meshと同様にサーフェスメッシュが生成されますが,メッシュはサーフェスとしてレンダリングされます.
Contour3
メッシュのコンターを表示します.
ImShow
イメージアクタを使用して,多数の配列をイメージデータとして表示できます.これはMayaVi1の mayavi.tools.imv.viewi にそっくりです.

これらすべての良い例を見るために,mlab.pyファイルの最後にある test_* 関数を見てください.次に,これらのテスト関数の一部を使用する簡単な例を示します.

>>> from tvtk.tools import mlab
>>> f = mlab.figure()
>>> mlab.test_surf(f) # Create a spherical harmonic.
>>> f.pop() # Remove it.
>>> mlab.test_molecule(f) # Show a caffeine molecule.
>>> f.renwin.reset_zoom() # Scale the view.
>>> f.pop() # Remove this.
>>> mlab.test_lines(f) # Show pretty lines.
>>> f.clear() # Remove all the stuff on screen.

mlab の使い方がいかに簡単かを示すために, test_surf 関数を以下に示します.

>>> # Create the spherical harmonic.
>>> from numpy import pi, cos, sin, mgrid
>>> dphi, dtheta = pi/250.0, pi/250.0
>>> [phi,theta] = mgrid[0:pi+dphi*1.5:dphi,0:2*pi+dtheta*1.5:dtheta]
>>> m0, m1, m2, m3, m4, m5, m6, m7 = 4, 3, 2, 3, 6, 2, 6, 4
>>> r = sin(m0*phi)**m1 + cos(m2*phi)**m3 + sin(m4*theta)**m5 + cos(m6*theta)**m7
>>> x = r*sin(phi)*cos(theta)
>>> y = r*cos(phi)
>>> z = r*sin(phi)*sin(theta)
>>> # Now show the surface.
>>> from tvtk.tools import mlab
>>> fig = mlab.figure()
>>> s = Surf(x, y, z, z)
>>> fig.add(s)

お気づきかもしれませんが,この例は Octaviz サイトからも翻訳されています.

plugins

TVTKには2つのEnvisageプラグインが付属しています.1つはTVTKシーン用で,もう1つはパイプラインブラウザ用です.

scene プラグインを使用すると,作業領域に新しいTVTKシーンを作成できます.これらはいくつでも作成できます.シーンのビューを設定するのに(ivtkのメニューのように)便利なメニューがあります.また,ビューをイメージに保存することもできます.プラグインには,ウィンドウの背景色などを設定するためのプリファレンスもいくつか用意されています.

browser プラグインは,Envisageウィンドウの左側にパイプラインブラウザを配置します.このブラウザは,作業領域へのシーン追加を聞くために接続されています.シーンを追加するたびに,ブラウザに最上位ノードとして表示されます.

これらのプラグインは,任意のEnvisageプラグインから使用できます.完全に機能する例を見るには, examples/plugin/ ディレクトリを見てください.この例では,Envisageのプラグインを使用してアプリケーションを作成する方法を示します.