返回介绍

Jupyter Notebook

发布于 2025-04-20 18:52:17 字数 14461 浏览 0 评论 0 收藏

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
  • PDF
  • 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')

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。