Widget plugins

Vitessce supports multiple types of plugins defined using JavaScript code.

Leveraging concepts from anywidget, we can define such plugins directly from Python: plugin developers can supply custom JavaScript code via a Python string.

The most minimal example of such plugin JavaScript code is the following:

PLUGIN_ESM = """
function createPlugins(utilsForPlugins) {
    const {
        React,
        PluginFileType,
        PluginViewType,
        PluginCoordinationType,
        PluginJointFileType,
        z,
        useCoordination,
    } = utilsForPlugins;
    return {
        pluginViewTypes: undefined,
        pluginFileTypes: undefined,
        pluginCoordinationTypes: undefined,
        pluginJointFileTypes: undefined,
    };
}
export default { createPlugins };
"""

The plugin string must be defined as an EcmaScript Module (ESM) that exports a function named createPlugins. The createPlugins function is called (on the initial render of the Jupyter widget) with the utilsForPlugins argument (to facilitate dependency injection) and returns an object with the following properties:

  • pluginViewTypes: an array of objects that define the view types of the plugin.

  • pluginFileTypes`: an array of objects that define the file types of the plugin.

  • pluginCoordinationTypes: an array of objects that define the coordination types of the plugin.

  • pluginJointFileTypes: an array of objects that define the joint file types of the plugin.

If defined, these plugin arrays are passed to the Vitessce component as props with the same names.

Note: For maximum stability of plugins, we recommend that plugin developers document which version(s) of the vitessce Python package that plugins have been developed under.

Passing plugin ESM to the widget

The plugin string can be passed to the widget using the plugins parameter and passing a subclass of VitesscePlugin:

from vitessce import VitessceConfig, VitesscePlugin

class MyPlugin(VitesscePlugin):
    plugin_esm = PLUGIN_ESM

vc = VitessceConfig(description="A Vitessce widget with a custom plugin")
# Some more configuration here...

plugin = MyPlugin()
vc.widget(plugins=[plugin])

Defining plugin views using JSX

Vitessce plugin view types are defined as React components. During typical React component development, JSX syntax is used. However, JSX is not valid JavaScript and therefore must be transformed to valid JavaScript before it can be passed to the widget where it will be interpreted as ESM. Vitessce plugin developers then have two options for defining React components for plugin view types:

  • Use React.createElement directly (without JSX).

  • Use the transform function from esbuild_py to perform JSX to JS transformation.

from esbuild_py import transform

PLUGIN_ESM = transform("""
function createPlugins(utilsForPlugins) {
    const {
        React,
        PluginFileType,
        PluginViewType,
        PluginCoordinationType,
        PluginJointFileType,
        z,
        useCoordination,
    } = utilsForPlugins;

    function MyPluginView(props) {
        return (
            <p>Hello world from JSX!</p>
        );
    }

    const pluginViewTypes = [
        new PluginViewType('myPlugin', MyPluginView, []),
    ];
    return { pluginViewTypes };
}
export default { createPlugins };
""")

To import additional dependencies, JavaScript (more specifically, ESM) can be dynamically imported from CDN (such as unpkg or esm.sh) within the createPlugins function:

PLUGIN_ESM = """
async function createPlugins(utilsForPlugins) {
    const {
        React,
        PluginFileType,
        PluginViewType,
        PluginCoordinationType,
        PluginJointFileType,
        z,
        useCoordination,
    } = utilsForPlugins;

    const d3 = await import('https://cdn.jsdelivr.net/npm/d3@7/+esm');

    // Do something with d3 here...

    return {
        pluginViewTypes: undefined,
        pluginFileTypes: undefined,
        pluginCoordinationTypes: undefined,
        pluginJointFileTypes: undefined,
    };
}
export default { createPlugins };
"""

To support more complex import scenarios, see dynamic-importmap.

vitessce.widget_plugins

class vitessce.widget_plugins.demo_plugin.DemoPlugin[source]

Example of a minimal plugin view that gets the obsType coordination value from the coordination space and renders a button. This plugin view is not meant to be useful for end-users, but rather to demonstrate how to develop a plugin view that uses coordination (and uses eslint_py for JSX transformation).

from vitessce.widget_plugins import DemoPlugin

# ...
vc.widget(plugins=[DemoPlugin()])
class vitessce.widget_plugins.spatial_query.SpatialQueryPlugin(adata, spatial_key='X_spatial', label_key='cell_type')[source]

Spatial-Query plugin view renders controls to change parameters passed to the Spatial-Query methods.

Construct a new Vitessce widget.

Parameters
  • adata (anndata.AnnData) – AnnData.

  • spatial_key (str) – The key in adata.obsm that contains the (x, y) coordinates of each cell. By default, “X_spatial”.

  • label_key (str) – The column in adata.obs that contains the cell type labels. By default, “cell_type”.

from vitessce.widget_plugins import SpatialQueryPlugin

plugin = SpatialQueryPlugin(adata, spatial_key="X_spatial", label_key="cell_type")
# ...
vc.widget(plugins=[plugin], remount_on_uid_change=False)
on_config_change(new_config)[source]

Config change handler.

Parameters

new_config (dict) – The new config object.

Returns

config (likely with new “uid” property) or None

Return type

dict or None