Yet more simple python API

Hi folks,

Over this weekend, I prototyped another layer of simple python interface that is a lot closer to pyvista and vedo. Here is a description:

The functional and postfix part are super easy to implement and maintain. Just a matter of registering certain filters and their short names. There was a little bit more work involved in dusting off the representation-views framework and improving it. There is yet more work to be done there such as volume representations, axes, selection etc. I also did not add support for composite datasets so that’s on my list too.

I would love to hear what you think.

3 Likes

Berk, this looks very nice.

This VTK Python API is now very similar to ParaView’s. Maybe this would be confusing for users of both VTK and ParaView simple?

ParaView does

from paraview.simple import *
s = Sphere(Radius=3.0)
Show()

and VTK does

from vtkmodules.simple_api import *
s = sphere(radius=3.0)
s.show()

I don’t have any suggestions here, just noting the similarity

This is very nice. I have one weird thought: in ParaView, pipelines are often composed of filters that are named differently than the underlying VTK filters - it’s not always clear what VTK filters (I suppose it might even be a few chained filters) are actually executing, so I end up hunting this information down which can be annoying, and it makes it difficult sometimes to understand what’s going on under the hood. Similarly, I am wondering is it possible to embed a property in the python interface/functions that provides a level of introspection to facilitate the learning of classic VTK? I think building consistent bridges between VTK, ParaView, VTK.wasm, trame, SimpleVTK, etc could significantly improve the usability and teachability of the various systems. It could also provide a improved path from prototyping ideas to creating production code.

This is neat!

While I’ve not officially announced a JavaScript API for VTK.wasm, I’m inclined to apply this idea. Wdyt @Sebastien_Jourdain ?

Interesting Will. I have been thinking about the same thing. I think this may be where an AI assistant may come in handy. It is an easy thing to do. I have also been wondering if there is a more direct way of exposing the underlying VTK in ParaView… Currently, you have to use the python programmable filter and expose the API yourself… I wonder if it could be automated… Especially with the introspection layer that Jaswant and co. added…

See my response to Will. It may not be such a bad thing to start blurring the two since the only difference is interface really…

I fully disagree on your take that it would be beneficial to bring VTK and ParaView python API close together.

There is virtually no overlap between VTK users and ParaView. Moreover, we already have issue with users using servermanager.Fetch() without understanding the consequence. Lets not make it easier in ParaView side to do the wrong thing.

I have no opinion regarding VTK python API, which I’m not a user of apart the occasional programmable filter.

There is virtually no overlap between VTK users and ParaView.

Well there’s at least one: me :-). I find the ability to debug the output of complex VTK algorithms with ParaView to be very useful. Probing point and cell ids, evaluating feature/non-manifold/boundary edges, I could probably come up with several dozen PV tools that I’ve used. Not to mention producing images for publication etc.

It would be very easy to hide “bridge / integration layers” so that new functionality would only appear when an explicit switch is thrown.

I can see this as being realy useful in introducing new users to VTK. Especially in schools and Universities. Also for those wanting to quickly prototype something.

1 Like

The readme should show how to pass parameters to write, if they are supported. I frequently want to control ASCII/binary format, and usually want VTK files in 4.2 version which Slicer can read. Abstracting reader/writer type is welcome! Here is an excerpt from a program I wrote recently:

def writeSTL(mesh, filename):
    writer = vtk.vtkSTLWriter()
    writer.SetFileName(filename)
    writer.SetInputData(mesh)
    writer.SetFileTypeToBinary()  # smaller, reads faster
    writer.Update()


def writeVTK(mesh, filename):
    writer = vtk.vtkPolyDataWriter()
    writer.SetFileName(filename)
    writer.SetInputData(mesh)
    writer.SetFileTypeToASCII()  # better for debugging
    writer.SetFileVersion(42)
    writer.Update()

Thanks all for the responses. The ParaView issue aside, it looks like there is interest in this group at least. @dzenanz : You are absolutely right. Thanks for pointing it out. What I proposed here is more a concept (although I have working code) than the actual implementation. I will be more more careful designing the actual API and bounce it off you guys.

2 Likes

+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…

2 Likes

Brilliant suggestions @user27182 ! I need to think about the auto-generation part. My original idea was to curate the set of most useful filters…

I totally agree with your idea of naming filters consistently. I have been thinking about it and what I suggest is that we remove vtk and Filter/Source and snake case the rest. Filters sound more like actions then.