Create External Jobs
RELION has a built-in job called "External" that can run any command as a RELION job. This means that if you define the proper wrapper for the command you want to use, you can easily extend RELION.
Simple examples are available in the GitHub repository.
Class Structure
All the subclasses of RelionExternalJob will be registered as external jobs. The
subclasses must implement output_nodes() and run().
from himena_relion.external import RelionExternalJob
class MyJob(RelionExternalJob):
def output_nodes(self):
return [
("output-particles.star", "ParticleGroupMetadata.star"),
("output-density.mrc", "DensityMap.mrc"),
]
def run(
self,
in_3dref,
in_parts,
some_param: float,
):
# do something with the input files and parameters
output_nodes()should return a list of (output file name, node type) pairs. The output file name is relative to the job directory.RelionExternalJobwill trust the output files to be generated by therun()method and will not check the implementation sanity. The node type should be one of the node types that RELION can interpret.run()should implement the logic of the job. To make the job abortable,run()should be a generator function in whichyieldstatement is inserted at the checkpoints. Following variables are useful for the implementation:self.out_job_dirPath ... path to the job directory.self.consolerich.console.Console ... a console object for printing messages to the user.self.console.log("xyz")will print "xyz" to the run.out file.
Job Title
To make the job more informative, you can override the job_title() class method to provide a custom job title.
from himena_relion.external import RelionExternalJob
class MyJob(RelionExternalJob):
...
@classmethod
def job_title(cls):
return "My Job"
Parameter types
To provide the user interface for the job parameters, himena-relion uses the type-to-widget mapping functionality built by magicgui, with restrictions on the types so that the job parameters can be safely
serialized to and deserialized from a job.star file.
In short, following parameter types can be immediately used as the type annotations:
intfloatstrboolPath(frompathlib)T | None(whereTis one of the above.)list[T](whereTis one of the above.)tuple[T1, T2, ...](whereT1,T2, ... are one of the above.)Literal["option1", "option2", ...](fromtyping)
To improve the user interface, you will usually need to use Annotated type from
typing to provide extra information for the widgets.
Annotated[
int,
{
"min": 0, # specific to int and float types
"max": 100, # specific to int and float types
"step": 1, # specific to int and float types
"label": "Parameter X",
"tooltip": "This is an integer parameter.",
"group": "Advanced Parameters",
}
]
The reserved parameter names
Following parameter names are reserved for RELION and can be used in the run() method.
These parameters do not need type annotations.
in_3dref... Reference mapin_coords... Picked particle coordinatesin_mask... Maskin_mics... Micrographsin_movies... Moviesin_parts... Particlesj... Number of threads to use
Widget For Your Job
If defined, provide_widget() will be called when the job window is opened. This method
must return a Qt widget
class MyJob(RelionExternalJob):
...
def provide_widget(self, job_dir):
return QMyJobWidget(job_dir)
job_dir is a JobDirectory object. This object is implemented with properties and
methods that are useful for the manipulation of the job content.
job_dir.path... absolute path to the job directory.job_dir.relion_project_dir... absolute path to the RELION project directory.job_dir.make_relative_path(path)... convert to the path relative to the RELION project (like"Class2D/job020/job.star").job_dir.resolve_path(path)... convert to the absolute path.
The Qt widget class to be returned can be any class that inherits from QWidget. To
listen to the updates of the job content, you can implement the
on_job_updated(job_dir, path) method in the widget class. This method will be called
when the path file under the job_dir is updated.
from qtpy import QtWidgets as QtW
class QMyJobWidget(QtW.QWidget):
def __init__(self, job_dir):
super().__init__()
# build your custom widget here
def on_job_updated(self, job_dir, path):
# this method will be called when the `path` file under the `job_dir` is
# updated.
...
Run Your Job
himena can also install a .py file as a plugin. You can run the following command for
testing and actually running your jobs.
himena relion --install myjob.py
If the installation succeeds, you should see the file is listed under the "Plugins" panel of the setting dialog (Ctrl+,)

and your job is discoverable in the command palette (Ctrl+Shift+P).
Distribute As A Plugin
Since your RELION plugin is just a Python module, you can distribute it as a
pip-installable package. You need to specify the entry point in your pyproject.toml
file as follows.
[project.entry-points."himena.plugin"]
"My RELION Plugin" = mymodule.mysubmodule.myjob
Please refer to the himena plugin system for more details.