Org mode is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system.
Org-mode
类似于 Markdown
, 但是远胜于 Markdown
。
曾有小伙伴说过, Org-mode
是 Markdown
的封神模式, 个人觉得这话一点不夸张,
相比较而言, Markdown
只是一套简洁的文档格式, 而 Org-mode
除了涵盖作为文档格式的简洁之外,
还可用于记笔记,维护 TODO 列表, 工程管理,以及可用于元编程。
对于元编程的支持请阅读我之前的译文, Babel: org-mode的元编程。
所谓的元编程,即是 Org-mode
搭建了一个多语言可以交互执行的环境, 在这个环境中,可选用各语言的特性,来分解执行一个大型任务。
<img src="/images/babel-fish.jpg” />
The Babel Fish is small, yellow, and simultaneously translates from
one spoken language to another.
– The Hitchhiker’s Guide to the Galaxy, Douglas Adams
Org-mode
对于比较流行的语言都有很好的支持,
而且对于新语言,也可以很容易添加支持,本人就给两种语言添加过支持。
本文章主要讲述 Org-mode
对于 Python
源代码块的支持,
Python
相当的流行, 所以在 Org-mode
中被很完美的支持。
Org-mode
中的 Python
源代码块可用于定义函数、过滤器和数据分析、创建图表以及生成可重现的研究论文。
1 配置
这里假设 Python
的开发环境已配置完毕,若是还没配置,请自行google。
Org-mode
已内置在新的 Emacs 中,但是默认情况下, 只有 emacs-lisp
可被执行。
要启用或禁用其他语言, 可通过 Emacs 自定义交互界面来配置 org-babel-load-languages
变量,
或者将代码添加到 init
文件中, 启用python的代码如下所示:
1 | (org-babel-do-load-languages |
2 Org-mode对于Python源码块的支持
2.1 头参数
2.2 Sessions
python完全支持 session
模式,包括命名 session
。
在 session
模式下,代码块都运行在同一个长时间运行的 python
的交互式解释器 session
中,就像你在交互式 python
键入的一样。
可以拥有多个 session
,而且它们是完全相互独立。
session
可用于定义函数,设置变量和在源块之间共享代码。
python中的 session
模式与 non-session
模式略有不同,因为在 session
模式下, 你正在与单个“交互式” python session
交互。
在 python
的交互模式中,空行是特殊的:它们表示缩进代码块的结束, 所以会写出一些稍微不同的 python
代码。
另外,在 non-session
模式下,python代码块将被包装在一个函数中, 所以要返回一个值( :result value mode
),你必须使用一个return语句。
在 session
模式下, python
代码由解释器直接评估,而不是在一个函数的上下文中,
最后一个语句的值将被自动返回,因此不能使用 return
语句。
2.2.1 Session mode
# blank lines not OK in indented blocks, and don't use return() # Source block is passed directly to interactive python; # value is value of _ at end. #+begin_src python :session def foo(x): if x>0: return x+1 else: return x-1 foo(1) #+end_src #+RESULTS: : 2
2.2.2 Non-session mode
# blank lines OK in indented blocks, and use return() # Entire source block will get indented and used as the body of main() #+begin_src python def foo(x): if x>0: return x+1 else: return x-1 return foo(5) #+end_src #+RESULTS: : 6
最后,如果你使用 matplotlib
的图形功能,同时使用 seesion
模式,
必须显式设置后端, 例如 PDF , PNG 或其他文件导出后端。 见下面示例:
#+begin_src python :session :results file import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt fig=plt.figure(figsize=(3,2)) plt.plot([1,3,2]) fig.tight_layout() plt.savefig('images/myfig.pdf') 'images/myfig.pdf' # return this to org-mode #+end_src #+RESULTS: [[file:images/myfig.pdf]]
3 使用示例
- Hello World!
#+begin_src python :results output print "Hello, world!" #+end_src #+RESULTS: : Hello, world!
- 参数
#+NAME: square #+BEGIN_SRC python :var num=5 def square(x): return x*x return square(num) #+END_SRC #+RESULTS: square : 25 #+CALL: square(num=10) #+RESULTS: : 100
- 文学编程
#+NAME: square #+BEGIN_SRC python def square(x): return x*x #+END_SRC #+NAME: calc-square #+BEGIN_SRC python :var num=5 :noweb strip-export :results output <<square>> print(square(num)) #+END_SRC #+RESULTS: calc-square : 25 #+CALL: calc-square(num=7) #+RESULTS: : 49
- 内联调用(Inline calling):
2 加 2 等于 src_python{return(2+2)}
当导出 HTML 或者 LaTeX/PDF 时,如下所示:
2 加 2 等于 4
- 使用Org-mode的table作为参数
#+tblname: data_table | a | 1 | | b | 2 | | c | 3 | #+begin_src python :var val=1 :var data=data_table # Return row specified by val. # In non-session mode, use return to return results. return(data[val]) #+end_src #+RESULTS: | b | 2 |
- 绘图
#+begin_src python :results file import matplotlib, numpy matplotlib.use('Agg') import matplotlib.pyplot as plt fig=plt.figure(figsize=(4,2)) x=numpy.linspace(-15,15) plt.plot(numpy.sin(x)/x) fig.tight_layout() plt.savefig('../images/python-matplot-fig.png') return '../images/python-matplot-fig.png' #+end_src #+RESULTS: [[file:../images/python-matplot-fig.png]]
<img src="/images/python-matplot-fig.png” />
- 词云
#+BEGIN_SRC python :preamble "# -*- coding: utf-8 -*-" :results value file import jieba.analyse from wordcloud import WordCloud, ImageColorGenerator import numpy as np from PIL import Image import random font_path = '../resource/tyzkaishu.ttf' width = 640 height = 480 text = open('../resource/xiyouji.txt').read() words = jieba.analyse.extract_tags(text, topK=200, withWeight=True) word_freqs = {} for word in words: word_freqs[word[0]] = word[1] mask = np.array(Image.open('../resource/stormtrooper_mask.png')) wordcloud = WordCloud( font_path=font_path, width=width, height=height, mask=mask).generate_from_frequencies(word_freqs) wordcloud.to_file('../images/xiyouji-mask.png') return '../images/xiyouji-mask.png' #+END_SRC #+RESULTS: [[file:../images/xiyouji-mask.png]]
<img src="/images/xiyouji-mask.png” />
4 前方预警
当把 utf-8
的字符串传给 Python
, 需要格外小心。
4.1 传递utf-8字符串到Python
#+NAME: unicode_str #+BEGIN_EXAMPLE “this string is not ascii!” #+END_EXAMPLE
#+NAME: error-in-passing-var #+BEGIN_SRC python :var data=unicode_str return data #+END_SRC
#+RESULTS: error-in-passing-var
上面代码不会生成任何输出, 并在 *Org-Babel Error Output*
的缓冲区中打印以下消息:
File “<stdin>”, line 3 SyntaxError: Non-ASCII character ‘\xe2’ in file <stdin> on line 3, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)