Line type#

LineType is an enum that is passed as the line_type keyword argument to contour_generator() and is used to specify the format of data returned from calls to lines(). If not explicitly specified then the default is used for the requested algorithm name.

Supported enum members and the default vary by algorithm:

LineType

mpl2005

mpl2014

serial

threaded

Separate

Yes, default

Yes, default

SeparateCode

Yes, default

Yes, default

Yes

Yes

ChunkCombinedCode

Yes

Yes

ChunkCombinedOffset

Yes

Yes

ChunkCombinedNan

Yes

Yes

A string name can be used instead of the enum member so the following are equivalent:

>>> contour_generator(line_type="SeparateCode", ...)
>>> contour_generator(line_type=LineType.SeparateCode, ...)

Enum members are a combination of the following words:

  • Separate: each line is a separate array.

  • Combined: multiple lines are concatenated in the same array.

  • Chunk: each chunk is separate, and is None if the chunk has no lines.

  • Code: includes Matplotlib kind codes for the previous line array.

  • Offset: individual lines are identified via offsets into the previous line array.

  • Nan: individual lines are separated by NaN (Not a Number).

The format of data returned by lines() for each of the possible LineType members is best illustrated through an example.

../../_images/line_type_0.svg../../_images/line_type_1.svg

For the z values shown in green text, two contour lines are returned at z=2:

  • A closed line loop that is entirely within the domain and consists of 5 points, the last point is the same as the first.

  • An open line strip that starts and ends on boundaries of the domain and consists of 2 points.

Note

Contour line segments are directed with higher z on the left, hence closed line loops are oriented anticlockwise if they enclose a region that is higher then the contour level, or clockwise if they enclose a region that is lower than the contour level. This assumes a right-hand coordinate system.

First set up the imports, define the z array and limit NumPy printing to 2 decimal places:

>>> from contourpy import contour_generator, LineType
>>> import numpy as np
>>> np.set_printoptions(precision=2)
>>> z = [[1.4, 1.2, 0.9, 0], [0.6, 3, 0.4, 0.7], [0.2, 0.2, 0.5, 3]]

Separate#

>>> cont_gen = contour_generator(z=z, line_type=LineType.Separate)
>>> lines = cont_gen.lines(2)
>>> lines
[array([[0.58, 1.], [1., 0.44], [1.38, 1.], [1., 1.36], [0.58, 1.]]),
 array([[2.6, 2.], [3., 1.57]])]

This returns a list of arrays, each array is the 2D points of a single line loop or strip. The number of lines is len(lines) and the points of line i are lines[i].

SeparateCode#

>>> cont_gen = contour_generator(z=z, line_type=LineType.SeparateCode)
>>> lines = cont_gen.lines(2)
>>> lines
([array([[0.58, 1.], [1., 0.44], [1.38, 1.], [1., 1.36], [0.58, 1.]]),
  array([[2.6, 2.], [3., 1.57]])],
 [array([1, 2, 2, 2, 79], dtype=uint8),
  array([1, 2], dtype=uint8)])

This returns a tuple of two lists, each list has a length equal to the number of lines. The first list is the same as for LineType.Separate. The second list is of 1D np.uint8 arrays containing the Matplotlib kind codes (1 = start new line loop or strip, 2 = move to point, 79 = close line loop). For line i the points are lines[0][i] and the kind codes are lines[1][i].

ChunkCombinedCode#

>>> cont_gen = contour_generator(z=z, line_type=LineType.ChunkCombinedCode)
>>> lines = cont_gen.lines(2)
>>> lines
([array([[0.58, 1.], [1., 0.44], [1.38, 1.], [1., 1.36], [0.58, 1.], [2.6, 2.], [3., 1.57]])],
 [array([1, 2, 2, 2, 79, 1, 2], dtype=uint8)])

This returns a tuple of two lists, each list has a length equal to the number of chunks used which is one here. The first list contains a 2D np.float64 array for each chunk containing the combined points for all lines in that chunk, and the second list contains a 1D np.uint8 array for each chunk containing the combined Matplotlib kind codes for all lines in that chunk.

For chunk j the combined points are lines[0][j] and the combined codes are lines[1][j]. An empty chunk has None for each. The start of each line loop/strip is identified by a kind code of 1.

ChunkCombinedOffset#

>>> cont_gen = contour_generator(z=z, line_type=LineType.ChunkCombinedOffset)
>>> lines = cont_gen.lines(2)
>>> lines
([array([[0.58, 1.], [1., 0.44], [1.38, 1.], [1., 1.36], [0.58, 1.], [2.6, 2.], [3., 1.57]])],
 [array([0, 5, 7], dtype=uint32)])

This returns a tuple of two lists, each list has a length equal to the number of chunks used which is one here. The first list contains a 2D np.float64 array for each chunk containing the combined points for all lines in that chunk, and the second list contains a 1D np.uint32 array for each chunk containing the start and end offsets of lines in that chunk’s point array.

For chunk j the combined points are lines[0][j] and the combined offsets are lines[1][j]. An empty chunk has None for each. In this example the first line corresponds to point indices 0:5 and the second to 5:7. The length of the offset array is one more than the number of lines.

ChunkCombinedNan#

>>> cont_gen = contour_generator(z=z, line_type=LineType.ChunkCombinedNan)
>>> lines = cont_gen.lines(2)
>>> lines
([array([[0.58, 1.], [1., 0.44], [1.38, 1.], [1., 1.36], [0.58, 1.], [nan, nan], [2.6, 2.], [3., 1.57]])])

This returns a tuple of a single list. The list contains a 2D np.float64 array for each chunk containing the combined points for all lines in that chunk, with numpy.nan used as separators between adjacent lines. A tuple is used here for consistency with all of the other ChunkCombined line types.

For chunk j the combined nan-separated points are in lines[0][j]. An empty chunk has None instead.

This is the line type used internally by Bokeh and HoloViews.

How to choose which line type to use#

  1. Do you need Matplotlib kind codes?

  2. Do you want each line’s points in a separate array or combined together?

The second question is one of convenience and performance. It is often more convenient to deal with a single array of points per line, but it is slower to do this as more arrays have to be created. The difference may only be significant for scenarios that generate many contour lines. See Benchmarks.

The decision also depends on how the line data is to be used. The performance advantage of combined arrays is usually wasted if the lines have to separated out into their own arrays for subsequent analysis.

Note

The order of lines returned by a particular lines() call is deterministic except for the combination of name="threaded" and either line_type=LineType.Separate or line_type=LineType.SeparateCode. This is because the order that the chunks are processed in is not deterministic and lines are appended to the returned arrays as soon as their chunks are completed.