lookuptable.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. r"""Utility module for easy manipultions of lookup tables.
  2. This module is intended for use with by simple.py.
  3. DEPRECATED: will be removed in future releases of ParaView.
  4. """
  5. #==============================================================================
  6. #
  7. # Program: ParaView
  8. # Module: lookuptable.py
  9. #
  10. # Copyright (c) Kitware, Inc.
  11. # All rights reserved.
  12. # See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
  13. #
  14. # This software is distributed WITHOUT ANY WARRANTY; without even
  15. # the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  16. # PURPOSE. See the above copyright notice for more information.
  17. #
  18. #==============================================================================
  19. from __future__ import absolute_import
  20. import os
  21. from math import sqrt
  22. from . import servermanager
  23. from ._colorMaps import getColorMaps
  24. # -----------------------------------------------------------------------------
  25. class _vtkPVLUTData:
  26. """
  27. Internal container for ParaView lookup table data.
  28. Don't use this directly. Use vtkPVLUTReader.
  29. """
  30. def __init__(self):
  31. self.Name=""
  32. self.Space=""
  33. self.Values=[]
  34. self.Coords=[]
  35. def SetName(self,aName):
  36. self.Name=aName
  37. def GetName(self):
  38. return self.Name
  39. def SetColorSpace(self,aSpace):
  40. self.Space=aSpace
  41. def GetColorSpace(self):
  42. return self.Space
  43. def SetRGBValues(self,aValues):
  44. self.Values=aValues
  45. def GetRGBValues(self):
  46. return self.Values
  47. def SetMapCoordinates(self,aCoords):
  48. self.Coords=aCoords
  49. # normalize the coordinates
  50. # in preparation to map onto
  51. # an arbitrary scalar range
  52. nCoords = len(self.Coords)
  53. minCoord = float(min(self.Coords))
  54. maxCoord = float(max(self.Coords))
  55. deltaCoord = maxCoord - minCoord
  56. if (minCoord>=maxCoord):
  57. print ('ERROR: in coordinate values')
  58. return
  59. i=0
  60. while i<nCoords:
  61. self.Coords[i] -= minCoord
  62. self.Coords[i] /= deltaCoord
  63. i+=1
  64. return
  65. def GetMapCoordinates(self):
  66. return self.Coords;
  67. def PrintSelf(self):
  68. print (self.Name)
  69. print (self.Space)
  70. print (self.Values)
  71. print (self.Coords)
  72. # -----------------------------------------------------------------------------
  73. class vtkPVLUTReader:
  74. """
  75. Reader and container for ParaView's XML based lookup tables.
  76. Once lookup tables are loaded you access them by name. When
  77. accessing you must provide the array instance, which you may
  78. get from a pvpython 'Source' type object.
  79. This reader makes use of ParaView's XML LUT file format with
  80. one exception - the XML document must be root'ed by an element
  81. named "ColorMaps". Within the "ColorMaps" element an arbitrary
  82. number of ParaView's "ColorMap" elements define LUT entries.
  83. Usage:
  84. ::
  85. # at the top of your script
  86. # create the reader and load LUT's
  87. lr = lookuptable.vtkPVLUTReader()
  88. lr.Read('/path/to/luts.xml')
  89. lr.Print()
  90. # after you have a pvpython source object, get
  91. # one of it's arrays.
  92. srcObj = GetActiveSource()
  93. array = srcObj.PointData.GetArray('arrayName')
  94. # create a LUT for the array.
  95. lut = lr.GetLUT(array,'lutName')
  96. # set the active array and assign the LUT
  97. srcObjRep = Show(srcObj)
  98. srcObjRep.ColorArrayName = 'arrayName'
  99. srcObjRep.LookupTable = lut
  100. # finally render to display the result
  101. Render()
  102. File Format:
  103. ::
  104. <ColorMaps>
  105. ...
  106. <ColorMap name="LUTName" space="Lab,RGB,HSV" indexedLookup="true,false">
  107. <Point x="val" o="val" r="val" g="val" b="val"/>
  108. ...
  109. <Point x="val" o="val" r="val" g="val" b="val"/>
  110. <NaN r="val" g="val" b="val"/>
  111. </ColorMap>
  112. ...
  113. <ColorMap>
  114. ...
  115. </ColorMap>
  116. ...
  117. </ColorMaps>
  118. """
  119. def __init__(self,ns=None):
  120. self.LUTS={}
  121. self.DefaultLUT=None
  122. self.Globals=ns
  123. defaultColorMaps = getColorMaps()
  124. if defaultColorMaps:
  125. self._Read(defaultColorMaps)
  126. else:
  127. print('WARNING: default LUTs not found.')
  128. return
  129. def Clear(self):
  130. """
  131. Clear internal data structures.
  132. """
  133. self.LUTS={}
  134. self.DefaultLUT=None
  135. return
  136. def Read(self, aFileName):
  137. """
  138. Read in the LUT's defined in the named file. Each
  139. call to read extends the internal list of LUTs.
  140. """
  141. parser=servermanager.vtkPVXMLParser()
  142. parser.SetFileName(aFileName)
  143. if (not parser.Parse()):
  144. print ('ERROR: parsing lut file %s'%(aFileName))
  145. return
  146. root=parser.GetRootElement()
  147. if root.GetName()!='ColorMaps':
  148. print ('ERROR: parsing LUT file %s'%(aFileName))
  149. print ('ERROR: root element must be <ColorMaps>')
  150. return
  151. return self._Read(root)
  152. def _Read(self, root):
  153. nElems=root.GetNumberOfNestedElements()
  154. i=0
  155. nFound=0
  156. while (i<nElems):
  157. cmapElem=root.GetNestedElement(i)
  158. if (cmapElem.GetName()=='ColorMap'):
  159. nFound+=1
  160. lut=_vtkPVLUTData()
  161. lut.SetName(cmapElem.GetAttribute('name'))
  162. lut.SetColorSpace(cmapElem.GetAttribute('space'))
  163. coords=[]
  164. values=[]
  165. nRGB=cmapElem.GetNumberOfNestedElements()
  166. j=0
  167. while (j<nRGB):
  168. rgbElem=cmapElem.GetNestedElement(j)
  169. if (rgbElem.GetName()=='Point'):
  170. coord=float(rgbElem.GetAttribute('x'))
  171. coords.append(coord)
  172. val=[float(rgbElem.GetAttribute('r')),
  173. float(rgbElem.GetAttribute('g')),
  174. float(rgbElem.GetAttribute('b'))]
  175. values.append(val)
  176. j=j+1
  177. lut.SetMapCoordinates(coords)
  178. lut.SetRGBValues(values)
  179. #lut.PrintSelf()
  180. self.LUTS[lut.GetName()]=lut
  181. i=i+1
  182. if nFound==0:
  183. print ('ERROR: No ColorMaps were found in %s'%(aFileName))
  184. else:
  185. if self.DefaultLUT is None:
  186. names=list(self.LUTS)
  187. if len(names)>0:
  188. self.DefaultLUT=names[0]
  189. return nFound
  190. def GetLUT(self,aArray,aLutName,aRangeOveride=[]):
  191. """
  192. Given an array and lookup table name assign the LUT
  193. to the given array and return the LUT. If aRangeOveride
  194. is specified then LUT will be mapped through that
  195. range rather than the array's actual range.
  196. """
  197. try:
  198. self.LUTS[aLutName]
  199. except KeyError:
  200. if self.DefaultLUT is not None:
  201. print ('ERROR: No LUT named %s using %s'%(aLutName,self.DefaultLUT))
  202. aLutName = self.DefaultLUT
  203. else:
  204. print ('ERROR: No LUT named %s and no default available.'%(aLutName))
  205. return None
  206. range = self.__GetRange(aArray,aRangeOveride)
  207. return self.__GetLookupTableForArray(aArray,
  208. RGBPoints=self.__MapRGB(aLutName,range),
  209. ColorSpace=self.__GetColorSpace(aLutName),
  210. VectorMode='Magnitude',
  211. ScalarRangeInitialized=1.0)
  212. def GetLUTNames(self):
  213. """
  214. Return a list of the currently available LUT's names.
  215. """
  216. return sorted(iter(self.LUTS),cmp=lambda x,y: cmp(x.lower(), y.lower()))
  217. def Print(self):
  218. """
  219. Print the available list of LUT's.
  220. """
  221. names=""
  222. i=0
  223. for k in sorted(iter(self.LUTS),cmp=lambda x,y: cmp(x.lower(), y.lower())):
  224. lut=self.LUTS[k]
  225. names+=lut.GetName()
  226. names+=", "
  227. if ((i%6)==5):
  228. names+="\n"
  229. i+=1
  230. print (names)
  231. return
  232. # end of public interface
  233. def __GetColorSpace(self,aName):
  234. """
  235. Return the color space from the lookup table object.
  236. """
  237. return self.LUTS[aName].GetColorSpace()
  238. def __GetRGB(self,aName):
  239. """
  240. Return the rgb values for the named lut
  241. """
  242. return self.LUTS[aName]
  243. def __MapRGB(self,aName,aRange):
  244. """
  245. Map the rgb values onto a scalar range
  246. results are an array of [x r g b] values
  247. """
  248. colors=self.LUTS[aName].GetRGBValues()
  249. mapCoords=self.LUTS[aName].GetMapCoordinates()
  250. nColors=len(colors)
  251. coord0=float(aRange[0])
  252. coordDelta=float(aRange[1])-float(aRange[0])
  253. mappedColors=[]
  254. i=0
  255. while(i<nColors):
  256. x=coord0+coordDelta*mapCoords[i]
  257. val=[x]+colors[i]
  258. mappedColors+=val
  259. i=i+1
  260. return mappedColors
  261. def __GetRange(self,aArray,aRangeOveride):
  262. """
  263. Get the range from an array proxy object or if
  264. an override is provided use that.
  265. """
  266. nComps = aArray.GetNumberOfComponents()
  267. range = [0.0, 1.0]
  268. if (len(aRangeOveride) == 0):
  269. if (nComps == 1):
  270. range = aArray.GetRange()
  271. else:
  272. # TODO - this could be larger than the range of the magnitude aArray
  273. rx = aArray.GetRange(0)
  274. ry = aArray.GetRange(1)
  275. rz = aArray.GetRange(2)
  276. range = [0.0,
  277. sqrt(rx[1]*rx[1]+ry[1]*ry[1]+rz[1]*rz[1])]
  278. else:
  279. range = aRangeOveride
  280. return range
  281. def __GetLookupTableForArray(self,aArray,**kwargs):
  282. """
  283. Set the lookup table for the given array and assign
  284. the named properties.
  285. """
  286. proxyName='%d.%s.PVLookupTable'%(aArray.GetNumberOfComponents(),aArray.GetName())
  287. lut = servermanager.ProxyManager().GetProxy('lookup_tables',proxyName)
  288. if not lut:
  289. lut = servermanager.rendering.PVLookupTable(ColorSpace="HSV",RGBPoints=[0,0,0,1, 1,1,0,0])
  290. servermanager.Register(lut, registrationName=proxyName)
  291. for arg in kwargs.keys():
  292. if not hasattr(lut, arg):
  293. raise AttributeError("LUT has no property %s"%(arg))
  294. setattr(lut,arg,kwargs[arg])
  295. return lut