1
.. _creating-data-for-mayavi:
1
.. _data-structures-used-by-mayavi:
3
Creating data for Mayavi
4
========================
3
Data structures used by Mayavi
4
==============================
6
6
Describing data in three dimension in the general case is a complex
7
7
problem. Mayavi helps you focus on your visualization work and not worry
8
8
too much about the underlying data structures, for instance using mlab
9
(see :ref:`simple-scripting-with-mlab`). However, if you want to create
10
data for a more efficient visualization, it helps to understand the VTK
11
data structures that Mayavi uses.
9
(see :ref:`simple-scripting-with-mlab`). We suggest you create sources
10
for Mayavi using `mlab` or Mayavi sources when possible. However, if you
11
want to create data with a very specific structure for a more efficient
12
visualization, it helps to understand the VTK data structures that Mayavi
13
15
VTK data structures
14
16
--------------------
18
Mayavi uses the VTK library for all its visualization needs. The data is
19
exposed internally, by the sources, or at the output of the filters, as
20
VTK datasets, described below. Understanding these structures is useful
21
not only to manipulate them, but also to understand what happens when
22
using filters to transform the data in the pipeline.
24
Caracteristics of a dataset
25
.............................
27
A dataset is defined by many different characteristics:
29
.. image:: images/dataset_diagram/dataset_diagram.jpg
33
Connectivity is not only necessary to draw lines between the
34
different points, it is also needed to define a volume.
36
**Implicit connectivity**: connectivity or positioning is implicit. In
37
this case the data is considered as arranged on a lattice-like structure,
38
with equal number of layers in each direction, x increasing first along
39
the array, then y and finally z.
43
Dataset are made of points positioned in 3D, with the corresponding
44
data. Each dataset can carry several data components.
46
**Scalar or Vectors data**: The data can be scalar, in which case VTK
47
can perform operations such as taking the gradient and display the
48
data with a colormap, or vector, in which case VTK can perform an
49
integration to display streamlines, display the vectors, or extract the
50
norm of the vectors, to create a scalar dataset.
52
**Cell data and point data**: Each VTK dataset is defined by vertices and
53
cells, explicitly or implicitly. The data, scalar or vector, can be
54
positioned either on the vertices, in which case it is called point data,
55
or associated with a cell, in which case it is called cell data.
56
Point data is stored in the `.point_data` attribute of the dataset,
57
and the cell data is stored in the `.cell_data` attribute.
59
In addition the data arrays have an associated name, which is used in
60
Mayavi to specify on which data component module or filter apply (eg
61
using the`SetActiveAttribute` filter.
63
All VTK arrays, whether it be for data or position, are exposed as (n, 3)
64
numpy arrays for 3D components, and flat (n, ) array for 1D components.
65
The index vary in the opposite order as numpy: z first, y and then x.
66
Thus to go from a 3D numpy array to the corresponding flatten VTK array,
69
vtk_array = numpy_array.T.ravel()
71
Description of the different datasets
72
......................................
16
74
The 5 VTK structures used are the following (ordered by the cost of
17
75
visualizing them).:
26
84
UnstructuredGrid Explicit Volumes and surfaces x, y, z positions of vertices and arrays of volume Cells
27
85
================== ============= =========================== ============================================================
29
**Implicit connectivity**: connectivity or positioning is implicit. In
30
this case the data is considered as arranged on a lattice-like structure,
31
with equal number of layers in each direction, x increasing first along
32
the array, then y and finally z.
34
**Cell data and point data**: Each VTK dataset is defined by vertices and
35
cells, explicitly or implicitly. The data, scalar or vector, can be
36
positioned either on the vertices, in which case it is called point data,
37
or associated with a cell, in which case it is called cell data.
40
**Description of the datasets**:
43
89
This dataset is made of data points positioned on an orthogonal grid,
44
90
with constant spacing along each axis. The position of the data points
45
91
are inferred from their position on the data array (implicit
46
92
positioning), an origin and a spacing between 2 slices along each axis.
47
In 2D, this can be understood as a raster image.
93
In 2D, this can be understood as a raster image. This is the data
94
structure created by the `ArraySource` mayavi source, from a 3D numpy
95
array, as well as the `mlab.pipeline.scalar_field` and
96
`mlab.pipeline.vector_field` factory functions, if the `x`, `y` and
97
`z` arrays are not explicitely specified.
49
99
.. image:: image_data.png
101
Creating a `tvtk.ImageData` object from numpy arrays::
103
from enthought.tvtk.api import tvtk
104
from numpy import random
105
data = random.random((3, 3, 3))
106
i = tvtk.ImageData(spacing=(1, 1, 1), origin=(0, 0, 0))
107
i.point_data.scalars = data.ravel()
108
i.point_data.scalars.name = 'scalars'
109
i.dimensions = data.shape
52
113
This dataset is made of data points positioned on an orthogonal grid,
53
114
with arbitrary spacing along the various axis. The position of the data
57
118
.. image:: rectilinear_grid.png
120
Creating a `tvtk.RectilinearGrid` object from numpy arrays::
122
from enthought.tvtk.api import tvtk
123
from numpy import random, array
124
data = random.random((3, 3, 3))
125
r = tvtk.RectilinearGrid()
126
r.point_data.scalars = data.ravel()
127
r.point_data.scalars.name = 'scalars'
128
r.dimensions = data.shape
129
r.x_coordinates = array((0, 0.7, 1.4))
130
r.y_coordinates = array((0, 1, 3))
131
r.z_coordinates = array((0, .5, 2))
60
135
This dataset is made of data points positioned on arbitrary grid: each
61
136
point is connected to its nearest neighbors on the data array. The
62
137
position of the data points are fully described by 1 coordinate
63
arrays, specifying x, y and z for each point.
138
arrays, specifying x, y and z for each point. This is the dataset
139
created by the `mlab.pipeline.scalar_field` and
140
`mlab.pipeline.vector_field` factory functions, if the `x`, `y` and
141
`z` arrays are explicitely specified.
65
144
.. image:: structured_grid.png
146
Creating a `tvtk.StructuredGrid` object from numpy arrays::
148
from numpy import pi, cos, sin, empty, linspace, random
149
from enthought.tvtk.api import tvtk
151
def generate_annulus(r, theta, z):
152
""" Generate points for structured grid for a cylindrical annular
153
volume. This method is useful for generating a unstructured
154
cylindrical mesh for VTK.
156
# Find the x values and y values for each plane.
157
x_plane = (cos(theta)*r[:,None]).ravel()
158
y_plane = (sin(theta)*r[:,None]).ravel()
160
# Allocate an array for all the points. We'll have len(x_plane)
161
# points on each plane, and we have a plane for each z value, so
162
# we need len(x_plane)*len(z) points.
163
points = empty([len(x_plane)*len(z),3])
165
# Loop through the points for each plane and fill them with the
166
# correct x,y,z values.
169
end = start+len(x_plane)
170
# slice out a plane of the output points and fill it
171
# with the x,y, and z values for this plane. The x,y
172
# values are the same for every plane. The z value
173
# is set to the current z
174
plane_points = points[start:end]
175
plane_points[:,0] = x_plane
176
plane_points[:,1] = y_plane
177
plane_points[:,2] = z_plane
183
r = linspace(5, 15, dims[0])
184
theta = linspace(0, 0.5*pi, dims[1])
185
z = linspace(0, 10, dims[2])
186
pts = generate_annulus(r, theta, z)
187
sgrid = tvtk.StructuredGrid(dimensions=(dims[1], dims[0], dims[2]))
189
s = random.random((dims[0]*dims[1]*dims[2]))
190
sgrid.point_data.scalars = ravel(s.copy())
191
sgrid.point_data.scalars.name = 'scalars'
68
197
This dataset is made of arbitrarily positioned data points that can
69
198
be connected to form lines, or grouped in polygons to from surfaces
70
199
(the polygons are broken up in triangles). Unlike the other datasets,
71
this one cannot be used to describe volumetric data.
200
this one cannot be used to describe volumetric data. The is the dataset
201
created by the `mlab.pipeline.scalar_scatter` and
202
`mlab.pipeline.vector_scatter` functions.
73
204
.. image:: poly_data.png
206
Creating a `tvtk.PolyData` object from numpy arrays::
208
from numpy import array, random
209
from enthought.tvtk.api import tvtk
211
# The numpy array data.
212
points = array([[0,-0.5,0], [1.5,0,0], [0,1,0], [0,0,0.5],
213
[-1,-1.5,0.1], [0,-1, 0.5], [-1, -0.5, 0],
215
triangles = array([[0,1,3], [1,2,3], [1,0,5],
216
[2,3,4], [3,0,4], [0,5,4], [2, 4, 6],
218
scalars = random.random(points.shape)
221
mesh = tvtk.PolyData(points=points, polys=triangles)
222
mesh.point_data.scalars = scalars
223
mesh.point_data.scalars.name = 'scalars'
75
226
:UnstructuredGrid:
76
227
This dataset is the most general dataset of all. It is made of data
77
228
points positioned arbitrarily. The connectivity between data points
82
233
.. image:: unstructured_grid.png
235
Creating a `tvtk.UnstructuredGrid` object from numpy arrays::
237
from numpy import array, random
238
from enthought.tvtk.api import tvtk
240
points = array([[0,1.2,0.6], [1,0,0], [0,1,0], [1,1,1], # tetra
241
[1,0,-0.5], [2,0,0], [2,1.5,0], [0,1,0],
242
[1,0,0], [1.5,-0.2,1], [1.6,1,1.5], [1,1,1], # Hex
245
cells = array([4, 0, 1, 2, 3, # tetra
246
8, 4, 5, 6, 7, 8, 9, 10, 11 # hex
248
# The offsets for the cells, i.e. the indices where the cells
250
offset = array([0, 5])
251
tetra_type = tvtk.Tetra().cell_type # VTK_TETRA == 10
252
hex_type = tvtk.Hexahedron().cell_type # VTK_HEXAHEDRON == 12
253
cell_types = array([tetra_type, hex_type])
254
# Create the array of cells unambiguously.
255
cell_array = tvtk.CellArray()
256
cell_array.set_cells(2, cells)
258
ug = tvtk.UnstructuredGrid(points=points)
259
# Now just set the cell types and reuse the ug locations and cells.
260
ug.set_cells(cell_types, offset, cell_array)
261
scalars = random.random(points.shape[0])
262
ug.point_data.scalars = scalars
263
ug.point_data.scalars.name = 'scalars'
84
267
External references
85
268
--------------------
153
337
Add content here from the presentations.
339
Inserting TVTK datasets in the Mayavi pipeline.
340
-----------------------------------------------
342
TVTK datasets can be created using directly TVTK, as illustrated in the
343
examples above. A VTK data source can be inserted in the Mayavi pipeline
344
using the VTKDataSource. For instance we can create an `ImageData`
347
from enthought.tvtk.api import tvtk
349
a = np.random.random((10, 10, 10))
350
i = tvtk.ImageData(spacing=(1, 1, 1), origin=(0, 0, 0))
351
i.point_data.scalars = a.ravel()
352
i.point_data.scalars.name = 'scalars'
353
i.dimensions = a.shape
355
Inserting this dataset on the pipeline with `VTKDataSource` is done as
358
from enthought.mayavi.sources.api import VTKDataSource
359
src = VTKDataSource(data=i)
360
from enthought.mayavi.api import Engine
366
In addition, if you are scripting using `mlab`, the `mlab.pipeline`
367
factory functions creating filters and modules accept VTK datasets, in
368
which case they are automatically inserted on the pipeline. A surface
369
module could have been used to visualize the `ImageData` dataset as
372
from enthgouth.mayavi import mlab
373
mlab.pipeline.surface(i)
375
Of course, unless you want specific control on the attributes of the VTK
376
dataset, or you are using Mayavi in the context of existing code
377
manipulating TVTK objects, creating an `ImageData` TVTK object is not
378
advised. The `ArraySource` Mayavi will actually create an `ImageData`,
379
but make sure you don't get the shape wrong, which can lead to a
380
segmentation fault. An even easier way to create a data source for an
381
`ImageData` is to use the `mlab.pipeline.scalar_field` function.