Note
Go to the end to download the full example code.
Add a Custom Output System#
This example demonstrates how to build and register a new output system in MyoGestic.
By creating a subclass of the generic Output System Template, you can channel model predictions into any destination you like—such as a virtual environment or hardware device.
We Recommend Implementing any Additions in user_config.py
The user_config.py module is specifically designed for end-users to register and configure their own custom components such as models, features, and filters. This keeps your modifications modular, reduces conflicts with core MyoGestic settings, and simplifies upgrades in the future.
Important
By registering your addition in user_config.py
, you ensure that your custom
configuration stays separate from core MyoGestic functionality and remains
compatible with future updates.
Example Overview#
Create a custom output system class by inheriting from
OutputSystemTemplate
.Implement the required methods for processing and sending predictions.
Register the output system into
CONFIG_REGISTRY
.(Optional) Test your new output system by selecting it in your MyoGestic workflow.
Notes on Implementation#
The class design follows the interface defined by Output System Template, requiring:
A constructor that takes in the
main_window
(as all QObject do) and a boolean flag for classification vs. regression.Definitions for:
_process_prediction__classification(prediction: Any) -> Any
_process_prediction__regression(prediction: Any) -> Any
send_prediction(prediction: Any) -> None
closeEvent(event) -> None
Below, we provide a simplified demonstration that mirrors how you might adapt a neural rehabilitation device interface or a virtual hand interface. For further examples of fully featured implementations, see references in MyoGestic’s existing output systems.
Step 1: Define Your Custom Output System#
from typing import Any
from myogestic.gui.widgets.templates.output_system import OutputSystemTemplate
class MyCustomOutputSystem(OutputSystemTemplate):
"""
A simple example output system for demonstration purposes.
This class shows how to inherit from OutputSystemTemplate and implement
the required abstract methods. It can send predictions to any desired
interface or hardware, provided you adapt the methods below.
"""
def __init__(self, main_window, prediction_is_classification: bool) -> None:
"""
Initialize the custom output system.
Parameters
----------
main_window : Any
The main window object containing a logger or other references.
prediction_is_classification : bool
Set to True for classification tasks, False for regression.
"""
super().__init__(main_window, prediction_is_classification)
# (Optional) Initialize sockets, signals, or other resources here
def _process_prediction__classification(self, prediction: Any) -> Any:
"""
Convert a classification prediction into a format suitable
for your output system or interface.
"""
# Replace with your own logic or mappings
return f"Classification: {prediction}".encode("utf-8")
def _process_prediction__regression(self, prediction: Any) -> Any:
"""
Convert a regression prediction into a format suitable
for your output system or interface.
"""
# Replace with your own logic or mappings
return f"Regression: {prediction}".encode("utf-8")
def send_prediction(self, prediction: Any) -> None:
"""
Send the processed prediction to your output destination.
"""
processed = self.process_prediction(prediction)
# For demonstration, we simply print the processed data
self._main_window.logger.print(
f"Sending: {processed}",
)
def close_event(self, event) -> None:
"""
Handle any cleanup needed when your system closes.
"""
# Close sockets, timers, or other resources here
pass
Step 2: Register the Output System in CONFIG_REGISTRY#
from myogestic.utils.config import CONFIG_REGISTRY
CONFIG_REGISTRY.register_output_system(
name="MyCustomOutputSystem", output_system=MyCustomOutputSystem
)
Example: Virtual Hand Interface#
1from typing import Any
2
3from myogestic.gui.widgets.logger import LoggerLevel
4from myogestic.gui.widgets.templates.output_system import OutputSystemTemplate
5from myogestic.gui.widgets.visual_interfaces.virtual_hand_interface.setup_interface import (
6 VirtualHandInterface_SetupInterface,
7)
8
9PREDICTION2INTERFACE_MAP = {
10 -1: "Rejected Sample",
11 0: "[0, 0, 0, 0, 0, 0, 0, 0, 0]",
12 1: "[0, 0, 1, 0, 0, 0, 0, 0, 0]",
13 2: "[1, 0, 0, 0, 0, 0, 0, 0, 0]",
14 3: "[0, 0, 0, 1, 0, 0, 0, 0, 0]",
15 4: "[0, 0, 0, 0, 1, 0, 0, 0, 0]",
16 5: "[0, 0, 0, 0, 0, 1, 0, 0, 0]",
17 6: "[0.67, 1, 1, 1, 1, 1, 0, 0, 0]",
18 7: "[0.45, 1, 0.6, 0, 0, 0, 0, 0, 0]",
19 8: "[0.55, 1, 0.65, 0.65, 0, 0, 0, 0, 0]",
20}
21
22
23class VirtualHandInterface_OutputSystem(OutputSystemTemplate):
24 """Output system for the Virtual Hand Interface.
25
26 Parameters
27 ----------
28 main_window : MainWindow
29 The main window object.
30 prediction_is_classification : bool
31 Whether the prediction is a classification or regression.
32 """
33
34 def __init__(self, main_window, prediction_is_classification: bool) -> None:
35 super().__init__(main_window, prediction_is_classification)
36
37 if self._main_window.selected_visual_interface is None:
38 self._main_window.logger.print(
39 "No visual interface selected.", level=LoggerLevel.ERROR
40 )
41 raise ValueError("No visual interface selected.")
42
43 if not isinstance(
44 self._main_window.selected_visual_interface.setup_interface_ui,
45 VirtualHandInterface_SetupInterface,
46 ):
47 raise ValueError(
48 "The virtual interface must be the Virtual Hand Interface."
49 f"Got {type(self._main_window.selected_visual_interface)}."
50 )
51
52 self._outgoing_message_signal = (
53 self._main_window.selected_visual_interface.outgoing_message_signal
54 )
55
56 def _process_prediction__classification(self, prediction: Any) -> bytes:
57 """Process the prediction for classification."""
58 return PREDICTION2INTERFACE_MAP[prediction].encode("utf-8")
59
60 def _process_prediction__regression(self, prediction: Any) -> bytes:
61 """Process the prediction for regression."""
62 return str(prediction).encode("utf-8")
63
64 def send_prediction(self, prediction: Any) -> None:
65 """Send the prediction to the visual interface."""
66 self._outgoing_message_signal.emit(self.process_prediction(prediction))
67
68 def close_event(self, event):
69 """Close the output system."""
70 pass
Total running time of the script: (0 minutes 0.368 seconds)
Estimated memory usage: 528 MB