采用网络标准
我们开发当前Notebook电脑Web应用程序的主要原因之一是采用了Web技术。
通过使用HTML、JavaScript和CSS作为纯Web应用程序,Notebook电脑可以免费获得所有Web技术的改进。因此,随着浏览器对不同媒体的支持的扩展,Notebook网络应用程序应该能够在不进行修改的情况下兼容。
随着JavaScriptVM速度的提高,用户界面的性能也是如此。
仅使用Web技术的另一个优点是,最终用户可以完全访问接口的代码,并且可以实时修改。即使这项任务并不总是简单的,我们也努力使代码尽可能地可访问和可重用。这应该允许我们以最小的努力开发定制Web界面行为的小扩展。
篡改Notebook应用程序
您可以使用的第一个工具是浏览器“开发人员工具”。确切的命名可能会随着浏览器的不同而改变,可能需要安装扩展。但基本上,它们允许您检查/修改DOM,并与运行前端的JavaScript代码交互。
在Chrome和Safari中,开发人员工具在菜单中
View > Developer > JavaScript Console
在Firefox中,您可能需要安装 Firebug
这些将是您调试和尝试不同扩展方法的最好朋友。
注射JS
使用魔法
上面的工具在编辑长的javascript文件时可能很繁琐。因此,我们提供 %%javascript
魔术。这允许您快速将javascript注入到Notebook中。不过,以这种方式注入的javascript在重新加载后仍然无法生存。因此,它是一个测试和精炼脚本的好工具。
你可能会看到这里或那里有人通过读取文件并将其发布到Notebook中来修改CSS和向Notebook中注入JS。这不仅经常打断Notebook的流程,使Notebook的重新执行中断,而且还意味着每次需要更新代码时,都需要在整个Notebook中执行这些单元格。
这在某些情况下仍然有用,例如 %autosave
可以控制每次保存之间的时间的魔法。但是可以用一个javascript下拉菜单替换它来选择保存间隔。
[ ]:
## you can inspect the autosave code to see what it does.
%autosave??
custom.js
为了注入javascript,我们提供了一个入口点: custom.js
允许用户执行其他资源并将其加载到Notebook中。javascript代码输入 custom.js
将在Notebook应用程序启动时执行,然后可用于自定义用户界面和Notebook行为中的几乎任何内容。
custom.js
可以在 ~/.jupyter/custom/custom.js
. 您可以与其他人共享您的custom.js。
回到理论
[ ]:
from jupyter_core.paths import jupyter_config_dir
jupyter_dir = jupyter_config_dir()
jupyter_dir
自定义JS在
[ ]:
import os.path
custom_js_path = os.path.join(jupyter_dir, 'custom', 'custom.js')
[ ]:
# my custom js
if os.path.isfile(custom_js_path):
with open(custom_js_path) as f:
print(f.read())
else:
print("You don't have a custom.js file")
注意 custom.js
是指由用户修改。在编写脚本时,可以在单独的文件中定义它,并将一行配置添加到 custom.js
这将获取并执行文件。
警告 :即使修改 custom.js
浏览器刷新后立即生效(除非浏览器缓存具有攻击性)。 创建 一个文件 static/
目录需要 服务器重新启动 .
练习:
创建一个
custom.js
在正确的位置,包含以下内容:
alert("hello world from custom.js")
重新启动服务器并打开任何Notebook。
受到custom.js的欢迎
看一看 default custom.js ,以查看其内容和更多解释。
对于快速的:
我们在上面已经看到,你可以改变自动保存率使用魔术。这通常是我不想每次都键入的内容,而且我不喜欢将其嵌入到我的工作流和文档中。(读者不在乎我的自动保存时间是多少)。让我们构建一个允许我们这样做的扩展。
在工具栏(dom)中创建下拉元素 Jupyter.toolbar.element
)你需要
Jupyter.notebook.set_autosave_interval(milliseconds)
知道1分=60秒,1秒=1000毫秒
var label = jQuery('<label/>').text('AutoScroll Limit:');
var select = jQuery('<select/>')
//.append(jQuery('<option/>').attr('value', '2').text('2min (default)'))
.append(jQuery('<option/>').attr('value', undefined).text('disabled'))
// TODO:
//the_toolbar_element.append(label)
//the_toolbar_element.append(select);
select.change(function() {
var val = jQuery(this).val() // val will be the value in [2]
// TODO
// this will be called when dropdown changes
});
var time_m = [1,5,10,15,30];
for (var i=0; i < time_m.length; i++) {
var ts = time_m[i];
//[2] ____ this will be `val` on [1]
// |
// v
select.append($('<option/>').attr('value', ts).text(thr+'min'));
// this will fill up the dropdown `select` with
// 1 min
// 5 min
// 10 min
// 10 min
// ...
}
首先是一个非交互式示例
我喜欢我的赛马拉松被很好的强调
Jupyter.config.cell_magic_highlight['magic_text/x-cython'] = {}
Jupyter.config.cell_magic_highlight['magic_text/x-cython'].reg = [/^%%cython/]
text/x-cython
是codemirror模式名称, magic_
前缀将只是修补模式,以便包含魔术的第一行不会破坏突出显示。 reg
将触发模式更改的列表或正则表达式。
获取更多文档
遗憾的是,您必须读取JS源文件(但是有很多注释)和/或使用yuidoc构建JavaScript文档。如果你有 node
和 yui-doc
安装:
$ cd ~/jupyter/notebook/notebook/static/notebook/js/
$ yuidoc . --server
warn: (yuidoc): Failed to extract port, setting to the default :3000
info: (yuidoc): Starting YUIDoc@0.3.45 using YUI@3.9.1 with NodeJS@0.10.15
info: (yuidoc): Scanning for yuidoc.json file.
info: (yuidoc): Starting YUIDoc with the following options:
info: (yuidoc):
{ port: 3000,
nocode: false,
paths: [ '.' ],
server: true,
outdir: './out' }
info: (yuidoc): Scanning for yuidoc.json file.
info: (server): Starting server: http://127.0.0.1:3000
浏览http://127.0.0.1:3000获取文档
一些方便的方法
通过浏览文档,您将看到我们有一些方便的方法,使我们能够避免每次重新发明UI:
Jupyter.toolbar.add_buttons_group([
{
'label' : 'run qtconsole',
'icon' : 'fa-terminal', // select your icon from
// http://fontawesome.io/icons/
'callback': function(){Jupyter.notebook.kernel.execute('%qtconsole')}
}
// add more button here if needed.
]);
用一个 lot of icons 您可以从中选择。
单元元数据
最需要的功能通常是能够区分Notebook中的单个单元格,或者对其执行特定操作。为此,您可以使用 Jupyter.notebook.get_selected_cell()
或依赖 CellToolbar
. 这允许您注册一组将附加到单个单元格的操作和图形元素。
单元工具栏
您可以看到通过切换 Cell Toolbar
在Notebook顶部工具栏中的选择器。它提供两个默认值 presets
那是 Default
和 slideshow
. 默认值允许用户手动编辑附加到每个单元格的元数据。
首先,我们定义一个函数,它首先在DOM上使用一个元素作为参数,在其中注入ui元素。第二个元素是这个元素WIS注册的单元。然后我们需要注册这个函数并给它一个名称。
注册回调
[ ]:
%%javascript
var CellToolbar = Jupyter.CellToolbar
var toggle = function(div, cell) {
var button_container = $(div)
// let's create a button that shows the current value of the metadata
var button = $('<button/>').addClass('btn btn-mini').text(String(cell.metadata.foo));
// On click, change the metadata value and update the button label
button.click(function(){
var v = cell.metadata.foo;
cell.metadata.foo = !v;
button.text(String(!v));
})
// add the button to the DOM div.
button_container.append(button);
}
// now we register the callback under the name foo to give the
// user the ability to use it later
CellToolbar.register_callback('tuto.foo', toggle);
注册预设
此函数现在可以是许多函数的一部分 preset
单元格工具栏的。
[ ]:
%%javascript
Jupyter.CellToolbar.register_preset('Tutorial 1',['tuto.foo','default.rawedit'])
Jupyter.CellToolbar.register_preset('Tutorial 2',['slideshow.select','tuto.foo'])
您现在应该可以访问两个预设:
教程1
教程2
并检查您定义的按钮在切换预设时是否共享状态。另外,请检查单击按钮时是否修改了单元格的元数据,以及在重新加载时保存元数据时是否仍然可用。
练习:
尝试将所有代码包装在一个文件中,将此文件放入 {{jupyter_dir}}/custom/<a-name>.js
并添加
require(['custom/<a-name>']);
在里面 custom.js
使此脚本自动加载到所有Notebook中。
require
is provided by a JavaScript library 这允许你表达依赖性。对于与前一个扩展类似的简单扩展,我们直接将全局命名空间设为静音,但对于更复杂的扩展,可以将回调传递给 require([...], <callback>)
调用,允许用户将配置信息传递给插件。
在python语言中,
require(['a/b', 'c/d'], function( e, f){
e.something()
f.something()
})
可以理解为
import a.b as e
import c.d as f
e.something()
f.something()
例如,见@damianavila “ZenMode” plugin :
// read that as
// import custom.zenmode.main as zenmode
require(['custom/zenmode/main'],function(zenmode){
zenmode.background('images/back12.jpg');
})
为了最快的
尝试使用 the following 将下拉列表绑定到 cell.metadata.difficulty.select
.
它应该能够取以下4个值:
<None>
Easy
Medium
Hard
我们将使用它根据每个单元格上的标记自定义已转换Notebook的输出。
[1]:
# %load soln/celldiff.js
[ ]: