Created
July 25, 2017 02:36
-
-
Save jeremyschlatter/c35c6bfa568e5a40440cb2fefcc7fd4e to your computer and use it in GitHub Desktop.
Render React inline from a Jupyter notebook cell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Render React from a Jupyter notebook cell, and access Python as needed at runtime.\n", | |
"\n", | |
"The `%jsx` magic:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/javascript": [ | |
"\n", | |
"// Load our libraries from a CDN instead of wherever this notebook is hosted.\n", | |
"require.config({\n", | |
" paths: {\n", | |
" babel: 'https://unpkg.com/babel-standalone@6/babel.min',\n", | |
" react: 'https://unpkg.com/[email protected]/dist/react',\n", | |
" 'react-dom': 'https://unpkg.com/[email protected]/dist/react-dom'\n", | |
" }\n", | |
"})\n", | |
"\n", | |
"// Hook to call into Python.\n", | |
"// Credit to disarticulate for documenting the usage of iopub: \n", | |
"// https://gist.github.com/disarticulate/d06069ff3e71cf828e5329beab8cb084\n", | |
"window.python = code => new Promise((resolve, reject) => {\n", | |
" IPython.notebook.kernel.execute(\n", | |
" code,\n", | |
" {iopub: {output: data => resolve(data.content.text)}},\n", | |
" ) \n", | |
"})\n" | |
], | |
"text/plain": [ | |
"<IPython.core.display.Javascript object>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"import json\n", | |
"from string import Template\n", | |
"\n", | |
"from IPython.display import Javascript, display\n", | |
"from IPython.core.magic import register_cell_magic\n", | |
"\n", | |
"\n", | |
"display(Javascript('''\n", | |
"// Load our libraries from a CDN instead of wherever this notebook is hosted.\n", | |
"require.config({\n", | |
" paths: {\n", | |
" babel: 'https://unpkg.com/babel-standalone@6/babel.min',\n", | |
" react: 'https://unpkg.com/[email protected]/dist/react',\n", | |
" 'react-dom': 'https://unpkg.com/[email protected]/dist/react-dom'\n", | |
" }\n", | |
"})\n", | |
"\n", | |
"// Hook to call into Python.\n", | |
"// Credit to disarticulate for documenting the usage of iopub: \n", | |
"// https://gist.github.com/disarticulate/d06069ff3e71cf828e5329beab8cb084\n", | |
"window.python = code => new Promise((resolve, reject) => {\n", | |
" IPython.notebook.kernel.execute(\n", | |
" code,\n", | |
" {iopub: {output: data => resolve(data.content.text)}},\n", | |
" ) \n", | |
"})\n", | |
"'''))\n", | |
"\n", | |
"\n", | |
"@register_cell_magic\n", | |
"def jsx(line, cell):\n", | |
" display(Javascript((Template('''\n", | |
" require(['babel', 'react', 'react-dom'], (Babel, React, ReactDOM) => {\n", | |
" eval(Babel.transform($quoted_script, {presets: ['react']}).code)\n", | |
" })\n", | |
" ''').substitute(quoted_script=json.dumps(cell)))))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Some Python state to access from React:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"greeting = 'Hello from Python and React!'" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The punchline:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/javascript": [ | |
"\n", | |
" require(['babel', 'react', 'react-dom'], (Babel, React, ReactDOM) => {\n", | |
" eval(Babel.transform(\"python('print(greeting)').then(greeting => {\\n ReactDOM.render(\\n <h1>{greeting}</h1>,\\n element[0],\\n )\\n})\", {presets: ['react']}).code)\n", | |
" })\n", | |
" " | |
], | |
"text/plain": [ | |
"<IPython.core.display.Javascript object>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"%%jsx\n", | |
"python('print(greeting)').then(greeting => {\n", | |
" ReactDOM.render(\n", | |
" <h1>{greeting}</h1>,\n", | |
" element[0],\n", | |
" )\n", | |
"})" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.1" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Thanks for sharing this!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
JavaScript is disabled for gists, so you can't see the rendered output above. If you run the notebook yourself, you will see this as the final output:
Hello from Python and React!