如何在Jupyter笔记本/JupyterLab中更改单个单元格的背景颜色?

19

我设计了一个笔记本,让用户可以改变的变量分组到笔记本的不同单元格中。我想使用不同的背景颜色突出显示这些单元格,以便用户知道在哪里调节。

我该如何实现这个功能?

NB: 这个相关问题 是关于静态代码高亮(用于手册),而且被接受的答案建议基本上把所有内容放在标记注释中。在我的情况下,我希望突出显示的代码在一个可运行的单元格中。


使用小部件来设置这些变量怎么样?这样用户就完全不需要触碰代码了。 - SergiyKolesnikov
不是一个坏主意,但我认为这并不等同。我的理解是小部件更多地存在于交互空间,而在这里我想改变配置变量。如果一个变量对应于长计算的参数,我希望在计算过程中此参数不会改变,并向用户明确说明。我个人会坚持使用小部件进行即时交互反馈(通常通过%interac)。 - P-Gn
1
您可以禁用在计算开始时用于设置配置变量的小部件。这样,您将防止用户更改变量,并表示这些值当前正在计算中使用,无法更改。 - SergiyKolesnikov
值得考虑。谢谢! - P-Gn
4个回答

25

这里是(假设您使用Python核心):

from IPython.display import HTML, display

def set_background(color):    
    script = (
        "var cell = this.closest('.jp-CodeCell');"
        "var editor = cell.querySelector('.jp-Editor');"
        "editor.style.background='{}';"
        "this.parentNode.removeChild(this)"
    ).format(color)
    
    display(HTML('<img src onerror="{}" style="display:none">'.format(script)))

然后按照以下方式使用:

set_background('honeydew')

这个解决方案有点巧妙,但我很希望看到一个更加优雅的解决方案。 演示:

在此输入图片描述

在 Firefox 60 和 Chrome 67 中使用 JupyterLab 0.32.1 进行测试。

如果想要将其作为单元格魔法,你可以简单地执行以下操作:

from IPython.core.magic import register_cell_magic

@register_cell_magic
def background(color, cell):
    set_background(color)
    return eval(cell)

然后像这样使用它:

%%background honeydew
my_important_param = 42

1
请使用“set_background('')”来禁用着色。 - krassowski
1
这似乎在新版本上不再起作用了(已测试使用jupyter笔记本服务器:6.0.0,Chrome浏览器:76.0.3809.132)。 - martin-martin
这仅适用于代码单元格,因为%%background不适用于标记单元格。 - yoonghm
5
对于 Jupyter notebook v6+,请使用以下代码: script = ( "var cell = this.closest('.code_cell');" "var editor = cell.querySelector('.input_area');" "editor.style.background='{}';" "this.parentNode.removeChild(this)" ).format(color) display(HTML(''.format(script)))``` 注意:翻译后的代码与原始代码的意思相同,但可能不会保留精细的技术细节。 - psychemedia
1
这个函数很棒!魔法几乎可以使用——它可以给单元格上色,但会抑制该单元格中的任何print()输出。有没有办法让魔法允许看到print()语句(或任何其他单元格输出)? - MJoseph
显示剩余8条评论

2
如果您只需要更改使用nbconvert转换的单元格的颜色,请在您的文件夹中创建一个模板mytemplate.tpl并添加以下内容:

{% extends 'full.tpl'%}
{% block any_cell %}
{% if 'highlight' in cell['metadata'].get('tags', []) %}
    <div style="background:lightpink">
        {{ super() }}
    </div>
{% else %}
    {{ super() }}
{% endif %}
{% endblock any_cell %}

(从官方 文档 改编)

... 然后将标签“highlight”添加到您的单元格中。在 Jupyter lab 中,您可以在选定的单元格左侧执行此操作: enter image description here

现在,使用模板将笔记本转换为 nbconvert:

jupyter nbconvert --to html 'mynb.ipynb' --template=mytemplate.tpl

生成的 HTML 将如下所示:

enter image description here

我发现这很适合向读者突出显示特定单元格。

2

对于 krassowski 的代码,我有一个小的补充(试图将其作为评论添加,但无法使格式正常显示)。

from IPython.core.magic import register_cell_magic
from IPython.display import HTML, display

@register_cell_magic
def bgc(color, cell=None):
    script = (
        "var cell = this.closest('.jp-CodeCell');"
        "var editor = cell.querySelector('.jp-Editor');"
        "editor.style.background='{}';"
        "this.parentNode.removeChild(this)"
    ).format(color)

    display(HTML('<img src onerror="{}">'.format(script)))

这样你就可以将它作为魔法和普通函数调用两种方式来使用:
bgc('yellow')
bla = 'bla'*3

或者

%%bgc yellow
bla = 'bla'*3

这个魔法似乎会抑制单元格中print()和其他输出(就像krassowski的答案中一样)。然而,该函数运行正常。你知道怎么在使用这个魔法时允许这些输出吗? - MJoseph

1

以下是我在 jupyter-notebook (v6.3.0) 和 jupyter-nbconvert --to=html (v6.0.7) 中使用的有效方法。

它与 @krassowski 和 @Gabe 的答案有两个不同之处:

  1. 交互式笔记本使用类名 .cell.input_area,但 nbconvert HTML 使用 .jp-CodeCell.jp-Editor.highlight。这段代码可以处理所有这些情况。

  2. 我更喜欢 "line magic" 而不是 "cell magic",因为 "line magic" 不会改变单元格其余部分的计算结果。

from IPython.core.magic import register_line_magic
from IPython.display import HTML, display
import json

@register_line_magic
def bg(color, cell=None):    
    script = (
        "var n = [this.closest('.cell,.jp-CodeCell')];"
        "n = n.concat([].slice.call(n[0].querySelectorAll('.input_area,.highlight,.jp-Editor')));"
        f"n.forEach(e=>e.style.background='{color}');"
        "this.parentNode.removeChild(this)"
    )
    display(HTML(f'<img src onerror="{script}" style="display:none">'))  

%bg yellow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接