Jupyter Notebook
Jupyter Notebook(以下简称 JN)就是原来的 IPython Notebook,它是一个基于 Web 的、可以使用 IPython 绝大多数功能的记事本应用。它允许将交互式的代码、图片在 Web 上展示出来,支持不同语言的语法高亮、缩进、Tab 自动补全、在线编辑和保存等功能,广泛用于如下场景:
- 项目说明文档。
- PPT 演示,尤其是交互的数据分析相关的 PPT 演示。
- 个人技术笔记。
- 技术博客。Pelican 通过 pelican-ipynb 插件以及 Nikola 可以支持 JN 格式文章。
我们先安装它。由于 Notebook 现在已经拆分出来,为了保证能使用全部的功能,需要使用-U 更新全部依赖包:
> pip install -U ipywidgets "ipython[notebook]" ipywidgets 是从 IPython 拆分出来的 HTML 挂件项目,需要先激活: > jupyter nbextension enable --py widgetsnbextension Enabling notebook extension jupyter-js-widgets/extension... - Validating: OK
现在启动它:
> cd ~/web_develop/chapter12/section2 > jupyter notebook --port 5000 --no-browser --ip="*"
启动 JN 默认会自动打开浏览器访问 Web 应用,使用--no-browser 则会禁止打开。JN 使用的 Web 应用框架为 Tornado。
现在打开“http://localhost:5000”就可以访问 JN 了。首先创建一个 JN 文档。在页面的右侧有一个“New”按钮,单击它,出现下拉框,选择“Python 2”,如图 12.1 所示。
图 12.1 创建一个 JN 文档
新建的文件由于还没有命名,会使用 Untitled.ipynb 这个名字。
默认系统中只有这个“Python 2”内核,也就是支持 Python 2 的语法。如果希望支持更多内核,可以通过官网(http://bit.ly/23fz8eS )获得。如果希望同时支持 Python 2 和 Python 3,可以把“Python 3”的内核文件先安装到公用目录/usr/local/share/jupyter/kernels/下:
> sudo pip3 install ipython[notebook] > sudo ipython3 kernelspec install-self
图 12.2 所示的是含有 4 个交互执行代码块的例子。
图 12.2 含有 4 个交互执行的代码块
每一个交互区域叫作一个 Cell,前两个使用 IPython 的 Magic 函数执行 Python 代码文件,第三个执行 Bash 代码,第四个是使用自带的下拉菜单(Dropdown)这个 HTML 挂件。页面上可以看到两排菜单:第一排包含了全部的可执行操作,第二排是一些基于第一排菜单中操作的快捷方式。
JN 除了支持代码还支持 Markdown 语法,同时还支持使用键盘快捷键(使用快捷键 H 就可以看到快捷键列表)来执行任务。常用的快捷键如表 12.2 所示。
表 12.2 常用的键盘快捷键
快捷键 | 功能 |
B | 在当前选择的 Cell 之后添加新的 Cell |
A | 在当前选择的 Cell 之前添加新的 Cell |
Command+S | 保存当前的 JN 文件 |
Shift+Enter | 执行当前的 Cell,然后选择下一个 Cell |
在单击“New”按钮出现下拉框时,可以看到还有如下两种常见类型。
- 文本文件(Text File)。把 JN 当作在线编辑器,可以在线编辑代码,选择代码语言,编辑时语法高亮,还能保存、重命名、下载、选择编辑器绑定类型(目前支持 VIM、Emacs 和 Sublime Text)等。
- Terminal(终端)。需要安装 terminado 包才能使用这个功能。terminado 是一个为 term.js 提供 Tornado 的 Websocket 后端支持的终端模拟器库,让我们可以把 Web 页面当成终端来使用,如图 12.3 所示。
图 12.3 把 Web 页面当成终端来使用
Notebook 配置
除了在启动时添加参数指定端口和 IP,还可以把对应的设置存放在配置文件中。现在需要手动生成配置文件:
> jupyter notebook --generate-config
这样就会添加~/.jupyter/jupyter_notebook_config.py 文件。我们修改这个文件的如下几个设置:
c.NotebookApp.open_browser=False c.NotebookApp.password='sha1:19c53926b1d7:6248a00119f231540f9ba294e2739858da82bba3' c.NotebookApp.port=5000 c.NotebookApp.ip='0.0.0.0' c.NotebookApp.certfile='/home/ubuntu/web_develop/chapter12/section2/mycert.pem' c.NotebookApp.keyfile='/home/ubuntu/web_develop/chapter12/section2/mykey.key'
其中密码并不是明文存储的,而是通过如下命令获得的哈希字符串:
In : from notebook.auth import passwd In : passwd() Enter password: Verify password: Out: 'sha1:19c53926b1d7:6248a00119f231540f9ba294e2739858da82bba3'
这个例子中为了加密通信,使用了自建 SSL 证书,通过如下命令获得 pem 和 key 文件:
> openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mykey.key -out mycert.pem
现在只需要使用“jupyter notebook”启动就可以访问“https://127.0.0.1:5000”了。
Notebook 格式
Notebook 文档有自己的格式,事实上它是一个后缀为.ipynb 的 JOSN 文件,包含文本、源码、富媒体输出、Metadata 等类型的数据。我们通过上面的例子生成的 Notebook 文档分析一下 Notebook 格式。
顶级结构包含 cells、nbformat、nbformat_minor、metadata 等 4 个键:
{ "cells":[], "metadata":{ "kernelspec":{ "display_name":"Python 2", "language":"python", "name":"python2" }, "language_info":{ "codemirror_mode":{ "name":"ipython", "version":2 }, "file_extension":".py", "mimetype":"text/x-python", "name":"python", "nbconvert_exporter":"python", "pygments_lexer":"ipython2", "version":"2.7.6" }, "widgets":{ "state":{}, "version":"1.1.0" } }, "nbformat":4, "nbformat_minor":0 }
nbformat 和 nbformat_minor 表示 Notebook 格式版本,一般不需要担心不同版本间的兼容问题,JN 会提示你是否转换格式,在确认后会帮你转换。cells 列表中每个 cell 就是一个交互执行段。我们展示其中一个 Cell:
{ "cell_type":"code", "execution_count":null, "metadata":{ "collapsed":true }, "outputs":[], "source":[ "#%%writefile foo.py\n", "print 'Hello world'" ] }
cell_type 除了是 code 外还可以是 markdown 等类型,source 就是在 input 框内输入的内容,outputs 是执行的输出。
nbformat 现在也是一个独立的包,通过这样的 Notebook 文档就可以在任何地方生成 HTML 页面:
In : import nbformat In : nb=nbformat.read('/home/ubuntu/web_develop/chapter12/section2/Untitled.ipynb', as_version=4) In : nb['cells'][1]['source'] Out: u'%run foo' In : nb_v3=nbformat.convert(nb, 3) # 转换 V3 版本格式
Notebook 格式转换和预览
JN 支持把 Notebook 文档转换为其他格式的文档,Nbconvert 提供这样的转换方法。目前支持的常见格式如下:
- HTML
- LaTeX
- Markdown
- ReStructured Text
我们先安装它:
> pip install nbconvert
假如转换为 HTML,则执行如下命令:
> jupyter nbconvert --to html Untitled.ipynb
就会生成同名的 Untitled.html 文件了。
我们还可以定义转换的模板,nbconvert 默认使用了 full.tpl(http://bit.ly/1UScC88 )模板,模板引擎是 Jinja2,我们可以使用 Jinja2 语法基于它扩展新的模板:
> cat web_develop.tpl {%- extends 'full.tpl' -%} {% block footer %} FOOOOOOOOTEEEEER {% endblock footer %}
在转换的时候指定使用 web_develop.tpl 这个模板:
> jupyter nbconvert --to html --template web_develop.tpl Untitled.ipynb
如果你希望共享 ipynb 文件,可以将其上传到 Nbviewer(http://nbviewer.jupyter.org )网站上,这样就生成了在线的 HTML 页面。它的原理其实很简单,通过如下代码就可以实现:
In : from urllib import urlopen In : import nbformat In : from nbconvert import HTMLExporter In : response=urlopen('/path/tp/xxx.ipynb').read().decode() In : nb=nbformat.reads(response, as_version=4) In : html_exporter=HTMLExporter() In : html_exporter.template_file='basic' In : (body, resources)=html_exporter.from_notebook_node(nb)
其中 body 就是生成的 HTML 代码。如果不希望你的 JN 文档暴露到外网,可以在内部使用 nbviewer(https://github.com/jupyter/nbviewer )搭建生成静态 HTML 页面的服务。
为什么使用 RequireJS
JN 使用了 RequireJS 作为 JavaScript 文件和模块加载器。在网站发展的早期,JavaScript 代码并不多,完全可以写在一个文件里面,只要加载这一个文件就够了。但是随着业务发展,代码越来越多,就会把它拆分成多个文件,依次加载。通常采用如下的写法:
<script src="1.js"></script> <script src="2.js"></script> <script src="3.js"></script> ...
但是这样做有很大的缺点:
- 加载时浏览器会停止网页渲染,加载的文件越多,网页失去响应的时间就会越长。
- JavaScript 之间可能存在依赖关系,因此必须严格保证加载顺序(比如上例的 1.js 要在 2.js 的前面),当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
使用 RequireJS 就是为了解决这两个问题而诞生的,它能:
- 实现 JavaScript 文件的异步加载,避免网页失去响应。
- 管理模块之间的依赖性,便于代码的编写和维护。
在 Notebook 里使用 Echarts
Echarts 是百度开源的,功能强大、美观、图表丰富、兼容绝大多数浏览器,支持移动设备访问的纯 JavaScript 图表库。它和 Highcharts 以及 amCharts 是三种最常用的图表库。
笔者曾经分享过 Highcharts(http://bit.ly/1W2V9fM )的例子,本节就来使用 Echarts。首先通过 GitHub 的 API 获得 Django 项目的提交活动情况:
from collections import defaultdict from datetime import datetime import requests from IPython.display import HTML r=requests.get('https://api.github.com/repos/django/django/stats/commit_activity') series=defaultdict(int) monthname=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] for d in r.json(): month=datetime.fromtimestamp(d['week']).month series[month]+=d['total'] # 数据是按月分开的
由于 Echarts 和 Notebook 的加载机制有冲突,需要使用 require.config 配置路径:
HTML(''' <div id="chart" style="width: 600px; height:400px;"></div> <script> require.config({ paths:{ echarts: '//cdn.bootcss.com/echarts/3.0.0/echarts.min', } }); require(['echarts'], function(ec){ var myChart=ec.init(document.getElementById('chart')); var option={ title:{ text:'Last Year of commit activity', left:'center' }, subtitle:{ text:'https://github.com/django/django', }, xAxis:{ data:%s }, yAxis:{}, series:[{ name:'Commits', type:'line', data:%s }] }; myChart.setOption(option); }); </script> '''%(monthname, series.values()))
执行这个 Cell 的结果如图 12.4 所示。这样就方便地实现使用 Notebook 的图表展示了。
图 12.4 执行 Cell 的结果
富显示
Notebook 除了能展示 HTML 代码,还可以直接显示图片、链接等类型的内容,而且可以定制显示的效果。
直接显示图片时,还可以定义长和宽:
from IPython.display import display_html, Image, FileLink, FileLinks, HTML Image(filename='/tmp/dongxi.jpg', width='100px')
使用 FileLink 和 FileLinks 可以显示文件链接:
FileLink('rich-display.ipynb') FileLinks('/tmp')
Notebook 可以自动把表格用可视化的样式显示出来,如图 12.5 所示。
图 12.5 以可视化的样式显示表格
Pandas 的 DataFrame 对象也支持可视化显示,如图 12.6 所示。
图 12.6 DataFrame 对象也支持可视化显示
能用这样的方式显示出来是因为定义了_repr_html_方法:
In : df._repr_html_()
其实对任意对象添加这个方法都能自定义显示的方式:
class DictTable(dict): def _repr_html_(self): html=['<table>'] for key, value in self.iteritems(): html.append("<tr><td>{0}</td><td>{1}</td></tr>".format(key, value)) html.append("</table>") return ''.join(html) t=DictTable(a=1, b=2, c=4) display_html(t)
自定义 JavaScript 和 CSS 样式
Jupyter Notebook 提供了定制额外 JavaScript 代码和 CSS 样式的功能,代码都存在~/.jupyter/custom/目录下。我们先看自定义的样式文件 custom.css,它替换默认的 Notebook 的 Logo,隐藏一些不常用或者危险操作的选项:
#menubar .navbar{ visibility:hidden; } .btn-group{ visibility:hidden; } #cell_type{ visibility:hidden; } a[title="dashboard"]{ display:none; } #ipython_notebook{ background:url("/custom/dongxi.jpg") no-repeat scroll 0 0/100%auto rgba(0, 0, 0, 0); height:54px; width:120px; border-radius:3px; } .container.border-box-sizing.toolbar{ visibility:hidden; } #run_int{ visibility:visible; margin-left:-222px; }
需要注意,JN 4.0 之后自定义的静态文件访问的地址不再是/static/custom,而是/custom。看一下效果,如图 12.7 所示。
图 12.7 效果图
JN 的在线编辑器使用了开源的 CodeMirror,它自带支持 Emacs/VIM 的键盘绑定。现在我们定制使用 Emacs,修改 custom.js 的内容:
require(["base/js/events","base/js/namespace","notebook/js/cell", "codemirror/lib/codemirror","codemirror/keymap/emacs"], function(events, Jupyter, Cell, CodeMirror){ events.on('notebook_loaded.Notebook', function(){ var load_ipython_extension=function(){ var extraKeys=CodeMirror.keyMap.emacs; Cell.Cell.options_default.cm_config.extraKeys=extraKeys; Cell.Cell.options_default.cm_config.lineWrapping=true; var cells=Jupyter.notebook.get_cells(); var numCells=cells.length; for (var i=0;i<numCells;i++){ var theseExtraKeys=cells[i].code_mirror.getOption('extraKeys '); for (var k in extraKeys){ theseExtraKeys[k]=extraKeys[k]; } cells[i].code_mirror.setOption('extraKeys', theseExtraKeys); cells[i].code_mirror.setOption('lineWrapping', true); } }; return{ load_ipython_extension:load_ipython_extension, }; }); });
使用 nbextension 扩展 Notebook
IPython 有扩展系统,比如之前提到的内置的 autoreload、storemagic,以及外部需要额外安装的 cythonmagic 等。JN 也有自己的扩展系统,叫作 nbextension。通过扩展都会存放在~/.jupyter/nbextensions 目录下。最知名的扩展项目就是 IPython-notebook-extensions。我们先下载它:
> git clone https://github.com/ipython-contrib/IPython-notebook-extensions
拷贝 nbextensions 目录到 Jupyter 配置目录下:
> cp -rp IPython-notebook-extensions/nbextensions/ ~/.jupyter > cp -rp IPython-notebook-extensions/nbextensions/config/ ~/.jupyter/nbextensions > mkdir ~/.jupyter/extensions > cp -rp IPython-notebook-extensions/extensions/nbextensions.py ~/.jupyter/extensions
在 custom.js 中添加希望自动加载的插件:
Jupyter.load_extensions('usability/chrome_clipboard');
给 jupyter_notebook_config.py 添加如下配置:
import os import sys from jupyter_core.paths import jupyter_config_dir, jupyter_data_dir sys.path.append(os.path.join(jupyter_data_dir(), 'extensions')) c=get_config() ... c.NotebookApp.extra_template_paths=[os.path.join(jupyter_data_dir(), 'templates') ] c.NotebookApp.server_extensions=['nbextensions']
启动 Notebook 之后可以访问“https://127.0.0.1:5000/nbextensions”配置插件。
打开 Notebook 页面就可以在浏览器终端可以看到如下的输出:
load_extensions ["jupyter-js-widgets/extension","usability/chrome-clipboard/main"] utils.js:36 Loading extension:usability/chrome-clipboard/main utils.js:36 Loading extension:jupyter-js-widgets/extension extension.js:88 loaded widgets
我们就可以使用这些扩展提供的功能了。扩展的功能和使用方法详见项目的 Wiki 页面。
在 Notebook 上使用并行计算
可以直接在 Notebook 里使用并行计算功能,但是需要先安装 ipyparallel,然后启动集群插件:
> ipcluster nbextension enable
先创建一个集群用的配置:
> ipython profile create mycluster --parallel
访问“https://localhost:5000/tree#ipyclusters”或者切换到“IPython Clusters”这个 Tab 上就可以启动集群,而不需要用命令行管理了,单击 mycluster 后面显示为“Start”的按钮,集群就会启动。如果在 # of engines 的输入框中未指定启动的进程数,会默认启动与逻辑 CPU 个数相同数目的进程,如图 12.8 所示。
图 12.8 默认启动与逻辑 CPU 个数相同数目的进程
现在就可以在终端或者 Notebook 上连接这个集群了:
import ipyparallel as ipp c=ipp.Client(profile='mycluster')
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论