+1 for improving the python API
RE: filters:
Filters can be called as standalone functions (passing a dataset as the first argument) or as methods on any dataset object
I like this. In particular, implementing these as methods is super important for discoverability, since IDEs will suggest and auto-complete method names (assuming these have .pyi files generated for the methods). VTK has so many great filters but I find it hard sometimes to even know there’s a filter out there that does exactly what I want due to the discoverability issue, i.e. answer the question where can I find all the filters that operate on PolyData?.
Is it possible to abstract the idea of filters as methods even further outside of the proposed from vtkmodules.simple_api module? E.g. maybe there’s some kind of machinery that can auto-generate filters as python methods based on the input port information? E.g. if a filter does something like this:
def FillInputPortInformation(self, vtkself, port, info):
info.Set(vtk.vtkAlgorithm.INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet")
return 1
then is it possible to somehow inspect this when generating the python bindings, and since the input can be any vtkDataSet in this case, then all subclasses can be auto-assigned this filter as a method? (I know very little about the inner workings of vtkAlgorithm and how the python bindings are generated).
This would be similar to the new VTK 9.4 syntax for connecting filters. E.g. an example from the release notes https://docs.vtk.org/en/v9.4.1/release_details/9.4/new-python-api-for-pipelines.html:
result = vtkShrinkFilter(shrink_factor=0.5)(input_data)
would instead become
result = input_data.vtkShrinkFilter(shrink_factor=0.5)
Or, drop vtk and Filter from the name too and make it snake_case:
result = input_data.shrink(shrink_factor=0.5)
(not sure if this syntax should describe input connections or input objects… though)
Speaking of algorithm names, for the new vtkmodules.simple_api, I would recommended using the original vtk alg names exactly if possible, other than perhaps removing vtk prefix and Filter/Source suffix. In the gist, I noticed that you have surface_nets and clean, for example. But there is both vtkSurfaceNets3D and vtkSurfaceNets2D … so which one does surface_nets use? Or does it try to abstract both into a unified filter? Similar for clean there is vtkCleanPolyData and vtkStaticCleanPolyData and also vtkStaticCleanUnstructuredGrid… if I do PolyData().clean(), which clean filter is being used internally, exactly? Moreover, the APIs differ for the different PolyData and UnstructuredGrid clean filters, so calling PolyData.clean vs UnstructuredGrid.clean results in a Liskov Substitution Principle violation… better to do PolyData.clean_poly_data or UnstructuredGrid.clean_unstructured_grid separately I think to make it clear to users which VTK algorithm is being used and therefore make it easier to lookup the docs for the algorithm.
Unless, perhaps part of the goal of the simple api is to remove some of this friction to unify the API? But then the new API requires entirely new documentation to describe these differences…