How Tos - Tool

To know what is the role of a tool in Snooz, see Technical Overview.

Before creating your own tool

  • You need to have a properly configured development environment for Snooz.
  • Ensure that you have created your repository (e.g., my_snooz_repo) to manage your packages.
  • You have already explored Snooz and have an understanding of its structure.

How to create a tool

We use a command line to help create new tool. To access the terminal in VS Code, make sure to close Snooz beforehand.

  • In VS Code navigate to Terminal -> New Terminal

  • Select your repository you forked from snooz-package-template (e.g. my_snooz_repo)

  • Make sure the virtual environment snooz_310_env is activated (see Developer Installation)

  • In the terminal type : python main_utils.py

  • Select 3- Create a tool

  • Fill the information to suit your design. If you make any mistakes, just repeat the steps and it will ask to overwrite the previous one. If you need more information, see Tools.

How to create a custom step

When using the main_utils.py Python script with the option 3- Create a tool, make sure to answer Y to the prompt “Is this a custom step?”

How to create a configuration step

TODO

How to use a module’s settings page inside a step

When using the main_utils.py Python script with the option 3- Create a tool, make sure to answer N to the prompt “Is this a custom step?”

The script will then ask for a module_id — this corresponds to the identifier field automatically generated when the module is instantiated in the tool’s process view. If the instance has not yet been created, you can leave this field empty and edit the JSON file later.

Example:

The tool SleepCycleExport from the CEAMS package includes a module’s settings view at the steps 2 - Cycle Definition. The step is described in the JSON file SleepCycleExport.json as follows:

{
   "name": "Cycle Definition",
   "description": "Define your sleep cycle.",
   "module_id": "4ae3d940-e282-414a-a1a7-c71f0a7acc98",
   "show_index": true
},

The module_id can be found in the same SleepCycleExport.json file under the module definition, as shown below:

},
   "module": "CEAMSModules.SleepCyclesDelimiter",
   "identifier": "4ae3d940-e282-414a-a1a7-c71f0a7acc98",
   "pos_x": -204.20408163265301,
   "pos_y": -156.0453514739229,
   "activation_state": "activated",
   "package": {
      "package_name": "CEAMSModules"
}

Warning

If you change the module instance in the process view (e.g., delete and recreate it), make sure to update the module_id in the JSON file accordingly.

Note

If multiple instances of the same module exist in the process view, you can distinguish them by their position or their connections.

A useful tip is to temporarily modify the value of an input field by adding a unique keyword to identify the instance more easily.

How to add picture to a step

Sometimes you may want to display a static image (e.g., a diagram, logo, or illustration) directly in your tool’s interface. To do this in Snooz, you can convert your image into Base64 format and then load it dynamically into a QLabel in your PyQt UI.

Step 1 — Convert your image to Base64

Use the following Python script to convert your image file(s) into a Base64-encoded .py file that can be safely included in your package.

import base64
import os

# List of images to convert
image_files = ['image_to_convert.png']

# Variable names for each image
variable_names = ['IMAGE_BASE64']

# Get script directory
script_dir = os.path.dirname(os.path.abspath(__file__))

# Create the output data file
output_file = os.path.join(script_dir, 'image_data_base64.py')

with open(output_file, 'w') as f:
   f.write('"""\n')
   f.write('Base64 encoded images\n')
   f.write('"""\n\n')

   for image_file, var_name in zip(image_files, variable_names):
      try:
            with open(os.path.join(script_dir, image_file), 'rb') as img_f:
               image_data = base64.b64encode(img_f.read()).decode()
               f.write(f'{var_name} = """\n')
               f.write(image_data)
               f.write('\n""".strip()\n\n')
      except FileNotFoundError:
            print(f"Warning: {image_file} not found in {script_dir}")
            f.write(f'{var_name} = ""\n\n')

print(f"Created {output_file}")

After running this script, a new file named image_data_base64.py will be created in the same folder. It will contain one variable (e.g., IMAGE_BASE64) storing your image data.

Step 2 — Add a QLabel to your UI

In Qt Designer, place a QLabel in your form where you want the image to appear. Rename it clearly (for example: label_illustration).

Note

Make sure the label has an appropriate size policy (e.g., Fixed or Preferred) and optionally set scaledContents to True if you want the image to resize with the label.

Step 3 — Display the image in your code

In your Python class that manages the UI, import the Base64 variable and set the image on the QLabel as follows:

import base64
from qtpy.QtGui import QPixmap
from .image_data_base64 import IMAGE_BASE64

image_bytes = base64.b64decode(IMAGE_BASE64)
pixmap = QPixmap()
pixmap.loadFromData(image_bytes)
self.label_illustration.setPixmap(pixmap)

Example:

The SleepBouts tool from the CEAMS package includes an image on its introduction page. The file sleep_bouts.png is converted to Base64 and stored in art_image_data.py. The file IntroStep.py then loads the image and sets it on the QLabel as follows:

def _load_embedded_image(self):
    """Load the embedded base64 image data into label_5."""
    from .art_image_data import SLEEP_BOUTS_IMAGE_BASE64
    image_bytes = base64.b64decode(SLEEP_BOUTS_IMAGE_BASE64)
    pixmap = QPixmap()
    pixmap.loadFromData(image_bytes)
    self.label_5.setPixmap(pixmap)

How to add a resource to a step

TODO

How to Share Information Between Steps

The Snooz architecture allows information to be shared between custom steps in the step-by-step tool before the tool is run. This makes it possible to adapt default settings or perform validation checks based on the user’s choices in previous steps.

The sharing process uses a context dictionary named _context_manager. A custom step can modify values in this dictionary through its UI, and any other step that listens to the same context key will be notified of changes. The _context_manager is a dictionary that publishes updates via the PubSubManager whenever a value is modified. For more details, see Information.

To modify the context dictionary

Edit the Python file of the step that modifies the context dictionary (e.g., Step1.py):

  • Define the context key as a class attribute (e.g., context_choice = "choice").

  • In the constructor, set the default value for that key in the _context_manager dictionary (inherited from BaseStepView):

    e.g., self._context_manager[self.context_choice] = "1"

  • Ensure the value of the key is kept in sync with the UI by updating it every time the user interacts with the interface.

To listen to the context dictionary

Edit the Python file of the step that listens to the context dictionary (e.g., Step2.py):

  • Import the class of the step that modifies the context dictionary:

    e.g., from CEAMSTools.Tool1.Step1Folder.Step1File import Step1Class

  • Update the on_topic_update function to respond to modifications of the context dictionary:
    def on_topic_update(self, topic, message, sender):
       if topic == self._context_manager.topic:
             if message == Step1Class.context_choice:  # key of the context dict
                # Read the value of the key
                context_value = self._context_manager[Step1Class.context_choice]
                # Adapt the settings based on the value read
    

Warning

If the communication between two steps is bidirectional, or if multiple steps need to listen to the same context key, the recommended strategy is to define the context key in a separate file (e.g., commons.py). This allows all relevant steps to write to the same dictionary.

Examples to look at

The tool PowerSpectralAnalysis from the CEAMS package shares information between the steps SelectionStep and AnnotationsSelStep.

For an example that uses a context key defined in a separate file, see the tool ConvertEDFBrowser from the CEAMS package. The steps InputFilesStep and GroupDefinition both write to the data model shared through the context manager.