Source code for paraview.lookuptable

# SPDX-FileCopyrightText: Copyright (c) Kitware Inc.
# SPDX-License-Identifier: BSD-3-Clause

r"""Utility module for easy manipultions of lookup tables.
This module is intended for use with by simple.py.


PARAVIEW_DEPRECATED_IN_5_12_0: will be removed in future releases of ParaView.
"""
from __future__ import absolute_import
import os
from math import sqrt

from . import servermanager
from ._colorMaps import getColorMaps


# -----------------------------------------------------------------------------

class _vtkPVLUTData:
    """
    Internal container for ParaView lookup table data.
    Don't use this directly. Use vtkPVLUTReader.
    """

    def __init__(self):
        self.Name = ""
        self.Space = ""
        self.Values = []
        self.Coords = []

    def SetName(self, aName):
        self.Name = aName

    def GetName(self):
        return self.Name

    def SetColorSpace(self, aSpace):
        self.Space = aSpace

    def GetColorSpace(self):
        return self.Space

    def SetRGBValues(self, aValues):
        self.Values = aValues

    def GetRGBValues(self):
        return self.Values

    def SetMapCoordinates(self, aCoords):
        self.Coords = aCoords
        # normalize the coordinates
        # in preparation to map onto
        # an arbitrary scalar range
        nCoords = len(self.Coords)
        minCoord = float(min(self.Coords))
        maxCoord = float(max(self.Coords))
        deltaCoord = maxCoord - minCoord
        if (minCoord >= maxCoord):
            print('ERROR: in coordinate values')
            return
        i = 0
        while i < nCoords:
            self.Coords[i] -= minCoord
            self.Coords[i] /= deltaCoord
            i += 1
        return

    def GetMapCoordinates(self):
        return self.Coords;

    def PrintSelf(self):
        print(self.Name)
        print(self.Space)
        print(self.Values)
        print(self.Coords)


# -----------------------------------------------------------------------------

[docs]class vtkPVLUTReader: """ Reader and container for ParaView's XML based lookup tables. Once lookup tables are loaded you access them by name. When accessing you must provide the array instance, which you may get from a pvpython 'Source' type object. This reader makes use of ParaView's XML LUT file format with one exception - the XML document must be root'ed by an element named "ColorMaps". Within the "ColorMaps" element an arbitrary number of ParaView's "ColorMap" elements define LUT entries. Usage: :: # at the top of your script # create the reader and load LUT's lr = lookuptable.vtkPVLUTReader() lr.Read('/path/to/luts.xml') lr.Print() # after you have a pvpython source object, get # one of it's arrays. srcObj = GetActiveSource() array = srcObj.PointData.GetArray('arrayName') # create a LUT for the array. lut = lr.GetLUT(array,'lutName') # set the active array and assign the LUT srcObjRep = Show(srcObj) srcObjRep.ColorArrayName = 'arrayName' srcObjRep.LookupTable = lut # finally render to display the result Render() File Format: :: <ColorMaps> ... <ColorMap name="LUTName" space="Lab,RGB,HSV" indexedLookup="true,false"> <Point x="val" o="val" r="val" g="val" b="val"/> ... <Point x="val" o="val" r="val" g="val" b="val"/> <NaN r="val" g="val" b="val"/> </ColorMap> ... <ColorMap> ... </ColorMap> ... </ColorMaps> """ def __init__(self, ns=None): import warnings warnings.warn("'vtkPVLUTReader' is deprecated.", DeprecationWarning) self.LUTS = {} self.DefaultLUT = None self.Globals = ns defaultColorMaps = getColorMaps() if defaultColorMaps: self._Read(defaultColorMaps) else: print('WARNING: default LUTs not found.') return
[docs] def Clear(self): """ Clear internal data structures. """ self.LUTS = {} self.DefaultLUT = None return
[docs] def Read(self, aFileName): """ Read in the LUT's defined in the named file. Each call to read extends the internal list of LUTs. """ parser = servermanager.vtkPVXMLParser() parser.SetFileName(aFileName) if (not parser.Parse()): print('ERROR: parsing lut file %s' % (aFileName)) return root = parser.GetRootElement() if root.GetName() != 'ColorMaps': print('ERROR: parsing LUT file %s' % (aFileName)) print('ERROR: root element must be <ColorMaps>') return return self._Read(root)
def _Read(self, root): nElems = root.GetNumberOfNestedElements() i = 0 nFound = 0 while (i < nElems): cmapElem = root.GetNestedElement(i) if (cmapElem.GetName() == 'ColorMap'): nFound += 1 lut = _vtkPVLUTData() lut.SetName(cmapElem.GetAttribute('name')) lut.SetColorSpace(cmapElem.GetAttribute('space')) coords = [] values = [] nRGB = cmapElem.GetNumberOfNestedElements() j = 0 while (j < nRGB): rgbElem = cmapElem.GetNestedElement(j) if (rgbElem.GetName() == 'Point'): coord = float(rgbElem.GetAttribute('x')) coords.append(coord) val = [float(rgbElem.GetAttribute('r')), float(rgbElem.GetAttribute('g')), float(rgbElem.GetAttribute('b'))] values.append(val) j = j + 1 lut.SetMapCoordinates(coords) lut.SetRGBValues(values) # lut.PrintSelf() self.LUTS[lut.GetName()] = lut i = i + 1 if nFound == 0: print('ERROR: No ColorMaps were found in %s' % (aFileName)) else: if self.DefaultLUT is None: names = list(self.LUTS) if len(names) > 0: self.DefaultLUT = names[0] return nFound
[docs] def GetLUT(self, aArray, aLutName, aRangeOveride=[]): """ Given an array and lookup table name assign the LUT to the given array and return the LUT. If aRangeOveride is specified then LUT will be mapped through that range rather than the array's actual range. """ try: self.LUTS[aLutName] except KeyError: if self.DefaultLUT is not None: print('ERROR: No LUT named %s using %s' % (aLutName, self.DefaultLUT)) aLutName = self.DefaultLUT else: print('ERROR: No LUT named %s and no default available.' % (aLutName)) return None range = self.__GetRange(aArray, aRangeOveride) return self.__GetLookupTableForArray(aArray, RGBPoints=self.__MapRGB(aLutName, range), ColorSpace=self.__GetColorSpace(aLutName), VectorMode='Magnitude', ScalarRangeInitialized=1.0)
[docs] def GetLUTNames(self): """ Return a list of the currently available LUT's names. """ return sorted(iter(self.LUTS), cmp=lambda x, y: cmp(x.lower(), y.lower()))
[docs] def Print(self): """ Print the available list of LUT's. """ names = "" i = 0 for k in sorted(iter(self.LUTS), cmp=lambda x, y: cmp(x.lower(), y.lower())): lut = self.LUTS[k] names += lut.GetName() names += ", " if ((i % 6) == 5): names += "\n" i += 1 print(names) return
# end of public interface def __GetColorSpace(self, aName): """ Return the color space from the lookup table object. """ return self.LUTS[aName].GetColorSpace() def __GetRGB(self, aName): """ Return the rgb values for the named lut """ return self.LUTS[aName] def __MapRGB(self, aName, aRange): """ Map the rgb values onto a scalar range results are an array of [x r g b] values """ colors = self.LUTS[aName].GetRGBValues() mapCoords = self.LUTS[aName].GetMapCoordinates() nColors = len(colors) coord0 = float(aRange[0]) coordDelta = float(aRange[1]) - float(aRange[0]) mappedColors = [] i = 0 while (i < nColors): x = coord0 + coordDelta * mapCoords[i] val = [x] + colors[i] mappedColors += val i = i + 1 return mappedColors def __GetRange(self, aArray, aRangeOveride): """ Get the range from an array proxy object or if an override is provided use that. """ nComps = aArray.GetNumberOfComponents() range = [0.0, 1.0] if (len(aRangeOveride) == 0): if (nComps == 1): range = aArray.GetRange() else: # TODO - this could be larger than the range of the magnitude aArray rx = aArray.GetRange(0) ry = aArray.GetRange(1) rz = aArray.GetRange(2) range = [0.0, sqrt(rx[1] * rx[1] + ry[1] * ry[1] + rz[1] * rz[1])] else: range = aRangeOveride return range def __GetLookupTableForArray(self, aArray, **kwargs): """ Set the lookup table for the given array and assign the named properties. """ proxyName = '%d.%s.PVLookupTable' % (aArray.GetNumberOfComponents(), aArray.GetName()) lut = servermanager.ProxyManager().GetProxy('lookup_tables', proxyName) if not lut: lut = servermanager.rendering.PVLookupTable(ColorSpace="HSV", RGBPoints=[0, 0, 0, 1, 1, 1, 0, 0]) servermanager.Register(lut, registrationName=proxyName) for arg in kwargs.keys(): if not hasattr(lut, arg): raise AttributeError("LUT has no property %s" % (arg)) setattr(lut, arg, kwargs[arg]) return lut