Skip to content

Instantly share code, notes, and snippets.

@deeplook
Created February 12, 2013 14:42
Show Gist options
  • Save deeplook/4770302 to your computer and use it in GitHub Desktop.
Save deeplook/4770302 to your computer and use it in GitHub Desktop.
An IPython notebook illustrating an IPython extension for displaying object graphs.
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "object_graphs"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Writing an IPython extension to show object graphs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Idea**: Reuse a Python package, [pyrels](http://pypi.python.org/pypi/pyrels/0.1.1), to display data structures graphically (see [presentation](http://de.slideshare.net/dinugherman/visualizing-relationships-between-python-objects-europython-2008) at EuroPython 2008) in an IPython notebook.\n",
"\n",
"**Inspiration**: Find an existing extension that already does something similar: display [GraphViz](http://www.graphviz.org) DOT files. [ipython-hierarchymagic](https://github.com/tkf/ipython-hierarchymagic) does it!"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%install_ext https://raw.github.com/tkf/ipython-hierarchymagic/master/hierarchymagic.py\n",
"%load_ext hierarchymagic"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Installed hierarchymagic.py. To use it, type:\n",
" %load_ext hierarchymagic\n"
]
}
],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This gives two new IPython magic commands: `%hierarchy` and `%%dot`, doing what you expect them to do, at least for `%%dot`. We skip %hierarchy here, but you can uncomment it to see the standard example. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# %hierarchy get_ipython()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is actually the command that is pretty similar to what we want:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%dot -f svg\n",
"digraph G {\n",
" a->b; b->c; c->d; c->a; d->b; d->a;\n",
"}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"svg": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n",
" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n",
"<!-- Generated by dot version 2.2.1 (Wed Jan 25 18:54:27 UTC 2012)\n",
" For user: (dinu) Dinu Gherman Title: G Pages: 1 -->\n",
"<svg width=\"150pt\" height=\"264pt\"\n",
" viewBox = \"-1 -1 149 263\"\n",
" xmlns=\"http://www.w3.org/2000/svg\">\n",
"<g id=\"graph0\" class=\"graph\" style=\"font-family:Times-Roman;font-size:14.00;\">\n",
"<title>G</title>\n",
"<g id=\"node1\" class=\"node\"><title>a</title>\n",
"<ellipse cx=\"78\" cy=\"22\" rx=\"27\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"78\" y=\"27\">a</text>\n",
"</g>\n",
"<g id=\"node3\" class=\"node\"><title>b</title>\n",
"<ellipse cx=\"78\" cy=\"94\" rx=\"27\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"78\" y=\"99\">b</text>\n",
"</g>\n",
"<g id=\"edge2\" class=\"edge\"><title>a&#45;&gt;b</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M78,40C78,48 78,57 78,66\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"82,66 78,76 75,66 82,66\"/>\n",
"</g>\n",
"<g id=\"node5\" class=\"node\"><title>c</title>\n",
"<ellipse cx=\"32\" cy=\"166\" rx=\"27\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"32\" y=\"171\">c</text>\n",
"</g>\n",
"<g id=\"edge4\" class=\"edge\"><title>b&#45;&gt;c</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M67,111C62,119 55,131 49,140\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"51,143 43,149 46,139 51,143\"/>\n",
"</g>\n",
"<g id=\"edge8\" class=\"edge\"><title>c&#45;&gt;a</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M31,148C32,129 33,100 42,76 46,65 52,55 58,46\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"55,44 64,38 61,48 55,44\"/>\n",
"</g>\n",
"<g id=\"node7\" class=\"node\"><title>d</title>\n",
"<ellipse cx=\"87\" cy=\"238\" rx=\"27\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"87\" y=\"243\">d</text>\n",
"</g>\n",
"<g id=\"edge6\" class=\"edge\"><title>c&#45;&gt;d</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M44,182C51,191 61,203 69,214\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"72,212 75,222 66,216 72,212\"/>\n",
"</g>\n",
"<g id=\"edge12\" class=\"edge\"><title>d&#45;&gt;a</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M95,221C108,191 129,127 114,76 110,65 104,55 98,46\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"95,48 92,38 101,44 95,48\"/>\n",
"</g>\n",
"<g id=\"edge10\" class=\"edge\"><title>d&#45;&gt;b</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M86,220C84,195 82,151 80,122\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"77,122 79,112 83,122 77,122\"/>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now install *pyrels* 0.1.1 (or higher) if you don't have it already: "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!pip install pyrels==0.1.1"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Requirement already satisfied (use --upgrade to upgrade): pyrels==0.1.1 in /opt/lib/python2.7/site-packages\r\n",
"Cleaning up...\r\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's see if that worked as expected with a very simple example. Here we create some DOT code that we first display manually after passing it to the `%%dot` command:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from pyrels.pyrels2dot import namespace2dot_str\n",
"print namespace2dot_str({\"myInt\": 42})"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"digraph G {\n",
" overlap=false;\n",
"\n",
" name4331282912 [label=\"myInt\", shape=\"ellipse\"];\n",
" int4298193560 [label=\"int: 42\", shape=\"box\"];\n",
"\n",
" name4331282912 -> int4298193560 [label=\"ref\"];\n",
"\n",
"}\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n"
]
}
],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%dot -f svg\n",
"digraph G {\n",
" overlap=false;\n",
"\n",
" name4368865680 [label=\"myInt\", shape=\"ellipse\"];\n",
" int4298193560 [label=\"int: 42\", shape=\"box\"];\n",
"\n",
" name4368865680 -> int4298193560 [label=\"ref\"];\n",
"\n",
"}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"svg": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n",
" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n",
"<!-- Generated by dot version 2.2.1 (Wed Jan 25 18:54:27 UTC 2012)\n",
" For user: (dinu) Dinu Gherman Title: G Pages: 1 -->\n",
"<svg width=\"72pt\" height=\"136pt\"\n",
" viewBox = \"-1 -1 71 135\"\n",
" xmlns=\"http://www.w3.org/2000/svg\">\n",
"<g id=\"graph0\" class=\"graph\" style=\"font-family:Times-Roman;font-size:14.00;\">\n",
"<title>G</title>\n",
"<g id=\"node1\" class=\"node\"><title>name4368865680</title>\n",
"<ellipse cx=\"35\" cy=\"22\" rx=\"30\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"35\" y=\"27\">myInt</text>\n",
"</g>\n",
"<g id=\"node2\" class=\"node\"><title>int4298193560</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"62,92 8,92 8,128 62,128 62,92\"/>\n",
"<text text-anchor=\"middle\" x=\"35\" y=\"115\">int: 42</text>\n",
"</g>\n",
"<g id=\"edge2\" class=\"edge\"><title>name4368865680&#45;&gt;int4298193560</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M35,40C35,52 35,68 35,82\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"39,82 35,92 32,82 39,82\"/>\n",
"<text text-anchor=\"middle\" x=\"43\" y=\"71\">ref</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is what we want to create directly with an extension using pyrels. The code to do that is on [Gist](https://gist.github.com/deeplook/4731035)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# %install_ext file:///Users/dinu/Desktop/joy-of-scipy/ipython_objgraph_magic.py\n",
"%install_ext https://gist.github.com/deeplook/4731035/raw/daa82e13f6635f513694bffb0bb9bc8a1b4ceff2/ipython_object_graphs.py\n",
"%load_ext ipython_objgraph_magic"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Installed ipython_object_graphs.py. To use it, type:\n",
" %load_ext ipython_object_graphs\n"
]
}
],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can create some data structure and display it (as a *namespace*) with the new magic command `%%objgraph`:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class C(object):\n",
" pass\n",
"n = 23\n",
"L = [1, 23, (2, 3), None, C]\n"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%objgraph -f svg\n",
"{\"myInt\": n, \"myList\": L}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"svg": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n",
" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n",
"<!-- Generated by dot version 2.2.1 (Wed Jan 25 18:54:27 UTC 2012)\n",
" For user: (dinu) Dinu Gherman Title: G Pages: 1 -->\n",
"<svg width=\"460pt\" height=\"298pt\"\n",
" viewBox = \"-1 -1 459 297\"\n",
" xmlns=\"http://www.w3.org/2000/svg\">\n",
"<g id=\"graph0\" class=\"graph\" style=\"font-family:Times-Roman;font-size:14.00;\">\n",
"<title>G</title>\n",
"<g id=\"node1\" class=\"node\"><title>name4367705552</title>\n",
"<ellipse cx=\"179\" cy=\"22\" rx=\"33\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"179\" y=\"27\">myList</text>\n",
"</g>\n",
"<g id=\"node2\" class=\"node\"><title>list4367703360</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"100,128 258,128 258,92 100,92 100,128\"/>\n",
"<text text-anchor=\"middle\" x=\"119\" y=\"115\">list:</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"138,128 138,92 \"/>\n",
"<text text-anchor=\"middle\" x=\"150\" y=\"115\">0</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"162,128 162,92 \"/>\n",
"<text text-anchor=\"middle\" x=\"174\" y=\"115\">1</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"186,128 186,92 \"/>\n",
"<text text-anchor=\"middle\" x=\"198\" y=\"115\">2</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"210,128 210,92 \"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"115\">3</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"234,128 234,92 \"/>\n",
"<text text-anchor=\"middle\" x=\"246\" y=\"115\">4</text>\n",
"</g>\n",
"<g id=\"edge16\" class=\"edge\"><title>name4367705552&#45;&gt;list4367703360</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M179,40C179,52 179,68 179,82\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"183,82 179,92 176,82 183,82\"/>\n",
"<text text-anchor=\"middle\" x=\"187\" y=\"71\">ref</text>\n",
"</g>\n",
"<g id=\"node3\" class=\"node\"><title>int4298192568</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"59,180 5,180 5,216 59,216 59,180\"/>\n",
"<text text-anchor=\"middle\" x=\"32\" y=\"203\">int: 1</text>\n",
"</g>\n",
"<g id=\"edge2\" class=\"edge\"><title>list4367703360&#45;&gt;int4298192568</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M138,128C117,148 90,166 68,179\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"69,182 59,184 66,176 69,182\"/>\n",
"</g>\n",
"<g id=\"node4\" class=\"node\"><title>int4298192040</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"131,180 77,180 77,216 131,216 131,180\"/>\n",
"<text text-anchor=\"middle\" x=\"104\" y=\"203\">int: 23</text>\n",
"</g>\n",
"<g id=\"edge4\" class=\"edge\"><title>list4367703360&#45;&gt;int4298192040</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M162,128C151,143 138,159 127,172\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"129,175 120,180 124,170 129,175\"/>\n",
"</g>\n",
"<g id=\"node5\" class=\"node\"><title>tuple4366071424</title>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"161,216 235,216 \"/>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M235,216C241,216 247,210 247,204\"/>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"247,204 247,192 \"/>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M247,192C247,186 241,180 235,180\"/>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"235,180 161,180 \"/>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M161,180C155,180 149,186 149,192\"/>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"149,192 149,204 \"/>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M149,204C149,210 155,216 161,216\"/>\n",
"<text text-anchor=\"middle\" x=\"174\" y=\"203\">tuple:</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"199,216 199,180 \"/>\n",
"<text text-anchor=\"middle\" x=\"211\" y=\"203\">0</text>\n",
"<polyline style=\"fill:none;stroke:black;\" points=\"223,216 223,180 \"/>\n",
"<text text-anchor=\"middle\" x=\"235\" y=\"203\">1</text>\n",
"</g>\n",
"<g id=\"edge6\" class=\"edge\"><title>list4367703360&#45;&gt;tuple4366071424</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M198,128C198,140 198,156 198,170\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"202,170 198,180 195,170 202,170\"/>\n",
"</g>\n",
"<g id=\"node8\" class=\"node\"><title>none</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"319,180 265,180 265,216 319,216 319,180\"/>\n",
"<text text-anchor=\"middle\" x=\"292\" y=\"203\">None</text>\n",
"</g>\n",
"<g id=\"edge8\" class=\"edge\"><title>list4367703360&#45;&gt;none</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M234,128C246,143 259,159 269,172\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"272,170 276,180 267,175 272,170\"/>\n",
"</g>\n",
"<g id=\"node9\" class=\"node\"><title>type4368459968</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"453,180 337,180 337,216 453,216 453,180\"/>\n",
"<text text-anchor=\"middle\" x=\"395\" y=\"203\">new style class: C</text>\n",
"</g>\n",
"<g id=\"edge10\" class=\"edge\"><title>list4367703360&#45;&gt;type4368459968</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M258,128C281,148 310,164 336,176\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"337,173 345,180 334,179 337,173\"/>\n",
"</g>\n",
"<g id=\"node6\" class=\"node\"><title>int4298192544</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"214,254 160,254 160,290 214,290 214,254\"/>\n",
"<text text-anchor=\"middle\" x=\"187\" y=\"277\">int: 2</text>\n",
"</g>\n",
"<g id=\"edge12\" class=\"edge\"><title>tuple4366071424&#45;&gt;int4298192544</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M205,216C202,225 199,235 196,244\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"199,245 193,254 193,243 199,245\"/>\n",
"</g>\n",
"<g id=\"node7\" class=\"node\"><title>int4298192520</title>\n",
"<polygon style=\"fill:none;stroke:black;\" points=\"286,254 232,254 232,290 286,290 286,254\"/>\n",
"<text text-anchor=\"middle\" x=\"259\" y=\"277\">int: 3</text>\n",
"</g>\n",
"<g id=\"edge14\" class=\"edge\"><title>tuple4366071424&#45;&gt;int4298192520</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M241,216C244,225 247,235 250,244\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"253,243 253,254 247,245 253,243\"/>\n",
"</g>\n",
"<g id=\"node10\" class=\"node\"><title>name4367706896</title>\n",
"<ellipse cx=\"38\" cy=\"110\" rx=\"30\" ry=\"18\" style=\"fill:none;stroke:black;\"/>\n",
"<text text-anchor=\"middle\" x=\"38\" y=\"115\">myInt</text>\n",
"</g>\n",
"<g id=\"edge18\" class=\"edge\"><title>name4367706896&#45;&gt;int4298192040</title>\n",
"<path style=\"fill:none;stroke:black;\" d=\"M50,127C60,140 74,157 84,172\"/>\n",
"<polygon style=\"fill:black;stroke:black;\" points=\"87,170 90,180 81,174 87,170\"/>\n",
"<text text-anchor=\"middle\" x=\"84\" y=\"159\">ref</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
]
}
],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Neat! "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment