Creating custom transforms

To create our custom transform, we will first start off by generating a data schema for our transform. This schema will consist of the media type that we want associated with our custom transform and the required data. Let's create a custom image transform that will take a URL render the image inline. We'll use the application/custom+image media type for our transform. We expect our transform to return the following data.

"application/custom+image": {
    url: "some_url_string
}

To return this custom display object, we'll write some Python code to return it. Note that this code can live in a user's notebook or inside an SDK.

from IPython import display
def display_image(url):
    display(
        {
            'application/custom+image': {
                'url': url
            }
        },
        raw=True
    )

Now, whenever we invoke display_image with a URL...

display_image("https://google.com")

...our custom display object will be returned.

{
  "header": {
    "msg_id": "dee8b762-55ff3974d3ec058673943272",
    "msg_type": "display_data",
    "username": "jovyan",
    "session": "ab5f4df2-170dc205efb0162216b06b93",
    "date": "2020-01-20T18:39:17.094143Z",
    "version": "5.3"
  },
  "msg_id": "dee8b762-55ff3974d3ec058673943272",
  "msg_type": "display_data",
  "parent_header": {
    "msg_id": "a701150300c047fb884c0532cec803b5",
    "username": "username",
    "session": "64a0b46ccde943fd8c3928a604e76dbc",
    "msg_type": "execute_request",
    "version": "5.2",
    "date": "2020-01-20T18:39:17.091372Z"
  },
  "metadata": {},
  "content": {
    "data": { "application/custom+image": { "url": "https://google.com" } },
    "metadata": {},
    "transient": {}
  },
  "buffers": [],
  "channel": "iopub"
}

Next, we will need to create a nteract transform that renders our component. An nteract transform is a React component that adheres to the following schema.

import React from "react";

interface CustomImageObject {
    url: string;
}

interface Props {
    mediaType: "application/custom+image",
    data: CustomImageObject;
}

export default class CustomImageTransform extends React.Component<Props> {
    static defaultProps {
        mediaType: "application/custom+image",
    }

    render() {
        const { data } = this.props;
        return <img src={data.url}/>;
    }
}

A nteract transform must define a mediaType prop that stores the media type the transform is related to. In this case, it's application/custom+image. The transform must also take a data prop which takes the value of the media type in the return display_data object. In this case, it is an object with a url property that holds a string representation of the URL.

The transforms render method is where the magic happens. Here, we take the data from the props of the component and use the url field to render an image. The logic inside the render method is media-type specific so get creative and implement whatever render logic you want based on the contents of the transform.

Once a transform is created, we will need to register it to the transform state in nteract. This can be done by dispatch an addTransform.

import { actions } from "@nteract/core";
import { dispatch } from "redux;

import CustomImageTransform from "./custom-image";

dispatch(
    actions.addTransform({
        mediaType: "application/custom+image",
        component: CustomImageTransform
    })
)

You can also register the transform in the initial state of your nteract-based UI.

{
  "transforms": {
    "byId": {
      "application/custom+image": CustomImageTransform
    },
    "displayOrder": ["application/custom+image"]
  }
}

And voila! Now when we execute our display_image function, we will see the image in the provided URL in our cell's output.