"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"HTML(tag_from_data(im.data))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can create our own subclass, hich take a list of images and contruct and HTML representation for each of these, then join them together. We define and define a `_repr_html_`, that wrap the all in a paragraph tag, and add a comma between each image: "
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"class VignetteList:\n",
" \n",
" \n",
" def __init__(self, *images, size=None):\n",
" self.images = images\n",
" self.size = size\n",
" \n",
" def _repr_html_(self):\n",
" return ''+','.join(tag_from_data(im.data, self.size) for im in self.images)+'
'\n",
" \n",
" def _repr_latex_(self):\n",
" return '$ O^{rly}_{books} (%s\\ images)$ ' % (len(self.images))\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We also define a LaTeX Representation – that we will not use here, and look at our newly created object using previously defined list:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
"
"
],
"text/latex": [
"$ O^{rly}_{books} (9\\ images)$ "
],
"text/plain": [
"<__main__.VignetteList at 0x107ddd400>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"VignetteList(*mylist, size='200px')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That is nice, though it forces us to unpack all the lists we have explicitely into a VignetteList – which may be annoying. Let's cleanup a bit the above, and register an external formatter for the \"text/html\" mimetype that should be used for any object which is a `list`. We'll also improve the formatter to recusrse in objects. THat is to say: \n",
" - If it's an image return the PNG data in an `` tag, \n",
" - If it's an object that has an `text/html` reprensetation, use that. \n",
" - Otherwise, use th repr. \n",
" \n",
"With this we loose some nice formatting of text lists with the pretty module, we could easily fix that; but we leve it as an exercice for the reader. We're also going to recusrse into objects, that have a html representation. That it to say, make it work with lists of lists. "
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"def tag_from_data_II(data, size='100%'):\n",
" return ''''''.format(''.join(base64.encodebytes(data).decode().split('\\n')), size)\n",
"\n",
"def html_list_formatter(ll):\n",
" html = get_ipython().display_formatter.formatters['text/html']\n",
" reps = []\n",
" for o in ll:\n",
" if isinstance(o, Image):\n",
" reps.append(tag_from_data_II(o.data, '200px') )\n",
" else: \n",
" h = html(o)\n",
" if h: \n",
" reps.append(h)\n",
" else:\n",
" reps.append(repr(o)+'')\n",
" \n",
" return '['+','.join(reps)+']'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Same as before, with square bracket after and before, and a bit of styling that change the drop shadow on hover. Now we register the above with IPython:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"ipython = get_ipython()\n",
"html = ipython.display_formatter.formatters['text/html']\n",
"html.for_type(list, html_list_formatter)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"[,,,,,,,,]"
],
"text/plain": [
"[,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ,\n",
" ]"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mylist"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Disp\n",
"\n",
"External integration for some already existing object is available in [disp](https://github.com/ipython/disp), in particular you will find representation for SparkContext, `requests`'s `Responses` object (collapsible json content and headers), as well as a couple others. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Magic integration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The above demonstatratino show that a kernel is more than a language, it is a controling process that manage user requests (in our case code execution) and how the results are returned to the user. There is often the assumtion that a kernel is a single language, this is an incorrect assumtion as a kernl proces may manage several language and can orchestrate data movement from one language to another. \n",
"\n",
"In the following we can see how a Python process make use of what we have defined above to make sql querries returning rich results. We also see that the execution od SQL queries have side effects in the Python namespace, showing how the kernel can orchestrate things. "
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"load_ext fakesql"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"`rly` not defined\n"
]
}
],
"source": [
"try:\n",
" rly\n",
"except NameError:\n",
" print('`rly` not defined')"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"[['buzzwordfirst-big.png',],['buzzwordfirstdesign-big.png',],['goodenoughtoship-big.png',],['noddingalong-big.png',],['resumedrivendevelopment-big.png',],['takingonneedlessdependencies-big.png',]]"
],
"text/plain": [
"[['buzzwordfirst-big.png', ],\n",
" ['buzzwordfirstdesign-big.png', ],\n",
" ['goodenoughtoship-big.png', ],\n",
" ['noddingalong-big.png', ],\n",
" ['resumedrivendevelopment-big.png', ],\n",
" ['takingonneedlessdependencies-big.png', ]]"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%%sql\n",
"SELECT name,cover from orly WHERE color='red' LIMIT 10"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"['goodenoughtoship-big.png',]"
],
"text/plain": [
"['goodenoughtoship-big.png', ]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rly[2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It would not be hard to have modification of the Python namespace to affect the SQL database, this is left as an exercise to the user as well (hint use properties) and to have integration with other languages like R, Julia, ... "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note:\n",
"\n",
"> This notebook has initially been written to display prototype features of IPython and the Jupyter notebook, in particular completions of cell magic (for the Sql Cell), and UI element allowing to switch between the shown mimetype. This will not be reflected in static rendering and is not mentioned in the text, which may lead to a confusing read. "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "PythonRoot",
"language": "python",
"name": "pythonroot"
},
"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
}