{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Jigsaw in IPython\n",
"\n",
"This notebook demonstrates using the %jigsaw magic in IPython.\n",
"\n",
"Dependencies:\n",
"\n",
"1. system running IPython or Jupyter\n",
"2. [metakernel](https://github.com/Calysto/metakernel)\n",
"\n",
"## Overview\n",
"\n",
"Jigsaw is a combination of Google's Blockly drag-and-drop interface in the browser with Python. With Jigsaw, you can:\n",
"\n",
"* do many Python tasks in the block-only view\n",
"* have access to predefined Python variables\n",
"* create functions and variables in Jigsaw, but use them in Python cells\n",
"\n",
"To use in IPython, you need to add the metakernel magics for IPython:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from metakernel import register_ipython_magics\n",
"register_ipython_magics()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, let's define some Python things:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"x = 42"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def myfunc(a, b):\n",
" return a + b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we create a Jigsaw workspace named \"workspace1\". This will create two files in this subdirectory:\n",
"\n",
"1. workspace1.html\n",
"2. workspace1.xml\n",
"\n",
"Once you have the Jigsaw workspace showing, then you can start dragging blocks around:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
" if (document.jigsaw_register_workspace === undefined) {\n",
"\n",
" document.jigsaw_workspaces = {};\n",
"\n",
" document.jigsaw_register_workspace = function(workspace_filename, workspace, xml_init) {\n",
" workspace.element = document.element;\n",
" document.jigsaw_workspaces[workspace_filename] = workspace;\n",
"\n",
" try {\n",
" $([window.parent.IPython.events]).on('notebook_saved.Notebook', function() { \n",
" try {\n",
" document.jigsaw_save_workspace(workspace_filename); \n",
" } catch(err) {\n",
" // ignore failure, might not exist\n",
" }\n",
" });\n",
" } catch (err) {\n",
" // rendering for display\n",
" }\n",
" \n",
" var xml = document.jigsaw_loadXMLDoc(workspace_filename);\n",
" if (xml === null) {\n",
" xml = xml_init;\n",
" if (xml === null) {\n",
" xml = Blockly.Xml.textToDom('');\n",
" }\n",
" } else {\n",
" xml = xml.children[0]; // document\n",
" }\n",
" Blockly.Xml.domToWorkspace(workspace, xml);\n",
" };\n",
"\n",
" document.jigsaw_handle_output = function(workspace_filename, out) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" //var output_area = workspace.element.output_area;\n",
" var cell_index = document.jigsaw_get_cell(workspace.element);\n",
" var cell = IPython.notebook.get_cell(cell_index);\n",
" var res = null;\n",
" var data = null;\n",
" document.cell = cell;\n",
" document.out = out;\n",
" if (out.msg_type == \"stream\") {\n",
" res = out.content.text;\n",
" //document.getElementById('code_output').value += res.toString();\n",
" } else if (out.msg_type === \"pyout\") {\n",
" // if output is a python object\n",
" res = out.content.data[\"text/plain\"];\n",
" //document.getElementById('code_output').value += res.toString(); \n",
" } else if (out.msg_type == \"pyerr\") {\n",
" // if output is a python error\n",
" res = out.content.data[\"text/plain\"];\n",
" //document.getElementById('code_output').value += res.toString();\n",
" } else if (out.msg_type == \"execute_result\") {\n",
" var str = out.content.data[\"text/plain\"];\n",
" res = str;\n",
" if (res.indexOf(\"u\") == 0)\n",
" res = res.substring(2, res.length - 1) + \"\\n\";\n",
" if (res) {\n",
" //document.getElementById('code_output').value += res.toString();\n",
" }\n",
" } else if (out.msg_type == \"error\") {\n",
" res = out.content.ename + \": \" + out.content.evalue + \"\\n\";\n",
" // FIXME: out.traceback is Array of terminal color-coded [-codes\n",
" } else {\n",
" // if output is something we haven't thought of\n",
" res = out.toString();\n",
" //document.getElementById('code_output').value += res.toString();\n",
" }\n",
" if (res) {\n",
" cell.output_area.append_output({output_type: \"stream\", text: res.toString(), name: \"output\"});\n",
" }\n",
" };\n",
" \n",
" document.jigsaw_generate = function(workspace_filename, language, insert_code) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" var callbacks = { 'iopub' : {'output' : function(out) { document.jigsaw_handle_output(workspace_filename, out); }}};\n",
" var code = Blockly[language].workspaceToCode(workspace);\n",
" if (insert_code == 1) {\n",
" var cell_index = document.jigsaw_get_cell(workspace.element);\n",
" var cell = IPython.notebook.insert_cell_at_index(0, cell_index + 1);\n",
" cell.set_text(code);\n",
" } else {\n",
" window.parent.IPython.notebook.kernel.execute(code,\n",
" callbacks,\n",
" {silent: false});\n",
" }\n",
" };\n",
" \n",
" document.jigsaw_save_workspace = function(workspace_filename) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" var xml = Blockly.Xml.workspaceToDom(workspace);\n",
" document.xml = xml;\n",
" if (xml !== undefined) {\n",
" console.log(xml);\n",
" //xml.style = \"display: none\";\n",
" //xml.id = \"workspace\";\n",
" var xml_text = Blockly.Xml.domToText(xml)\n",
" IPython.notebook.kernel.execute('%%file ' + workspace_filename + '\\n' + xml_text);\n",
" }\n",
" };\n",
" \n",
" document.jigsaw_loadXMLDoc = function(filename) {\n",
" var xhttp = new XMLHttpRequest();\n",
" xhttp.open(\"GET\", filename, false);\n",
" xhttp.send();\n",
" return xhttp.responseXML;\n",
" };\n",
" }\n",
"\n",
" document.jigsaw_get_cell = function (element) {\n",
" // FIXME: brittle and ugly:\n",
" var mydiv = element[0].parentNode.parentNode.parentNode.parentNode;\n",
" var cells = IPython.notebook.get_cells();\n",
" for (var i = 0; i < cells.length; i++) {\n",
" if (mydiv === cells[i].element[0]) {\n",
" return i;\n",
" }\n",
" }\n",
" return null;\n",
" };\n",
"\n",
" document.jigsaw_clear_output = function (workspace_filename) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" var cell_index = document.jigsaw_get_cell(workspace.element);\n",
" var cell = IPython.notebook.get_cell(cell_index);\n",
" // FIXME: brittle and ugly:\n",
" cell.element[0].children[2].children[1].children[2].children[1].children[0].innerHTML = \"\"\n",
" cell.output_area.outputs[2].text = \"\"\n",
" };\n",
"\n",
" try {\n",
" document.element = element;\n",
" } catch (err) {\n",
" // rendering\n",
" }\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "output",
"output_type": "stream",
"text": [
"42\n"
]
}
],
"source": [
"%jigsaw Python --workspace workspace1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"In the above example, I pulled a print block from the Text category on the left, and a variable block from the Variables category. Snapping them together forms a valid program. I then clicked on the \"Run\" button to run the code. x got its value from the Python cell above.\n",
"\n",
"Let's create another workspace:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
" if (document.jigsaw_register_workspace === undefined) {\n",
"\n",
" document.jigsaw_workspaces = {};\n",
"\n",
" document.jigsaw_register_workspace = function(workspace_filename, workspace, xml_init) {\n",
" workspace.element = document.element;\n",
" document.jigsaw_workspaces[workspace_filename] = workspace;\n",
"\n",
" try {\n",
" $([window.parent.IPython.events]).on('notebook_saved.Notebook', function() { \n",
" try {\n",
" document.jigsaw_save_workspace(workspace_filename); \n",
" } catch(err) {\n",
" // ignore failure, might not exist\n",
" }\n",
" });\n",
" } catch (err) {\n",
" // rendering for display\n",
" }\n",
" \n",
" var xml = document.jigsaw_loadXMLDoc(workspace_filename);\n",
" if (xml === null) {\n",
" xml = xml_init;\n",
" if (xml === null) {\n",
" xml = Blockly.Xml.textToDom('');\n",
" }\n",
" } else {\n",
" xml = xml.children[0]; // document\n",
" }\n",
" Blockly.Xml.domToWorkspace(workspace, xml);\n",
" };\n",
"\n",
" document.jigsaw_handle_output = function(workspace_filename, out) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" //var output_area = workspace.element.output_area;\n",
" var cell_index = document.jigsaw_get_cell(workspace.element);\n",
" var cell = IPython.notebook.get_cell(cell_index);\n",
" var res = null;\n",
" var data = null;\n",
" document.cell = cell;\n",
" document.out = out;\n",
" if (out.msg_type == \"stream\") {\n",
" res = out.content.text;\n",
" //document.getElementById('code_output').value += res.toString();\n",
" } else if (out.msg_type === \"pyout\") {\n",
" // if output is a python object\n",
" res = out.content.data[\"text/plain\"];\n",
" //document.getElementById('code_output').value += res.toString(); \n",
" } else if (out.msg_type == \"pyerr\") {\n",
" // if output is a python error\n",
" res = out.content.data[\"text/plain\"];\n",
" //document.getElementById('code_output').value += res.toString();\n",
" } else if (out.msg_type == \"execute_result\") {\n",
" var str = out.content.data[\"text/plain\"];\n",
" res = str;\n",
" if (res.indexOf(\"u\") == 0)\n",
" res = res.substring(2, res.length - 1) + \"\\n\";\n",
" if (res) {\n",
" //document.getElementById('code_output').value += res.toString();\n",
" }\n",
" } else if (out.msg_type == \"error\") {\n",
" res = out.content.ename + \": \" + out.content.evalue + \"\\n\";\n",
" // FIXME: out.traceback is Array of terminal color-coded [-codes\n",
" } else {\n",
" // if output is something we haven't thought of\n",
" res = out.toString();\n",
" //document.getElementById('code_output').value += res.toString();\n",
" }\n",
" if (res) {\n",
" cell.output_area.append_output({output_type: \"stream\", text: res.toString(), name: \"output\"});\n",
" }\n",
" };\n",
" \n",
" document.jigsaw_generate = function(workspace_filename, language, insert_code) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" var callbacks = { 'iopub' : {'output' : function(out) { document.jigsaw_handle_output(workspace_filename, out); }}};\n",
" var code = Blockly[language].workspaceToCode(workspace);\n",
" if (insert_code == 1) {\n",
" var cell_index = document.jigsaw_get_cell(workspace.element);\n",
" var cell = IPython.notebook.insert_cell_at_index(0, cell_index + 1);\n",
" cell.set_text(code);\n",
" } else {\n",
" window.parent.IPython.notebook.kernel.execute(code,\n",
" callbacks,\n",
" {silent: false});\n",
" }\n",
" };\n",
" \n",
" document.jigsaw_save_workspace = function(workspace_filename) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" var xml = Blockly.Xml.workspaceToDom(workspace);\n",
" document.xml = xml;\n",
" if (xml !== undefined) {\n",
" console.log(xml);\n",
" //xml.style = \"display: none\";\n",
" //xml.id = \"workspace\";\n",
" var xml_text = Blockly.Xml.domToText(xml)\n",
" IPython.notebook.kernel.execute('%%file ' + workspace_filename + '\\n' + xml_text);\n",
" }\n",
" };\n",
" \n",
" document.jigsaw_loadXMLDoc = function(filename) {\n",
" var xhttp = new XMLHttpRequest();\n",
" xhttp.open(\"GET\", filename, false);\n",
" xhttp.send();\n",
" return xhttp.responseXML;\n",
" };\n",
" }\n",
"\n",
" document.jigsaw_get_cell = function (element) {\n",
" // FIXME: brittle and ugly:\n",
" var mydiv = element[0].parentNode.parentNode.parentNode.parentNode;\n",
" var cells = IPython.notebook.get_cells();\n",
" for (var i = 0; i < cells.length; i++) {\n",
" if (mydiv === cells[i].element[0]) {\n",
" return i;\n",
" }\n",
" }\n",
" return null;\n",
" };\n",
"\n",
" document.jigsaw_clear_output = function (workspace_filename) {\n",
" var workspace = document.jigsaw_workspaces[workspace_filename];\n",
" var cell_index = document.jigsaw_get_cell(workspace.element);\n",
" var cell = IPython.notebook.get_cell(cell_index);\n",
" // FIXME: brittle and ugly:\n",
" cell.element[0].children[2].children[1].children[2].children[1].children[0].innerHTML = \"\"\n",
" cell.output_area.outputs[2].text = \"\"\n",
" };\n",
"\n",
" try {\n",
" document.element = element;\n",
" } catch (err) {\n",
" // rendering\n",
" }\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "output",
"output_type": "stream",
"text": [
"11\n"
]
}
],
"source": [
"%jigsaw Python --workspace workspace2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"In the above example, I dragged the following blocks:\n",
" \n",
"1. print from Text\n",
"2. expression from Python\n",
"3. set ... to from Variables\n",
"4. sqrt(2) from Math\n",
"\n",
"I had to click on the set block and create a new variable named \"sqrt_two\". I also had to click on the math constant block to change pi to sqrt(2).\n",
"\n",
"If you click on the \"Generate Python Code\" it will create a new cell below:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import math\n",
"\n",
"\n",
"print((myfunc(5, 6)))\n",
"sqrt_two = math.sqrt(2)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you enter the variable named \"sqrt_two\" in the following cell and run it, you get as output the result from running the Jigsaw blocks:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1.4142135623730951"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sqrt_two"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Try it out!"
]
}
],
"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.4.0"
}
},
"nbformat": 4,
"nbformat_minor": 0
}