download as script · edit page

A single EBSD measurement has several addresses. It has a position in a list, an id inherited from its parent map, and a position on the specimen. On a gridded map it also has a row and column. A hexagonal grid offers cube coordinates as a fifth address. They simplify neighbour-based algorithms.

These addresses answer different questions and stop agreeing as soon as measurements are selected or rearranged. This page keeps them apart. See Selecting EBSD Data for phase, property, and region selections. Square and Hex Grids gives the complete gridding model.

import matplotlib.pyplot as plt
import numpy as np
from mtex import *
plottingConvention.default('y↑→x')
ebsd = mtexdata('twins')
ebsd
EBSD (y↑→x)
  size: 137 × 167 grid
  Phase  Orientations  Mineral     Color         Symmetry  Crystal reference frame
  0      46 (0.2%)     notIndexed
  1      22833 (100%)  Magnesium   LightSkyBlue  6/mmm     Magnesium
  properties    : bands, bc, bs, error, mad
  scan unit     : um
  X × Y         : [0 → 49.8] × [0 → 40.8]
  square lattice: spacing 0.3

List position

The summary above identifies the imported map as a square grid. It is already stored as a matrix. Restricting it to a small rectangle returns a plain list. An arbitrary selection is not generally rectangular.

poly = [44, 0, 4, 2]
ebsd = ebsd[inpolygon(ebsd, poly)]
ebsd
EBSD (y↑→x)
  size: 98
  Phase  Orientations  Mineral    Color         Symmetry  Crystal reference frame
  1      98 (100%)     Magnesium  LightSkyBlue  6/mmm     Magnesium
  properties    : bands, bc, bs, error, mad
  scan unit     : um
  X × Y         : [44.1 → 48] × [0 → 1.8]
  square lattice: spacing 0.3

The summary reports 98 measurements. Each coloured square below is one entry in that list. Writing the list position into every square reveals the order in which the entries are stored.

plot(ebsd, ebsd.orientations, ipfDirection=zvector, micronbar=False, edgeColor='k', backend='patch')
text(ebsd, np.arange(len(ebsd)))

A single numeric subscript selects by list position, counted from zero. The red outline marks entries 15 to 17.

hold(True)
plot(ebsd[15:18], edgeColor='red', faceColor='none', lineWidth=4, backend='patch', legend=False)
hold(False)

This crop came from a gridded map and inherited its linear order. NumPy advances through every column of one matrix row before moving to the next row. Here that means visiting all x positions at one y position before moving to the next y position. A list imported without gridding instead follows the order in which its measurements were loaded.

Measurement id

Cropping changed every measurement’s position in the list. Entry 15 of the crop was not entry 15 of the full map. Its identifier in that parent map is stored in ebsd.id.

plot(ebsd, ebsd.orientations, ipfDirection=zvector, micronbar=False, edgeColor='k', backend='patch')
text(ebsd, ebsd.id)

The key 'id' selects by those identifiers. It therefore highlights the same three measurements as the list-position selection above.

hold(True)
plot(ebsd['id', ebsd.id[15:18]], edgeColor='red', faceColor='none', lineWidth=4, backend='patch', legend=False)
hold(False)

Keep an id when a result from one selection must be matched to another selection from the same parent map. Selection preserves it. Gridding is a different operation. It may assign identifiers for the new raster and stores the input identifiers in oldId. An id is therefore not necessarily a line number in the imported file. See Square and Hex Grids.

Position on the specimen

The key 'xy' returns the measurement closest to a specimen position. Its output shows both the selected id and the actual coordinates.

ebsd['xy', 44.5, 1]
EBSD (y↑→x)
  size: 1
  Phase  Orientations  Mineral    Color         Symmetry  Crystal reference frame
  1      1 (100%)      Magnesium  LightSkyBlue  6/mmm     Magnesium
   Id  Phase             orientation  bands   bc   bs  error  mad
  649      1  (176.5°,104.1°,182.9°)     10  139  245      0  0.5
  scan unit     : um
  X × Y         : [44.4 → 44.4] × [0.9 → 0.9]
  square lattice: spacing 0.3

The expression ebsd[x, y] does not perform that lookup on a plain list; it is an error. On a gridded map the same expression means the pixel in row x and column y. Requiring 'xy' prevents one line from changing meaning when a map changes between list and matrix storage.

Square-grid subscripts

Although the crop is a list, its measurements lie on a regular grid. gridify restores the matrix shape. The shape confirms that this crop has 7 rows and 14 columns.

ebsd = ebsd.gridify()
ebsd.shape
(7, 14)

The labels now show (row, column) rather than a single linear index.

plot(ebsd, ebsd.orientations, ipfDirection=zvector, micronbar=False, edgeColor='black', backend='patch')

i, j = np.indices(ebsd.shape)
labels = [f'({a},{b})' for a, b in zip(i.ravel(), j.ravel())]
text(ebsd, labels)

Two subscripts select by row and column. Ranges select a whole row or a rectangular block; the red outline marks columns 1 to 3 of row 1.

hold(True)
plot(ebsd[1, 1:4], edgeColor='red', faceColor='none', lineWidth=4, backend='patch', legend=False)
hold(False)

gridify is allowed to reorder a plain list so that dimension 0 follows increasing specimen y and dimension 1 increasing x. This crop is a special case: it already inherited that order from the full gridded map, so its sequence does not change. For a general list, use oldId, which relates input order to raster order. Square and Hex Grids works through that translation.

Hexagonal grids

The same distinction between linear index, id, specimen position, and matrix subscripts applies to a hexagonal measurement grid. The summary below identifies this map as a hexagonal grid. It is stored as a matrix from the start.

plottingConvention.default('y↓→x')
ebsd = mtexdata('titanium')
ebsd
EBSD (y↓→x)
  size: 97 × 84 grid
  Phase  Orientations  Mineral           Color         Symmetry  Crystal reference frame
  1      8100 (100%)   Titanium (Alpha)  LightSkyBlue  622       Titanium (Alpha)
  properties : ci, grainid, iq, sem_signal
  scan unit  : um
  X × Y      : [0 → 996] × [0 → 997.7]
  hex lattice: spacing 12

Row and column indexing works as in the square case. We retain a small block so that its subscripts remain legible.

ebsd = ebsd[9:16, 67:79]

plot(ebsd, ebsd.orientations, ipfDirection=zvector, edgeColor='k', micronbar=False, backend='patch')
plt.axis('off')

i, j = np.indices(ebsd.shape)
labels = [f'({a},{b})' for a, b in zip(i.ravel(), j.ravel())]
text(ebsd, labels)

The labels show that rows are horizontal lines of cells. Because alternate rows are offset, a matrix column follows a zigzag rather than a straight line on the specimen.

Cube coordinates

Offset rows make a neighbour step depend on whether the row is even or odd. Cube coordinates replace row and column by three redundant indices, making the six neighbour steps identical everywhere on the grid. They are cell addresses for algorithms, not specimen coordinates.

hex2cube and cube2hex convert between the two systems. Hexagonal Grids explains the geometric construction and further algorithms.

plot(ebsd, ebsd.orientations, ipfDirection=zvector, edgeColor='k', micronbar=False, backend='patch')
plt.axis('off')

x, y, z = ebsd.hex2cube(i, j)
labels = [f'({a},{b},{c})' for a, b, c in zip(*(np.rint(v).astype(int).ravel() for v in (x, y, z)))]
text(ebsd, labels, fontSize=6)

Every displayed triple satisfies \(x + y + z = 0\). A step to any of the six neighbours adds one to one coordinate and subtracts one from another, leaving the third unchanged.

Further reading

Indexing on ndarrays in the NumPy documentation explains linear and row-column indexing, including the row-major order used above.

I. Her, Geometric transformations on the hexagonal grid, IEEE Transactions on Image Processing 4(9), 1213–1222 (1995). The paper develops the symmetrical frame behind cube coordinates.

After grain reconstruction, Selecting Grains separates grain list positions, grain id values, and ebsd.grainId.

Citing this page. This page is part of the documentation of MTEX, a free and open source MATLAB toolbox for analyzing and modeling crystallographic textures. It was written by The MTEX Developers and is published at https://mtex-toolbox.github.io/EBSDIndex_py.html. If you use MTEX, or reuse text or figures from this page, in your research, please cite

F. Bachmann, R. Hielscher, H. Schaeben: Texture Analysis with MTEX - Free and Open Source Software Toolbox, Solid State Phenomena 160 (2010), 63-68. 10.4028/www.scientific.net/SSP.160.63

BibTeX
@article{bachmann2010mtex,
  author  = {F. Bachmann and R. Hielscher and H. Schaeben},
  title   = {Texture Analysis with MTEX - Free and Open Source Software Toolbox},
  journal = {Solid State Phenomena},
  volume  = {160},
  pages   = {63-68},
  year    = {2010},
  doi     = {10.4028/www.scientific.net/SSP.160.63},
  url     = {https://doi.org/10.4028/www.scientific.net/SSP.160.63}
}

Other papers describing specific MTEX methods are listed under Publications — please cite the one that best fits your application. The MTEX source code is licensed under the GNU General Public License v2.0; the text and figures of this documentation are licensed under CC BY 4.0, which permits reuse — including by automated systems — provided The MTEX Developers and this page are credited.