Hi Raphael,
I prepared the following:
This is the custom Python plugin for applying threshold iteratively for selected ranges of Tag property from predefined list:
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 30 20:45:00 2021
@author: Pavel Novikov
"""
"""This is the plugin for ParaView for thresholding the model with multiple
ranges simultaneously by using a list of predefined ranges for values
of property array.
Works for property of 'int' type.
Output object type: vtkUnstructuredGrid,
not vtkMultiBlockDataSet (as for vtkMultiThreshold filter)
"""
from paraview.util.vtkAlgorithm import *
import vtk
# Predefined ranges for values of 'Tag' property
TAG_RANGES = {
'Dots': (100, 110), # (min, max)
'Wake points': (110, 110),
'Polygons': (300, 332),
'Body Panel': (332, 332),
}
def createModifiedCallback(anobject):
"""Return a function needed for multiple tag selection"""
import weakref
weakref_obj = weakref.ref(anobject)
anobject = None
def _markmodified(*args, **kwars):
o = weakref_obj()
if o is not None:
o.Modified()
return _markmodified
@smproxy.filter(label="Threshold By Predefined Ranges")
@smproperty.input(name="Input")
@smdomain.datatype(dataTypes=["vtkUnstructuredGrid"],
composite_data_supported=False)
class PreserveInputTypeFilter(VTKPythonAlgorithmBase):
def __init__(self):
super().__init__(nInputPorts=1, nOutputPorts=1,
outputType="vtkUnstructuredGrid")
# Predefined ranges for dynamic selection
from vtkmodules.vtkCommonCore import vtkDataArraySelection
self._arrayselection = vtkDataArraySelection()
self._arrayselection.AddObserver("ModifiedEvent",
createModifiedCallback(self))
[self._arrayselection.AddArray(k) for k in TAG_RANGES.keys()]
self._arrayselection.DisableAllArrays()
self._tag_val_minmax = None # (min_val, max_val)
self._tag_ranges_selected = {}
def _get_array_selection(self):
return self._arrayselection
# Ability for users to choose in GUI which predefined ranges to use
# for thresholding the model.
@smproperty.dataarrayselection(name="Tag types")
def GetDataArraySelection(self):
return self._get_array_selection()
def _value_in_tag_ranges(self, v):
for r in self._tag_ranges_selected.values():
if (v >= r[0]) and (v <= r[1]):
return True
return False
def _get_ranges_to_exclude(self):
boundaries = [self._tag_val_minmax[0], self._tag_val_minmax[1]]
for r in self._tag_ranges_selected.values():
boundaries.extend([r[0], r[1]])
boundaries.sort()
ranges_to_exclude = []
for i in range(len(boundaries)-1):
v = 0.5*sum(boundaries[i:i+2])
if not self._value_in_tag_ranges(v):
ranges_to_exclude.append((boundaries[i], boundaries[i+1]))
return ranges_to_exclude
def RequestDataObject(self, request, inInfo, outInfo):
inData = self.GetInputData(inInfo, 0, 0)
assert inData is not None
if(inData.GetCellData().GetNumberOfArrays()>0):
if not inData.GetCellData().HasArray('Tag'):
raise RuntimeError('There is no "Tag" property in the model')
else:
minmax = inData.GetCellData().GetArray('Tag').GetRange()
self._tag_val_minmax = (int(minmax[0])-1, int(minmax[1])+1)
outData = self.GetOutputData(outInfo, 0)
if outData is None or (not outData.IsA(inData.GetClassName())):
outData = inData.NewInstance()
outInfo.GetInformationObject(0).Set(outData.DATA_OBJECT(), outData)
return super().RequestDataObject(request, inInfo, outInfo)
def RequestData(self, request, inInfo, outInfo):
"""This is a set of actions performed after clicking the Apply
button in ParaView filter GUI.
"""
inData = self.GetInputData(inInfo, 0, 0)
# Create dict with selected tag types and their value ranges
self._tag_ranges_selected = {}
for i in range(self._arrayselection.GetNumberOfArrays()):
k = self._arrayselection.GetArrayName(i)
if self._arrayselection.ArrayIsEnabled(k):
self._tag_ranges_selected[k] = TAG_RANGES[k]
# Find reversed set of ranges to apply them for threshold filter
# iteratively
ranges_to_exclude = self._get_ranges_to_exclude()
thr = vtk.vtkThreshold()
thr.SetInputData(inData)
for r in ranges_to_exclude:
if r[0]+1 <= r[1]-1:
thr.ThresholdBetween(r[0]+1, r[1]-1)
thr.SetInputArrayToProcess(0, 0, 0,
vtk.vtkDataObject.
FIELD_ASSOCIATION_CELLS, 'Tag')
thr.InvertOn()
thr.Update()
outData = self.GetOutputData(outInfo, 0)
outData.ShallowCopy(thr.GetOutput())
return 1
Hope this is the solution.
Best Regards,
Pavel