extract_selection.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. r"""This module is used by vtkPythonExtractSelection to extract query-based
  2. selections. It relies on `paraview.detail.calculator`
  3. to compute a mask array from the query expression. Once the mask array is obtained,
  4. this filter will either extract the selected ids, or mark those elements as requested.
  5. """
  6. from __future__ import absolute_import, print_function
  7. try:
  8. import numpy as np
  9. except ImportError:
  10. raise RuntimeError ("'numpy' module is not found. numpy is needed for "\
  11. "this functionality to work. Please install numpy and try again.")
  12. import re
  13. import vtkmodules.numpy_interface.dataset_adapter as dsa
  14. import vtkmodules.numpy_interface.algorithms as algos
  15. from vtkmodules.vtkCommonDataModel import vtkDataObject
  16. from vtkmodules.util import vtkConstants
  17. from . import calculator
  18. # this module is needed to ensure that python wrapping for
  19. # `vtkPythonExtractSelection` is setup correctly.
  20. from paraview.modules import vtkRemotingCore
  21. def _create_id_array(dataobject, attributeType):
  22. """Returns a VTKArray or VTKCompositeDataArray for the ids"""
  23. if not dataobject:
  24. raise RuntimeError ("dataobject cannot be None")
  25. if dataobject.IsA("vtkCompositeDataSet"):
  26. ids = []
  27. for ds in dataobject:
  28. ids.append(_create_id_array(ds, attributeType))
  29. return dsa.VTKCompositeDataArray(ids)
  30. else:
  31. return dsa.VTKArray(\
  32. np.arange(dataobject.GetNumberOfElements(attributeType)))
  33. def maskarray_is_valid(maskArray):
  34. """Validates that the maskArray is either a VTKArray or a
  35. VTKCompositeDataArrays or a NoneArray other returns false."""
  36. return maskArray is dsa.NoneArray or \
  37. isinstance(maskArray, dsa.VTKArray) or \
  38. isinstance(maskArray, dsa.VTKCompositeDataArray)
  39. def execute(self):
  40. inputDO = self.GetInputDataObject(0, 0)
  41. inputSEL = self.GetInputDataObject(1, 0)
  42. outputDO = self.GetOutputDataObject(0)
  43. assert inputSEL.GetNumberOfNodes() >= 1
  44. selectionNode = inputSEL.GetNode(0)
  45. field_type = selectionNode.GetFieldType()
  46. if field_type == selectionNode.CELL:
  47. attributeType = vtkDataObject.CELL
  48. elif field_type == selectionNode.POINT:
  49. attributeType = vtkDataObject.POINT
  50. elif field_type == selectionNode.ROW:
  51. attributeType = vtkDataObject.ROW
  52. else:
  53. raise RuntimeError ("Unsupported field attributeType %r" % field_type)
  54. # evaluate expression on the inputDO.
  55. # this is equivalent to executing the Python Calculator on the input dataset
  56. # to produce a mask array.
  57. inputs = []
  58. inputs.append(dsa.WrapDataObject(inputDO))
  59. query = selectionNode.GetQueryString()
  60. # get a dictionary for arrays in the dataset attributes. We pass that
  61. # as the variables in the eval namespace for calculator.compute().
  62. elocals = calculator.get_arrays(inputs[0].GetAttributes(attributeType))
  63. if ("id" not in elocals) and re.search(r'\bid\b', query):
  64. # add "id" array if the query string refers to id.
  65. # This is a temporary fix. We should look into
  66. # accelerating id-based selections in the future.
  67. elocals["id"] = _create_id_array(inputs[0], attributeType)
  68. try:
  69. maskArray = calculator.compute(inputs, query, ns=elocals)
  70. except:
  71. from sys import stderr
  72. print ("Error: Failed to evaluate Expression '%s'. "\
  73. "The following exception stack should provide additional developer "\
  74. "specific information. This typically implies a malformed "\
  75. "expression. Verify that the expression is valid.\n" % query, file=stderr)
  76. raise
  77. if not maskarray_is_valid(maskArray):
  78. raise RuntimeError(
  79. "Expression '%s' did not produce a valid mask array. The value "\
  80. "produced is of the type '%s'. This typically implies a malformed "\
  81. "expression. Verify that the expression is valid." % \
  82. (query, type(maskArray)))
  83. # if inverse selection is requested, just logical_not the mask array.
  84. if selectionNode.GetProperties().Has(selectionNode.INVERSE()) and \
  85. selectionNode.GetProperties().Get(selectionNode.INVERSE()) == 1:
  86. maskArray = algos.logical_not(maskArray)
  87. output = dsa.WrapDataObject(outputDO)
  88. if self.GetPreserveTopology():
  89. # when preserving topology, just add the mask array as
  90. # vtkSignedCharArray to the output. vtkPythonExtractSelection should
  91. # have already ensured that the input is shallow copied over properly
  92. # before this method gets called.
  93. # Note: we must force the data type to VTK_SIGNED_CHAR or the array will
  94. # be ignored by the freeze selection operation
  95. from vtkmodules.util.numpy_support import numpy_to_vtk
  96. if type(maskArray) is not dsa.VTKNoneArray:
  97. insidedness = numpy_to_vtk(maskArray, deep=1, array_type=vtkConstants.VTK_SIGNED_CHAR)
  98. insidedness.SetName("vtkInsidedness")
  99. output.GetAttributes(attributeType).VTKObject.AddArray(insidedness)
  100. else:
  101. # handle extraction.
  102. # flatnonzero() will give is array of indices where the arrays is
  103. # non-zero (or non-False in our case). We then pass that to
  104. # vtkPythonExtractSelection to extract the selected ids.
  105. nonzero_indices = algos.flatnonzero(maskArray)
  106. output.FieldData.append(nonzero_indices, "vtkSelectedIds");
  107. #print (output.FieldData["vtkSelectedIds"])
  108. self.ExtractElements(attributeType, inputDO, outputDO)
  109. del nonzero_indices
  110. del maskArray