Easy Customization of the ParaView Python Programmable Filter Property Panel
The Python Programmable Filter is a powerful tool for data analysis in ParaView, as it enables you to implement ParaView readers and filters using Python. Developing filters with Python has several advantages– it's fast to prototype and easy to share, since there's no compiled code. You can use the convenient features of the standard Python library, and use NumPy to perform fast, vectorized operations on VTK data arrays. However, the Programmable Filter interface presented in the property panel is not user friendly because there is no way to hide the Python implementation details. Most users want to adjust the filter by setting filter property values, not by editing Python source code. This blog post will show you how to hide the Python implementation details to make the programmable filter easier to use.
Figure 1. Double Helix Python Programmable Source. Left: custom properties panel. Right: visualization with tube filter. No code compiling required!
Python Programmable Filter with a Custom Property Panel
Aha! Well, it turns out that you can customize the programmable filter's property panel, but you've got to use the development version of ParaView, or any version of ParaView newer than 4.0.1. You can download that from the ParaView downloads page under the section titled Nightly Builds.
In Figure 1., I've used the Double Helix programmable source example and created a custom property panel for it. I took this example from the Python Programmable Filter wiki page. Visit that page to find many more example filters and sources.
How it Works
ParaView can load filters from XML plugins. An XLM plugin is an xml file that describes one-or-more filters using the ParaView server manager xml language. You can read all about that on the Plugin HowTo wiki page.
Through a neat trick in the server manager xml language, you can declare custom properties that will appear in the properties panel using standard property value entry widgets. The Programmable Filter & Source also have Script properties. These are string properties where you enter the filter implementation as Python source code. The Script properties can be given a hint attribute so that they are marked as advanced properties, which will be hidden by default. That way, the user will not be distracted by the properties, but advanced users still have the option of modifying the Python code. Alternatively, the Script properties can be hidden completely from the properties panel.
Figure 2. ParaView screenshot. The Toggle Advanced Properties button is active so that the Python script property is displayed.
Make it easier — Automatically Generate XML
I developed a tool that generates the XML file for you. All you have to do is write a Python script that defines the filter function and the filter properties, and other information like the filter name and documentation. Your Python script is used as input to generate XML automatically. For example, your Python filter might look like this:
Name = 'TestFilter' Label = 'Test Filter' Help = 'Help for the Test Filter' NumberOfInputs = 1 InputDataType = 'vtkPolyData' OutputDataType = 'vtkPolyData' ExtraXml = '' Properties = dict( test_bool = True, test_int = 123, test_int_vector = [1, 2, 3], test_double = 1.23, test_double_vector = [1.1, 2.2, 3.3], test_string = 'string value', ) def RequestData(): assert test_bool == True assert test_int == 123 assert test_int_vector == [1, 2, 3] assert test_double == 1.23 assert test_double_vector == [1.1, 2.2, 3.3] assert test_string == "string value"
Then use the python_filter_generator.py script line to generate the XML file. Here's the program usage:
$ python python_filter_generator.py
Usage: python_filter_generator.py <python input filename> <xml output filename>
Getting Started
Attached to this blog post are all the files you need to get started. I attached both the Python input files and the generated XML files, which are human readable for the most part. As I wrote earlier, this requires ParaView with a version newer than 4.0.1. At the time of this posting, you can download that from the ParaView downloads page under the section titled Nightly Builds. After you have generated an XML file from a Python input script, or written an XML file by hand, then you can load the XML plugin into ParaView using the menu Tools –> Manage Plugins and then click Load New and select your xml file.
Hi !
Do you support the filters with 2 inputs ?
If yes, what is the correct syntax to adopt in the filter header ? I suppose you write NumbreOfInputs = 2, but what about the InputDataType ? How do you specify both ?
Thanks
This does not work anymore in paraview 4.3.6, right? Is there any other way to do it?
Thanks
It should. I just tested it in ParaView 4.4 late last week, and it worked fine.
I can find the plugin under “tools” -> “Manage Plugins” and I even set it to “Auto load on startup” – but how do I find it now to use it? Sorry I might got confused on the way here …
The source or filter that you loaded in the plugin manager will be available in the Sources or Filters menu, respectively.
I just found the flaw, it works for me too now. Thanks for your help. One more question: How can I do a drop down menu?
Great. By drop down menu, do you mean you want to present a list of optional values that a property may take? If so,
see
http://www.paraview.org/Wiki/ParaView/Plugin_HowTo#Drop_down_list
to see how to add an option like this to your filter’s XML file.
The example there, specially for the DropDown menu does not work 🙁 The “initial_string” argument is missing, as I found out through here: http://public.kitware.com/pipermail/paraview/2015-February/033201.html
I don’t know how the correct code is, but for me this works (I had to remove ” from the HTML code and replaced them with ‘#’):
#IntVectorProperty name=”Test Drop Down Menu” command=”SetParameter” number_of_elements=”1″ initial_string=”test_drop_down_menu” default_values=”1″#
#EnumerationDomain name=”enum”#
#Entry value=”1″ text=”testvalue_1″/#
#Entry value=”2″ text=”2nd test value”/#
#Entry value=”3″ text=”42″/#
#/EnumerationDomain#
#Documentation#
Pre order your Chinese menu before you end up waiting too long.
#/Documentation#
#/IntVectorProperty#
I hope this might help someone in the future …
So far so good, but I have two more questions:
1.) how do I get the value the user has chosen?
2.) can I prevent all the other options in the Properties panel from showing up? I don’t want the user to see the “Display (GeometricRepresentation)” and “View (Render View)” options. Actually I would even prefere not to see the “Properties” panel itself, but only the input for the drop down menu I created ….
In response to 1.), in the environment in which your Python script executes, variables with the same name as the “name” attribute in your property are defined, so you can just access them. You should probably avoid spaces in the “name” attribute, e.g., change name=”Test Drop Down Menu” to “Test_Drop_Down_Menu”. Then you can access the value from within your script by referring to Test_Drop_Down_Menu. Note that you can set the text you want to display as the name of the property with the “label” attribute, e.g. label=”Test Drop Down Menu”. The name attribute is used internally to refer to the property.
2). It is likely possible to hide the “Display” and “View” sections, but would take some extensive custom programming.
Hi. I use your sample xml file via Tools -> Manager Custom Filters, then click Import button and select that xml file such as TestFilter.xml. But after all, I cannot see anything appear in the list of manager, and there is nothing about error message. It seems that the manager load the xml filter file unsuccessful. Do I miss any steps or do something wrong? Thanks.
Hi Mo,
I just tested both TestFilter.xml and DoubleHelixSource.xml in ParaView 5.0.0 RC1 and they loaded as plugins just fine.
What is the locale on your machine? I suspect there may be a problem if your machine’s locale is one that assumes a comma is used as the separator between the whole and fractional part of a floating-point number.
Hi,
I was really happy to find this article. We need a source plugin that includes time-steps, but the paraview timeline does not get updated if I feed this to RequestInformation() through the XML:
timeSteps = range(100)
outInfo = self.GetOutputInformation(0)
timeRange = [timeSteps[0], timeSteps[-1]]
outInfo.Set(vtk.vtkStreamingDemandDrivenPipeline.TIME_RANGE(), timeRange, 2)
outInfo.Set(vtk.vtkStreamingDemandDrivenPipeline.TIME_STEPS(), timeSteps, len(timeSteps))
The same lines from Programmable Source directly works. I’m puzzled… No errors appear, it gets executed properly. Doesn’t work from PV4.3-4.4.
Thanks for your help,
Christian
Christian,
I, too, was puzzled about this, but then realized you need one more property in the XML plugin to make this work:
Available timestep values.
This property informs ParaView about the timesteps in the source.
Hope that helps,
Cory
Oops, forgot to format the XML appropriately for this blog:
I’m feeling very stupid, but after 20′ minutes searching, looking into all the links and so, I can’t find the attached sample .xml files nor the python script that wraps filters to plug-ins.
Where do attachments appear in this site? I’ve tried both Chromium and Firefox and can’t see it.
BTW: In first line of How it Works section you’ve written XLM instead of XML.
Cheers,
Mauro
Hi Mauro, I asked the same thing on the newsletter some time ago http://public.kitware.com/pipermail/paraview/2016-February/036220.html , you can find the script in https://gitlab.kitware.com/paraview/paraview/snippets/5
Your response was indeed very helpful. Thanks, Livia!!!
Hi,
This is awesome!
However I have some difficulties using this tools with a “Drop down list with values from input arrays” from http://www.paraview.org/Wiki/ParaView/Plugin_HowTo#Drop_down_list_with_values_from_input_arrays. I managed to make a drop down list works but not from input array. I get the drop down list but can’t figure out how to use its selected value in my scripts. It doesn’t seem to work in the same way as a standard drop down list…
Anyone would know how to do this?
Cheers,
Alfred
Based on this blog post, I wrote a library that makes this process even easier:
https://github.com/shuhaowu/pvpyfilter
Instead of having to write python files based on a specific way, this library exposes a class that you extend from. An example is attached below. More rigorous example exist in that repository.
class ViscosityType(Enum):
Kinematic = 1
Dynamic = 2
class MyFilter(ProgrammableFilter):
label = “My Filter”
input_data_type = “vtkPolyData”
nu = Double(“Viscousity”, default=1.53e-5, slider=[0, 1e-4], help=”…”)
nu_type = IntegerEnum(“Type”, default=ViscosityType.Kinematic,
enum=ViscosityType)
@staticmethod
def request_data(inputs, outputs, nu, nu_type):
print(nu)
print(nu_type)
Nice article.
If I wanted to use a button on my property panel, in addition to the feilds how do I go about that. I was able to get buttons to show up on the panel with a method attribute, but when I click the button I get a error saying my method is not found even though I defined a method by same name in my python script. Any idea how to use buttons, I have been unable to find an example of this using python as the primary language.
Thanks..