
1.2.3 Notebook的显示系统
若单元中代码的最后一行没有缩进,并且不以分号结尾,则在单元的输出栏中显示运行该代码后得到的对象。此外运算核的标准输出被重定向到单元的输出框中,因此可以使用print语句输出任何信息。例如在下面的程序中,使用循环进行累加计算,在循环体中使用print输出中间结果,而最后一行的运算结果就是变量s的值:
s = 0 for i in range(4): s += i print "i={}, s={}".format(i, s) s i=0, s=0 i=1, s=1 i=2, s=3 i=3, s=6 6
1.display模块
由于Notebook采用浏览器作为界面,因此除了可以显示文本之外,还可以显示图像、动画、HTML等多种形式的数据。有关显示方面的功能均在IPython.display模块中定义。其中提供了表1-3所示的对象,用于显示各种格式的数据。
表1-3 IPython.display模块提供的用于显示各种格式的数据的类

当对单元中程序的最后一行求值并得到上述类型的对象时,将在单元的输出栏中显示对应的格式。也可以使用display模块中的display()函数在程序中输出这些对象。下面的程序使用Latex对象输出了3个数学公式,其中前两个使用display()输出,而由于最后一行的求值结果为Latex()对象,因此它也会被显示为数学公式。
from IPython import display for i in range(2, 4): display.display(display.Latex("$x^{i} + y^{i}$".format(i=i))) display.Latex("$x^4 + y^4$")
x2 +y2
x3 +y3
x4 +y4
Image对象可以用于显示图像,当用url参数时,它会从指定的网址获取图像,并显示在Notebook中。如果embed参数为True,图像的数据将直接嵌入到Notebook之中,这样此后打开此Notebook时,即使没有联网也可以显示该图像。
logourl = "https://www.python.org/static/community_logos/python-logo-master-v3-TM.png" display.Image(url=logourl, embed=True)
在后续的章节中经常会将NumPy数组显示为图像,这时可以使用matplotlib中提供的函数将数组转换成PNG图像的字符串,然后通过Image将图像数据嵌入到Notebook中。下面的as_png()使用matplotlib中的imsave()将数组转换成PNG图像数据:
def as_png(img, **kw): "将数组转换成PNG格式的字符串数据" import io from matplotlib import image from IPython import display buf = io.BytesIO() image.imsave(buf, img, **kw) return buf.getvalue()
下面的程序通过公式sin(x2 +2▪y2 +x▪y)生成二维数组z,并调用as_png()将其转换为字符串png,查看该字符串的头10个字节,可以看出该字符串就是PNG图像文件中的数据。最后使用Image()将该字符串使用PNG图像显示出来,结果如图1-10(左)所示。

图1-10 使用as_png()将数组显示为PNG图像(左),将as_png()注册为数组的显示格式(右)
import numpy as np y, x = np.mgrid[-3:3:300j, -6:6:600j] z = np.sin(x**2 + 2*y**2 + x*y) png = as_png(z, cmap="Blues", vmin=-2, vmax=2) print repr(png[:10]) display.Image(png) '\x89PNG\r\n\x1a\n\x00\x00'
2.自定义对象的显示格式
有两种方式可以自定义对象在Notebook中的显示格式:
●给类添加相应的显示方法。
●为类注册相应的显示函数。
当我们自己编写类的代码时,使用第一种方法最为便捷。和Python的__str__()方法类似,只需要定义_repr_*_()等方法即可,这里的*可以是html、svg、javascript、latex、png等格式的名称。
在下面的例子中,Color类中定义了IPython用的两个显示方法:_repr_html_()和_repr_png_(),它们分别使用HTML和PNG图像显示颜色信息。
class Color(object): def __init__(self, r, g, b): self.rgb = r, g, b def html_color(self): return '#{:02x}{:02x}{:02x}'.format(*self.rgb) def invert(self): r, g, b = self.rgb return Color(255-r, 255-g, 255-b) def _repr_html_(self): color = self.html_color() inv_color = self.invert().html_color() template = '<span style="background-color:{c};color:{ic};padding:5px;">{c}</span>' return template.format(c=color, ic=inv_color) def _repr_png_(self): img = np.empty((50, 50, 3), dtype=np.uint8) img[:,:,:] = self.rgb return as_png(img)
下面创建Color对象,并直接查看它,IPython会自动选择最合适的显示格式。由于Notebook是基于HTML的,HTML格式的优先级别最高,因此查看Color对象时,_repr_html_()方法将被调用:
c = Color(255, 10, 10) c
为了使用其他格式显示对象,可以调用display.display_*()函数,这里调用display_png()将Color对象转换成PNG图像显示:
display.display_png(c)
每种输出格式都对应一个Formatter对象,它们被保存在DisplayFormatter对象的formatters字典中,下面获取该字典中与PNG格式对应的Formatter对象:
shell = get_ipython() png_formatter = shell.display_formatter.formatters[u'image/png']
调用Formatter.for_type_by_name()可以为该输出格式添加指定的格式显示函数,其前两个参数分别为模块名和类名。由于使用字符串指定类,因此添加格式显示函数时不需要载入目标类。下面的代码为NumPy的数组添加显示函数as_png():
png_formatter.for_type_by_name("numpy", "ndarray", as_png)
下面查看前面创建的数组z,它将以图像的形式呈现,结果如图1-10(右)所示。
z
如果目标类已被载入,可以使用for_type()方法为其添加格式显示函数。下面的代码将表示分数的Fraction类使用LaTeX的数学公式进行显示:
from fractions import Fraction latex_formatter = shell.display_formatter.formatters[u"text/latex"] def fraction_formatter(obj): return '$$\\frac{%d}{%d}$$' % (obj.numerator, obj.denominator) latex_formatter.for_type(Fraction, fraction_formatter) Fraction(3, 4) ** 4 / 3
