Plugin Results Format

Currently only Python 3.7 code is supported, so this will be the first thing to get installed on your local workstation. Then download this requirements.txt file so you have the correct libraries and their version available. Install using pip install -r requirements.txt.

A plugin receives an input manifest as first command line argument, and the output file path via the second arguments. A report plugin run would look like this:

python main.py manifest.json results.json

A basic python plugin would look like this:

import sys
import json
with open(sys.argv[1]) as data_file:
manifest = json.load(data_file)
output = {
"data": {
"greeting": "Hello",
"name": "world"
},
"status": {
"code": "success",
"title": None,
"explanation": None,
"backtrace": None
},
"js": "return {greetWith: results.data.greeting}",
"jsx": '''
<Insight>
{ results.helpers.renderHello(data.greetWith, results.data.name) }
</Insight>
''',
"helper": '''
class {
constructor(results) {
}
renderHello(greeting, name) {
return <p>{greeting} {name}!</p>;
}
}
'''
}
f = open(sys.argv[2], 'w')
f.write(json.dumps(output))

It's important to note that the output JSON should always be written to argv[2]; in production this location will be writeable. In general, any files during your plugin run should written to the current path, thus no absolute or other paths, because they will not exist or not be writeable when your plugin runs on the platform in production.

First we read the JSON manifest file. Then we construct a basic JSON plugin results object, shown in the output variable in the example above. The data key can contain anything you like and will be available as-in in the context of the js, jsx and helper keys.

A plugin has different JavaScript contexts to use code within, each defined by their respective keys as a string in the plugin JSON result object. When a plugin runs as stand-alone, it first evaluates the js context and then jsx to display the visualizations — each of which can call any optionally defined helpers:

  1. js — here we have access to a global results variable; an object containing the plugin results. This results object contains two properties: data which is whatever data was returned from Python in the output JSON and helpers is a helper class that can be optionally outputted in the output JSON.
    The object returned in js will be available in the jsx context as the data variable. Normally the js property will not be used; instead it's best to use the helper instead because that will allows for better re-use of any helper code. If used, it's important that the JS code has code at the end of the file, and not comments. See the third item below.

  2. jsx — here we render any JSX components/tags to visualize our plugin. For a full overview of JSX components and API functions see the see the API library. Here we have access to the same global results variable. In addition we also have access to a variable called data, which contains whatever was returned from the js code. In most cases js should not be used, and there is thus no returned data available. Instead we use the helper class instead, as this will allow for easier code re-use, especially when this plugin is available to third-parties.

  3. helper — this is the main glue of the plugin, and defines functions that can be re-used in the jsx or js code parts. Within the helper code, you can access this to call another helper function. All helpers are also pre-initialized with this.results, which gives you access to the plugin results object. The helper functions can also be documented with a JSON format, making them available to third-parties where they can be re-used in the Insight API, with fully ready to use code examples. See the Plugin Helpers documentation for more details.

Finally a plugin ouput should always contain a valid status object. In case of no errors, it can simply look like this:

"status": {
"code": "success"
},

In case of an error, it's most basic format would be:

"status": {
"code": "error",
},

You can also provide a friendly title for end-users in the title key, together with a more detailed error message for the end-user in explanation. Any backtrace can be put into the backtrace. All fields are optional, so you can supply whatever you have available. A full error would look like this:

"status": {
"code": "error",
"title": "Not enough days of data.",
"explanation": "You need at least 14 days of data to make a forecast",
"backtrace": '''
Traceback (most recent call last):
File "main.py", line 4, in <module>
make_forecast(manifest)
File "main.py", line 2, in forecast
forecast(data, 20)
DataError: less than 20 samples, cannot predict.
'''
},

While the plugin code above thus shows how to use the full js, jsx and helper formats, normally you would only use the jsx and helper parts. The code would then be structure more like this:

{
...,
"data": {
"greeting": "Hello",
"name": "world",
"count": 1
},
"jsx": '''
<Insight>
{ results.helpers.renderHello(data.greetWith, results.data.name) }
</Insight>
''',
"helper": '''
class {
constructor(results) {
this.someCalculation = results.data.count * 2;
}
multiplySomeCalculation(factor) {
return this.someCalculation * factor;
}
renderHello() {
return <p>
{this.results.data.greeting} {this.results.data.name}!
My result is {this.multiplySomeCalculation(5)}.
</p>;
}
}
'''
}

Helper functions should not really be used to do intensive work, which is done instead in the plugin itself. The helpers should be a glue layer that render components, visualizes data — by mapping this custom object to the format for different visualization components, and to expose convenience functions for users of the plugin, which could be yourself or third-parties in case you publish the template.

Within js, jsx and helper there is access to a range of visualization components, utility methods and libraries to make developing plugins as easy as possible. See the API library for more details.