今天一早看到沈雕墨老师给 SQLFlow 贡献的一个 pull request。感觉非常有意思。跟大家分享一下。
SQLFlow 和命令行客户端
SQLFlow 扩展 SQL 语法。其中一个扩展是
SELECT ... TO EXPLAIN aTrainedModel USING TreeExplainer;
当用户执行这样一条语句的时候,SQLFlow 会调用 SHAP 图示化地解释一个训练好的模型 aTrainedModel。SHAP 的输出是一个 PNG 图像。SQLFlow 通常的用户界面是 Jupyter Notebook,它可以显示图片,如 SQLFlow 主页上的动图展示的。截图如下:
SQLFlow 还有一个命令行界面,类似 MySQL 的 mysql 命令。沈雕墨老师的这个 pull request 使得这个命令行工具在执行上述扩展语法的语句时,也可以展示 SHAP 输出的图片。不过要求 terminal 程序能支持显示图片。沈雕墨老师尝试了 macOS 自带的 Terminal.app,发现支持的图像颜色不多。最好用 iTerm2。
(等下回抓一个好看一点儿的图)
OSC 编码
为了能 review 沈雕墨老师的 code,我也学习了一下 iTerm 的展示图片的能力:
Images - Documentation - iTerm2 - macOS Terminal Replacementwww.iterm2.com基本原理是
iTerm2 extends the xterm protocol with a set of proprietary escape sequences. In general, the pattern is:
ESC]1337;key=value^G
上述1337被称为一个OSC code,全称是 operating system command terminal control sequences,是用来控制 terminal 的行为的。比如,在几乎任何 terminal 窗口里输入如下命令,可以利用 OSC code 0 来修改窗口标题为“唉呀妈呀”。
printf "033]0;唉呀妈呀a"
判断 iTerm2
上述 OSC code 1337 不是每个 terminal 程序都支持的。SQLFlow 需要知道自己是不是运行在 iTerm2 里,才能决定是否输出图片,还是应该只是打印一个指向图片的 URL。
为此,可以下载和运行这个 shell 脚本 https://github.com/gnachman/iterm2-website/blob/master/source/utilities/it2check
在 iTerm2 里运行它,结果是0(表示是 iTerm2)。
$ source ./it2check ; echo $?
0
在 Terminal.app 里运行它,结果是1(表示不是 iTerm2)。
$ source ./it2check ; echo $?
1
展示图片
在 iTerm2 里要展示一个图像文件,可以用脚本 imgcat。下载之后,在 iTerm2 里运行下述命令即可。
./imgcat a.png
这个命令干了什么呢?仔细读一读源码,发现它向标准输出打印了如下内容
033]1337;File=name=图像文件名;size=图像大小;inline=0:图像内容(Sixel编码);a
我以前没有用过 Sixel 图像格式,所以查了一下 Wikipedia,原来是一种把图像编码成 ASCII 序列的编码方式。
写一个 Go 程序来展示图片
知道关键是输出 Sixel 格式的图像给 iTerm,那么用任何语言写一个程序,向标准输出写一个 Sixel 格式的图像文件,即可在 iTerm2 里显示图片了。这样我也就理解沈雕墨老师的 pull request 了。为了方便大家了解,我简化这个 pull request 成如下命令行程序 imgcat.go:
package main
import (
"image"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"log"
"os"
"github.com/mattn/go-sixel"
)
func main() {
img, _, err := image.Decode(os.Stdin)
if err != nil {
log.Fatalf("Cannot decode image from stdin: %v", err)
}
err = sixel.NewEncoder(os.Stdout).Encode(img)
if err != nil {
log.Fatalf("Cannot encode image into sixel format: %v", err)
}
}
在 iTerm2 里运行如下命令,即可显示一个图像文件 a.png
cat a.png | go run imgcat.go