I am trying to automize Slicer functions that I regularly do manually using Python scripts and I have been facing some problems that have been slowing me down quite a bit. I have been reading through the forums and documentation but I cannot seem to find a proper way to consistently understand how to use the functions embedded in the different modules that Slicer offers. I am no expert in Python, but right now I am only able to successfully use Slicer modules with Python scripts if I happen to come across some use case example that resembles what I am trying to accomplish.
My question is, could someone perhaps give me some insight on their experience as to how would you find your way through using a specific module? Or maybe link some useful documentation to this regard? Maybe what I am asking is a bit too general and it heavily depends on the module itself, but I am really stuck and a bit overwhelmed by documentation at the moment.
If it helps to put a specific (simple) scenario, I am trying to use the surface toolbox module to invert normals from the surface I generate with the segmentation, so that when I extract the .obj or .stl file, normals are facing outwards (shouldn’t that be default?). After that I would like to use VMTK to auto-detect endpoints and extract centerlines, but I have not looked into this last part just yet.
Agreed, figuring out the mapping between UI features and implementation can be tricky. One thing I commonly use is git grep for to find a feature. Sometimes this means finding the text of a label in a .ui or cxx file and then finding the corresponding widget name, and then figuring out what signals it fires and what slots are connected to them. Other times it means reading through a script to figure out the logic. Basically is means getting comfortable with the source code and architecture of the system (and while that is a bit of work, it should be valuable when trying to automate things).
For Python scripted modules, you can see what exact Python calls are made and either replicate those in your module or call the methods of that scripted module. The latter is preferred, especially if it is more than a couple of lines of code, but sometimes modules don’t expose reusable components nicely in their logic interface - in this case you may contact the author and ask for improving the API.
Computing the normals is just 2-3 lines of Python code, so I would just call that directly. Inverting the normals should not be necessary. Maybe you applied a transform that turned the mesh inside out?
VMTK centerline extraction module is Python scripted module, so you can apply the techniques I described above. If you have trouble using the centerline extraction module logic (without the GUI) then submit an issue to the repository.
I discussed this @pieper and while this is fine for full-time developers, it is a very tedious process for someone who occasionally needs to script a basic function in Slicer. In R there is an excellent search function apropos which would return functions containing the string, from which one can directly get the help for (see below an example for SimpleITK. Fyi this all command line, no IDE is involved). I think something along these lines this would be great to implement for Slicer and help scientist who need to bring a few lines of code together without having to go through the source code manually (at least not at the beginning).
@pieper Thank you for the tips! I guess this is more or less what I was fearing a bit, but wanted to make the post before deep diving further in source code, just in case I am missing something obvious. Gonna to try the git grep tip, thanks!
@lassoan Okay, so from what you say, automating functions from CLI and loadable modules will generally be trickier than scripted modules, which should be more straight forward, is that correct?
Thanks! Will take a good look to this.
I do not think I have applied any transformation, I just applied thresholding (min=1, max=1) to a binary nifty and exported the segmentation as an STL or OBJ. Same happens when I do it manually. Should I do it differently?
Okay, will probably do at some point, thank you very much!
Apropos seems like a nice indexer for documentation of already installed Python-accessible packages but it would not help users in finding out how to access a specific features from Python to automate a workflow.
The problem is that scripting applications are much harder to learn that scripting libraries, because libraries typically do not have states and you build your data model yourself. To be able to script applications, you need to get to know how the application works internally, which is a lot of learning. Good documentation, macro recording, etc. can help, but most of the time you end up just googling for a problem and copy-pasting, modifying, combining scripts that you find on forums, blogs, or StackOverflow. This is not specific to Slicer, but the same for all applications that expose a large part of its API. See for example all MS Office applications and these examples to get an idea that just how complicated is to script even the simplest actions. You may be an expert Excel user, but there is no chance you could figure out what 4-5 lines to write to script an action because you need to be very familiar with the application’s data model and functions that operate on them. Macros that Excel records can be somewhat useful, but the recorded actions are rarely reusable directly, instead they may just give some useful hints or make lead you to a dead end.
So, while we can clearly improve many things, scripting an application will be always hard. However, it still takes less effort to learn an application platform than redeveloping an application from scratch.