Writing Plug-ins

A Shape-Link plug-in is a Python script with a class derived from shapelink.ShapeLinkPlugin and some additional meta data. Let’s have a look at this example plugin which prints the rolling mean of a few scalar features to stdout:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import shutil

import numpy as np

from shapelink import ShapeLinkPlugin

# We use the terminal width to make sure a line doesn't get cluttered
# with prints from a previous line.
TERMINAL_WIDTH = shutil.get_terminal_size((80, 20))[0]


class RollingMeansPlugin(ShapeLinkPlugin):
    """Displays a rolling mean of a few scalar features"""
    def __init__(self, *args, **kwargs):
        super(RollingMeansPlugin, self).__init__(*args, **kwargs)
        self.window_size = 100
        self.scalar_data = {}

    def after_register(self):
        print(" Preparing for transmission")
        for feat in self.registered_data_format.scalars:
            self.scalar_data[feat] = np.zeros(self.window_size) * np.nan

    def after_transmission(self):
        print("\n End of transmission\n")

    def handle_event(self, event_data):
        """Handle a new event"""
        window_index = event_data.id % self.window_size
        for ii, feat in enumerate(self.registered_data_format.scalars):
            self.scalar_data[feat][window_index] = event_data.scalars[ii]
        # print the first three features to stdout
        msgs = [" Rolling means: "]
        num_prints = min(3, len(self.registered_data_format.scalars))
        for ii in range(num_prints):
            feat = self.registered_data_format.scalars[ii]
            msgs.append("{}: {:.3g}".format(feat,
                                            np.mean(self.scalar_data[feat])))
        line = "  ".join(msgs)
        if len(line) < TERMINAL_WIDTH:
            line += " " * (TERMINAL_WIDTH - len(line))
        print(line, end="\r", flush=True)

        return False


info = {
    "class": RollingMeansPlugin,
    "description": "Displays a rolling mean of a few scalar features",
    "name": "Rolling Means",
    "version": "0.1.0",
}

The main action happens in the handle_event function - your plugin must implement at least this function. The two functions after_register and after_transmission can be used to set things up (e.g. creation of an additional output file) or to tear things down (e.g. closing that file). Use the __init__ function for defining additional class properties. The info dictionary is required so that the plugin can be run via the Command-line interface.