面向产品经理的Emacs教程:15. 在Org mode里用纯文本画图

· 2975字 · 6分钟

1 课程回顾 🔗

在上节课里,我们学习了如何在Org mode里写代码块,通过Org mode的代码块,我们可以实现「文学编程」,让写代码变成一件很有意思的事。这对于非程序员而言,更为重要,因为经验、编程能力、编程思想,非程序员和程序员之间相比,有比较大的鸿沟,而非程序员编写程序往往是为了实现一些简单快速的需求,使用代码块,一边写思路,一边写代码就非常适合。

今天我们来学习如何在Org mode里通过纯文本画图。

2 概述 🔗

作为产品经理,我们在很多时候需要画很多图:架构图、业务时序图、流程图、项目甘特图、脑图、类图等等,以往我们画这些图,要么通过微软的 Visio 软件,要么通过Mac下的 OmniGraffle 软件,要么通过 ProcessOn 这类SaaS软件等等。所有这些手段都是类似的方式,就是通过鼠标拖拉拽的方式,尽管很多软件做了优化,比如拖拉的时候能自动对齐,画连接线的时候也能自动链接,但还是不够方便。

此时,我们可以来看看在Emacs里如何画图的?相比上述的这些方式,在Emacs的Org mode里画图的最大不同在于,你只需要关注你的内容,而不需要去关注格式,不需要关注「画」这个动作。下面,我们来逐步介绍如何实现。

3 画图的语言 🔗

在Emacs的Org mode里,我们可以有很多画图语言的选择,比较知名的有:

就我个人使用下来的情况,我比较推荐的是 plantuml ,主要是它支持的图形种类最多:

这样基本上我们只需要学会 plantuml 的语法,就能够画出我们工作中需要的所有类型的图了,非常划算。

4 PlantUML绘图 🔗

4.1 PlantUML的安装和配置 🔗

我们首先来安装和配置 plantuml

  1. 需要提前通过 brew install plantuml 安装 plantuml 这个软件包
  2. 配置Emacs和Org mode支持 plantuml
(use-package plantuml-mode
  :ensure t
  :mode ("\\.plantuml\\'" . plantuml-mode)
  :init
  ;; enable plantuml babel support
  (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
  (org-babel-do-load-languages 'org-babel-load-languages
                               (append org-babel-load-languages
                                       '((plantuml . t))))
  :config
  (setq org-plantuml-exec-mode 'plantuml)
  (setq org-plantuml-executable-path "plantuml")
  (setq plantuml-executable-path "plantuml")
  (setq plantuml-default-exec-mode 'executable)
  ;; set default babel header arguments
  (setq org-babel-default-header-args:plantuml
        '((:exports . "results")
          (:results . "file")
          ))
  )

我们安装配置完 plantuml 后,可以在org文件里,输入下面的代码块,然后光标移动到代码块内部,按下 C-c C-c 执行代码块, plantuml 就会自动解析文本执行,并生成你想要的图片啦:

4.2 PlantUML各种图形的示例 🔗

下面仅仅介绍产品经理平常工作中会用到的画图类型,更全的图形类型、语法和示例,请参考 plantuml官网

4.2.1 时序图 🔗

时序图是我们经常画的图,我们常常来描述业务流程的时候通过时序图来描述,下面是一个时序图的例子:

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_135944.png :width 400 :exports both
@startuml
!theme materia                             /' 设定主题 '/
scale 2                                    /' 设定图片的清晰度 '/

Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication request
Alice <-- Bob: Another authentication response

@enduml
#+END_SRC

4.2.2 类图 🔗

我们用来描述类、实例、关系的时候常常会用到类图。

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_151217.png :width 800 :exports both
@startuml
!theme materia
scale 2
skinparam componentStyle rectangle
class Class
class ClassExpression
class IRI
class Entity
class ObjectProperty
class DataProperty
class AnnotationProperty
class Datatype
class DataRange {
        arity: UnlimitedNatural
        }
class NamedIndividual
class Individual
class AnonymousIndividual {
        nodeID: String
        }
class Literal {
        lexicalFrom: String
        }

Class -up-|> ClassExpression
Class -up-|> Entity
ObjectProperty -up-|> Entity
DataProperty -up-|> Entity
AnnotationProperty -up-|> Entity
Datatype -up-|> Entity
Datatype -up-|> DataRange
NamedIndividual -up-|> Entity
NamedIndividual -up-|> Individual
AnonymousIndividual -up-|> Individual
Entity -left-> IRI
Literal -up-> Datatype

Note bottom of Datatype: The arity of a datatype muse be one.
@enduml
#+END_SRC

4.2.3 组件图 🔗

我们可以通过组件图来画产品的架构、技术架构等。

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_151535.png :width 400 :exports both
@startuml
!theme materia
scale 2
skinparam componentStyle rectangle

package "Some Group" {
  HTTP - [First Component]
  [Another Component]
}

node "Other Groups" {
  FTP - [Second Component]
  [First Component] --> FTP
}

cloud {
  [Example 1]
}


database "MySql" {
  folder "This is my folder" {
    [Folder 3]
  }
  frame "Foo" {
    [Frame 4]
  }
}


[Another Component] --> [Example 1]
[Example 1] --> [Folder 3]
[Folder 3] --> [Frame 4]

@enduml
#+END_SRC

4.2.4 活动图 🔗

我们可以通过活动图来画一些偏程序向的流程图。

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_151804.png :width 400 :exports both
@startuml
!theme materia
scale 2
skinparam componentStyle rectangle

start
if (Graphviz 已安装?) then (yes)
  :处理所有\n绘制任务;
else (no)
  :仅处理
  __时序图__ 和 __活动__ 图;
endif
stop

@enduml
#+END_SRC

4.2.5 甘特图 🔗

我们在项目管理的时候,可以通过甘特图来展示项目的现状。

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_151940.png :width 400 :exports both
@startgantt
!theme materia
scale 2

[Prototype design] lasts 15 days
[Test prototype] lasts 10 days

Project starts 2020-07-01
[Prototype design] starts 2020-07-01
[Test prototype] starts 2020-07-16

@endgantt
#+END_SRC

4.2.6 思维脑图 🔗

思维脑图也是产品经理经常用到的工具,我们可以通过思维脑图来整理思路。下面这个例子是我们在 第5课:改变Emacs样貌 - 前言 写的思维脑图:

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_170342.png :width 400 :exports both
@startmindmap
!theme materia
scale 2

+ 系列教程
++ 1.Emacs初识
+++ Emacs安装启动
+++ Emacs配置文件
+++ Emacs配置文件
+++ Emacs基本快捷键
++ 2.Org mode初识
+++ Org mode的语法
+++ Org mode的快捷键@endmindmap
++ 3.通过Org mode来管理配置文件
+++ Org babel tangle
+++ tangle第一个配置文件early-init.el
++ 4.Emacs的包管理器
+++ package.el
+++ 安装use-package插件
+++ 安装quelpa插件

@endmindmap
#+END_SRC

4.2.7 JSON结构 🔗

我们还可以通过 plantuml 来展示JSON结构:

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_170915.png :width 600
@startjson
!theme materia
scale 2

{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 27,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null
}
@endjson
#+END_SRC

4.2.8 简单的原型 🔗

我们甚至可以通过 plantuml 来实现一些简单的原型图:

#+BEGIN_SRC plantuml :file 在Orgmode里用纯文本画图.assets/uml_20230115_171130.png :width 400 :exports both
@startsalt
!theme materia
scale 2

{
        Just plain text
        [This is my button]
        () Unchecked radio
        (X) Checked radio
        [] Uncheck box
        [X] Checked box
        "Enter text here    "
        ^This is a droplist^
}
@endsalt
#+END_SRC

5 gnuplot绘图 🔗

我们还可以使用 gnuplot 来画一些数学相关的图。

  1. 先通过 brew install gnuplot 安装 gnuplot
  2. 安装配置 Emacs的gnuplot插件
(use-package gnuplot
  :ensure t
  :mode ("\\.gp$" . gnuplot-mode)
  :init
  (add-to-list 'org-src-lang-modes '("gnuplot" . gnuplot))
  (org-babel-do-load-languages 'org-babel-load-languages
                               (append org-babel-load-languages
                                       '((gnuplot . t))))
  :config
  ;; (add-to-list 'auto-mode-alist '("\\.gp$" . gnuplot-mode))
  (setq org-babel-default-header-args:gnuplot
      '((:exports . "results")
        (:results . "file")))
  )

我们安装完 gnuplot 后,可以通过它来画图:

#+BEGIN_SRC gnuplot :file 在Orgmode里用纯文本画图.assets/gnuplot_20230115_173519.png :width 400
f(x) = x**2
plot f(x)
#+END_SRC

6 Lilypond乐谱绘图 🔗

我在学习一些类似「小星星」这种乐谱的时候,会尝试将他们记录下来,放到Emacs里,这个应该算是个小众的需求,我也用的不深,但我非常喜欢这种方式。

  1. 先通过 brew install lilypond 安装 lilypond
  2. brew install mactex-no-gui 安装 mactex-no-gui
(use-package lilypond-mode
  :ensure nil
  :mode ("\\.i?ly\\'" . LilyPond-mode)
  :init
  (add-to-list 'org-src-lang-modes '("lilypond" . lilypond))
  ;; add support for org babel
  (org-babel-do-load-languages 'org-babel-load-languages
                               (append org-babel-load-languages
                                       '((lilypond . t))))
  ;; set lilypond binary directory
  (setq org-babel-lilypond-ly-command "/usr/local/bin/lilypond -dpreview")
  :config
  ;; trim extra space for generated image
  (defun my/trim-lilypond-png (orig-fun
                               &optional arg
                               info
                               param)
    (when (member (car (org-babel-get-src-block-info)) '("lilypond"))
      (let ((ly-file (alist-get :file (nth 2 (org-babel-get-src-block-info)))))
        (let ((ly-preview-file (replace-regexp-in-string "\\.png" ".preview.png" ly-file)))
          (when (file-exists-p ly-preview-file)
            (shell-command (concat "mv " ly-preview-file " " ly-file)))
          (org-redisplay-inline-images)))))
  (advice-add 'org-babel-execute-src-block :after #'my/trim-lilypond-png)
  (setq ob-lilypond-header-args
        '((:results . "file replace")
          (:exports . "results")
          ))
  )

配置完 lilypond-mode 后,我们就可以通过 lilypond 代码块记录乐谱啦:

\relative

\new Staff
{
  \clef treble
  \key c \major
  \time 4/4

  \override Lyrics.LyricSpace #'minimum-distance = #1.0

  c'4 c g' g
  a a g2
  f4 f e e
  d d c2
  g4' g f f
  e e d2
  g4 g f f
  e e d2
  c4 c g' g
  a a g2
  f4 f e e
  d d c2

  \bar "|."
}

% \addlyrics {
%   Twin -- kle, twin -- kle, lit -- tle star, how I won -- der what you are!
%   Up a -- bove the sky so high, like a dia -- mond in the sky.
%   Twin -- kle, twin -- kle, lit -- tle star, how I won -- der what you are!
% }

\addlyrics {
  一 闪 一 闪 亮 晶 晶, 满 天 都 是 小 星 星。
  挂 在 天 上 放 光 明, 好 像 许 多 小 眼 睛。
  一 闪 一 闪 亮 晶 晶, 满 天 都 是 小 星 星。
}

7 结语 🔗

通过今天的学习,我们了解了如何在Emacs里通过Org mode的 plantuml, gnuplot, lilypond 等代码块来画各种图。这种方式体现了Emacs一个非常棒的思想,那就是「文本即一切」!换句话说「内容即一切」!

这节课的配置文件的快照见:emacs-config-l15.org

你也可以在 这里 查看最新的配置文件。