【问题标题】:is there a way to read the contents of the last jupyter markdown cell as a string?有没有办法将最后一个 jupyter markdown 单元格的内容作为字符串读取?
【发布时间】:2021-12-23 18:34:28
【问题描述】:

我正在使用 jupyter 和 pandas read_sql,这很好用但看起来很难看。

例如我有一个查询:

选择 * FROM table_a 作为 限制 10 个;

我可以在降价单元格中很好地展示它:

``` mysql
SELECT *
FROM table_a AS a
LIMIT 10; 
```

我可以像这样在代码单元中执行它:

 pd.read_sql('SELECT * FROM table_a AS a LIMIT 10;', conn)

这涉及复制/粘贴并显示两次查询(如果我只想将笔记本导出为 pdf 报告,那就不太好)

有没有办法通过将markdown文本读入字符串python变量或任何其他方式来避免重复?

【问题讨论】:

标签: jupyter-notebook markdown


【解决方案1】:

@Micah Kornfield 在问题 cmets 中引用的 cellmagic 答案可能非常适合许多情况。然而,在这个问题中,据说避免重复是可取的。假设 SQL 很大,我们不想多次看到同一个查询。

不幸的是,现在是 2021 年,没有简单的解决方案。在 jupyter notebook 中有两个世界,后端是内核,在我们的例子中运行 python,前端运行 javascript。只有 javascript 才能看到降价单元格。可以让后端和前端相互通信,这些方法通常有点hacky,但无论如何我们都会依赖其中的一些。

我编写了一个脚本,它以两种不同的方式完成我们的工作,这可能会带来相似的结果。我将这些方法称为文件读取方法和 javascript 方法。

首先,请将以下文件markdown.py 保存在与 ipython 相同的文件夹中(我们使用单独的文件,因为您指定您的笔记本最终将进入报告,并且不希望将此脚本与笔记本):

from IPython.display import Javascript
from urllib.parse import unquote
from json import loads as jsonloads

def markread(cellnumber,notebookname=None,callbackvar=None):
    try:
        if type(cellnumber) is int:# maybe check if (varname in globals()):
            if callbackvar is not None and type(callbackvar) is str:
                return Javascript("const mdtjs = Jupyter.notebook.get_cells().filter(c=>c.cell_type==\"markdown\")["+str(cellnumber)+"].get_text(); IPython.notebook.kernel.execute(\"mdtp = unquote('\"+encodeURI(mdtjs)+\"');mdtp=mdtp[mdtp.find('\\\\n',mdtp.find('```'))+1:min(mdtp.rfind('\\\\n'),mdtp.rfind('```'))].strip();"+callbackvar+"=mdtp;del mdtp\");")
            if notebookname is not None and type (notebookname) is str:
                if not notebookname.endswith('.ipynb'):
                    notebookname += '.ipynb'
                with open(notebookname) as f:
                    j = jsonloads(f.read())
                mdts = [''.join(c['source'][1:]).strip().strip('`').strip() for c in j['cells'] if c['cell_type']=='markdown']
                return mdts[cellnumber]
    except:
        return None
    return None

现在回到笔记本,要加载脚本,你必须导入它:

from markdown import markread, unquote

使用javascript方法需要取消引用,否则可以跳过。

1。文件读取方式:

用法:

marktext = markread(2, notebookname='mynotebookname')

这里marktext 将从mynotebookname 中的第三个降价单元格中获取值(第三个,因为我们生活在一个零索引的世界中,所以 2 表示第三个;如果您跳过 notebookname 中的“.ipynb”扩展名在这种情况下,它将自动附加)。重要 - 此方法读取写入磁盘上的笔记本文件,而不是事物的热状态。如果您在上次保存后更改了任何内容,则可能会出错。

2。 Javascript方法:

用法:

markread(1, callbackvar='marktext')

在这里,我们将第二个降价单元格的值写入一个名为 marktext 的变量中。 Javascript 方法比较复杂——它是异步的,所以我们必须发送我们想要写入的变量的名称(必须是表示其名称的字符串,而不是变量本身)。重要的是还要知道markread 必须是单元格中的最后一个命令,因为 javascript 调用存在限制。

工作原理

在内部,file read 方法只是读取 json 格式的 notebook 文件,从 'cells' 中选择值并过滤掉那些是 markdown 的。

然而,javascript 方法更复杂。它调用 JS,因为 JS 可以访问包括 markdown 在内的单元格,因此 JS 读取单元格值(来自 Jupyter.notebook.get_cells),过滤 markdown 单元格,调用 python 并发回那些 markdown 单元格 - url 编码。那些编码的单元被解码并分配给callbackvar。在这两种方法中,我做了一些关于修剪单元格值(``` 和空格)的开始和结束可能不正确的假设。

有一些方法可以改进代码,例如让它自动检测文件读取方法的笔记本名称,但它涉及更多黑客,再次依赖 javascript 获取笔记本名称或调用 api端口 8888,但必须处理会话密码。我相信我们的脚本已经涵盖了最重要的部分。如果一种方法不起作用,您可能还会使用另一种方法。

【讨论】:

  • markread 工作了一次,然后停止工作 - 知道我做错了什么吗?
  • 两种方法都停止工作了吗?您尝试读取文件了吗?
猜你喜欢
  • 2018-08-13
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多