# show.py
#
# An abbreviated way to output simple HTML layout of text and images
# into a python notebook.
#
# - show a PIL image to show an inline HTML .
# - show an array of items to vertically stack them, centered in a block.
# - show an array of arrays to horizontally lay them out as inline blocks.
# - show an array of tuples to create a table.
import PIL.Image, base64, io, IPython, types, sys
import html as html_module
from IPython.display import display
g_buffer = None
def blocks(obj, space=''):
return IPython.display.HTML(space.join(blocks_tags(obj)))
def rows(obj, space=''):
return IPython.display.HTML(space.join(rows_tags(obj)))
def rows_tags(obj):
if isinstance(obj, dict):
obj = obj.items()
results = []
results.append('
')
for row in obj:
results.append('')
for item in row:
results.append('')
results.extend(blocks_tags(item))
results.append(' | ')
results.append('
')
results.append('
')
return results
def blocks_tags(obj):
results = []
if hasattr(obj, '_repr_html_'):
results.append(obj._repr_html_())
elif isinstance(obj, PIL.Image.Image):
results.append(pil_to_html(obj))
elif isinstance(obj, (str, int, float)):
results.append('')
results.append(html_module.escape(str(obj)))
results.append('
')
elif isinstance(obj, dict):
results.extend(blocks_tags([(k, v) for k, v in obj.items()]))
elif hasattr(obj, '__iter__'):
if hasattr(obj, 'tolist'):
# Handle numpy/pytorch tensors as lists.
try:
obj = obj.tolist()
except:
pass
blockstart, blockend, tstart, tend, rstart, rend, cstart, cend = [
'',
'
',
'',
'',
'
',
'',
' | ',
]
needs_end = False
table_mode = False
for i, line in enumerate(obj):
if i == 0:
needs_end = True
if isinstance(line, tuple):
table_mode = True
results.append(tstart)
else:
results.append(blockstart)
if table_mode:
results.append(rstart)
if not isinstance(line, str) and hasattr(line, '__iter__'):
for cell in line:
results.append(cstart)
results.extend(blocks_tags(cell))
results.append(cend)
else:
results.append(cstart)
results.extend(blocks_tags(line))
results.append(cend)
results.append(rend)
else:
results.extend(blocks_tags(line))
if needs_end:
results.append(table_mode and tend or blockend)
return results
def pil_to_b64(img, format='png'):
buffered = io.BytesIO()
img.save(buffered, format=format)
return base64.b64encode(buffered.getvalue()).decode('utf-8')
def pil_to_url(img, format='png'):
return 'data:image/%s;base64,%s' % (format, pil_to_b64(img, format))
def pil_to_html(img, margin=1):
mattr = ' style="margin:%dpx"' % margin
return '' % (pil_to_url(img), mattr)
def a(x, cols=None):
global g_buffer
if g_buffer is None:
g_buffer = []
g_buffer.append(x)
if cols is not None and len(g_buffer) >= cols:
flush()
def reset():
global g_buffer
g_buffer = None
def flush(*args, **kwargs):
global g_buffer
if g_buffer is not None:
x = g_buffer
g_buffer = None
display(blocks(x, *args, **kwargs))
def show(x=None, *args, **kwargs):
flush(*args, **kwargs)
if x is not None:
display(blocks(x, *args, **kwargs))
def html(obj, space=''):
return blocks(obj, space)._repr_html_()
class CallableModule(types.ModuleType):
def __init__(self):
# or super().__init__(__name__) for Python 3
types.ModuleType.__init__(self, __name__)
self.__dict__.update(sys.modules[__name__].__dict__)
def __call__(self, x=None, *args, **kwargs):
show(x, *args, **kwargs)
sys.modules[__name__] = CallableModule()