annotation.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #==============================================================================
  2. #
  3. # Program: ParaView
  4. # Module: annotation.py
  5. #
  6. # Copyright (c) Kitware, Inc.
  7. # All rights reserved.
  8. # See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
  9. #
  10. # This software is distributed WITHOUT ANY WARRANTY; without even
  11. # the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. # PURPOSE. See the above copyright notice for more information.
  13. #
  14. #==============================================================================
  15. r"""
  16. This module is used by vtkPythonAnnotationFilter.
  17. """
  18. from __future__ import absolute_import, print_function
  19. try:
  20. import numpy as np
  21. except ImportError:
  22. raise RuntimeError("'numpy' module is not found. numpy is needed for "\
  23. "this functionality to work. Please install numpy and try again.")
  24. from . import calculator
  25. from vtkmodules.vtkCommonDataModel import vtkDataObject
  26. from vtkmodules.numpy_interface import dataset_adapter as dsa
  27. # import vtkPVVTKExtensionsFiltersPython so vtkAnnotateAttributeDataFilter wrapping
  28. # is registered.
  29. import paraview.modules.vtkPVVTKExtensionsFiltersPython
  30. import sys # also for sys.stderr
  31. if sys.version_info >= (3,):
  32. xrange = range
  33. def _get_ns(self, do, association):
  34. if association == vtkDataObject.FIELD:
  35. # For FieldData, it gets tricky. In general, one would think we are going
  36. # to look at field data in inputDO directly -- same for composite datasets.
  37. # However, ExodusIIReader likes to put field data on leaf nodes instead.
  38. # So we also check leaf nodes, if the FieldData on the root is empty.
  39. # We explicitly call dsa.DataObject.GetFieldData to ensure that
  40. # when dealing with composite datasets, we get the FieldData on the
  41. # vtkCompositeDataSet itself, not in the leaf nodes.
  42. fieldData = dsa.DataObject.GetFieldData(do)
  43. if len(fieldData.keys()) == 0:
  44. # if this is a composite dataset, use field data from the first block with some
  45. # field data.
  46. if isinstance(do, dsa.CompositeDataSet):
  47. for dataset in do:
  48. fieldData = dataset.GetFieldData()
  49. if (not fieldData is None) and (len(fieldData.keys()) > 0): break
  50. else:
  51. fieldData = do.GetAttributes(association)
  52. arrays = calculator.get_arrays(fieldData)
  53. ns = {}
  54. ns["input"] = do
  55. if self.GetDataTimeValid():
  56. ns["time_value"] = self.GetDataTime()
  57. ns["t_value"] = ns["time_value"]
  58. if self.GetNumberOfTimeSteps() > 0:
  59. ns["time_steps"] = [self.GetTimeStep(x) for x in range(self.GetNumberOfTimeSteps())]
  60. ns["t_steps"] = ns["time_steps"]
  61. if self.GetTimeRangeValid():
  62. ns["time_range"] = self.GetTimeRange()
  63. ns["t_range"] = ns["time_range"]
  64. if self.GetDataTimeValid() and self.GetNumberOfTimeSteps() > 0:
  65. try:
  66. ns["time_index"] = ns["time_steps"].index(ns["time_value"])
  67. ns["t_index"] = ns["time_index"]
  68. except ValueError: pass
  69. ns.update(arrays)
  70. return ns
  71. def execute(self):
  72. """Called by vtkPythonAnnotationFilter."""
  73. expression = self.GetExpression()
  74. inputDO = self.GetCurrentInputDataObject()
  75. if not expression or not inputDO:
  76. return True
  77. inputs = [dsa.WrapDataObject(inputDO)]
  78. association = self.GetArrayAssociation()
  79. ns = _get_ns(self, inputs[0], association)
  80. try:
  81. result = calculator.compute(inputs, expression, ns=ns)
  82. except:
  83. print("Failed to evaluate expression '%s'. "\
  84. "The following exception stack should provide additional "\
  85. "developer specific information. This typically implies a malformed "\
  86. "expression. Verify that the expression is valid.\n\n" \
  87. "Variables in current scope are %s \n" % (expression, list(ns)), file=sys.stderr)
  88. raise
  89. self.SetComputedAnnotationValue("%s" % result)
  90. return True
  91. def execute_on_attribute_data(self, evaluate_locally):
  92. """Called by vtkAnnotateAttributeDataFilter."""
  93. inputDO = self.GetCurrentInputDataObject()
  94. if not inputDO:
  95. return True
  96. inputs = [dsa.WrapDataObject(inputDO)]
  97. info = self.GetInputArrayInformation(0)
  98. association = info.Get(vtkDataObject.FIELD_ASSOCIATION())
  99. # sanitize name
  100. array_name = paraview.make_name_valid(info.Get(vtkDataObject.FIELD_NAME()))
  101. # note: _get_ns() needs to be called on all ranks to avoid deadlocks.
  102. ns = _get_ns(self, inputs[0], association)
  103. if array_name not in ns:
  104. print("Failed to locate array '%s'." % array_name, file=sys.stderr)
  105. raise RuntimeError("Failed to locate array")
  106. if not evaluate_locally:
  107. # don't evaluate the expression locally.
  108. return True
  109. array = ns[array_name]
  110. if array.IsA("vtkStringArray"):
  111. chosen_element = array.GetValue(self.GetElementId())
  112. else:
  113. chosen_element = array[self.GetElementId()]
  114. expression = self.GetPrefix() if self.GetPrefix() else ""
  115. expression += str(chosen_element)
  116. self.SetComputedAnnotationValue(expression)
  117. return True