這是針對(duì)今天找 bug 的記錄丰捷。
我在日常更改 sigminer 手冊(cè)后使用 knitr 生成網(wǎng)頁(yè)文檔時(shí)發(fā)現(xiàn)一直報(bào)錯(cuò):
Quitting from lines 42-43 (sigminer-doc.Rmd)
Error in png::readPNG(path, native = TRUE, info = TRUE) :
file is not in PNG format
這個(gè)報(bào)錯(cuò)源自于我使用了 knitr::include_graphics()
插入 png 圖片病往。圖片來(lái)自一篇自然綜述停巷,用于介紹 Mutation Signatures。
之前我也遇到過(guò)這種報(bào)錯(cuò),后來(lái)莫名其妙好了庆揪,我也就沒(méi)管了。今天不知道為什么又出現(xiàn)這種情況吝羞,所以還是自動(dòng)動(dòng)手想辦法解決吧钧排。
在 RStudio 的 code chunk 運(yùn)行中均澳,我是能正常看到預(yù)覽的圖片的糟袁,按理來(lái)說(shuō)沒(méi)有問(wèn)題系吭。我又試著使用 png::readPNG()
直接在控制臺(tái)讀入一張 png 圖片(這是一個(gè)重點(diǎn))肯尺,出現(xiàn)了跟報(bào)錯(cuò)無(wú)關(guān)的警告,但能夠正常讀入槐臀。這就奇怪了水慨。敬扛。啥箭。
我試著使用 debug()
函數(shù)后再運(yùn)行 knit,這樣可以跳入報(bào)錯(cuò)代碼急侥,按逐步運(yùn)行確實(shí)有出現(xiàn)了上述的報(bào)錯(cuò)贝润!
我依稀想起來(lái)之前重裝 knitr
包好像解決了問(wèn)題铝宵,我又重裝 knitr
,還是報(bào)錯(cuò)胧卤。
面對(duì)這個(gè)重復(fù)的報(bào)錯(cuò)拼岳,我越想越偏惜纸,我看到 png
包在讀入數(shù)據(jù)時(shí)底層應(yīng)該是調(diào)用了 C(++) 代碼耐版,難道是 png 包問(wèn)題粪牲?我重裝它還是沒(méi)解決,我又試著安裝源碼包落君,還是有問(wèn)題绎速。纹冤。。
真是奇怪购公,不可能存在兩份代碼萌京,我 knitr 外不報(bào)錯(cuò),而在 knitr 使用時(shí)報(bào)錯(cuò)宏浩。想不明白的我暫時(shí)把問(wèn)題扔到了 Stack overflow https://stackoverflow.com/questions/61721837/cannot-use-include-graphics-to-insert-png-in-rmarkdown-error-file-is-not-in-pn枫夺,吃飯去吧。
吃飯回來(lái)休息后打開(kāi)一開(kāi)發(fā)現(xiàn)有一回答:
I think that the issue might be where your Rmd is located
這個(gè)回答我內(nèi)心覺(jué)得不對(duì)绘闷,因?yàn)槲乙恢笔窃?Rmd 所在目錄進(jìn)行 knit 的橡庞,之前我使用 knitr
也沒(méi)遇到這方面問(wèn)題。不過(guò)如果真是這樣呢印蔗?還是試試吧扒最。
緊接著問(wèn)題來(lái)了,我發(fā)現(xiàn)在 knit 的過(guò)程中我是無(wú)法在控制臺(tái)看到輸出的华嘹!這該怎么辦呢吧趣?强挫?搜解決辦法。
通過(guò)谷歌我找到 2 種比較靠譜的方法來(lái)查看 knit 時(shí)使用的根目錄絮爷。
第一種是根據(jù) knitr
進(jìn)行設(shè)定:
knitr::opts_knit$set(root.dir = rprojroot::find_rstudio_root_file())
這樣就把 knit 時(shí)候的根目錄跟 RStudio 使用的根目錄保持一致了。但還是報(bào)錯(cuò),而且這里我無(wú)法查看到底根目錄是什么跨释。
第二種方法的來(lái)源鏈接我忘了阔涉,是在 Stack overflow 上贯要,我做了一點(diǎn)小的修改:
knitr::knit_hooks$set(debug = function(before, options, envir) {
if (!before) {
envir = as.list(envir)
message("Objects: ", paste(names(envir), collapse = " "))
for (i in names(envir)) {
if (!startsWith(i, ".")) {
message(
i, " = ", envir[[i]]
)
}
}
}
})
加入這段代碼后我就可以在 code chunk 的設(shè)定中加 debug = TRUE
,然后將 rprojroot::find_rstudio_root_file()
和 getwd()
的結(jié)果賦值給變量跟狱,knit 的時(shí)候會(huì)提示變量信息叼丑。
Objects: workdir root.dir
workdir = /Users/wsx/Documents/GitHub/sigminer-doc
root.dir = /Users/wsx/Documents/GitHub/sigminer-doc
|..... | 4%
ordinary text without R code
|...... | 5%
label: unnamed-chunk-3 (with options)
List of 2
$ echo : logi FALSE
$ fig.cap: chr "The illustration of SBS signature, fig source: https://www.nature.com/articles/nrg3729"
Quitting from lines 64-65 (sigminer-doc.Rmd)
Error in png::readPNG(path, native = TRUE, info = TRUE) :
file is not in PNG format
從輸出來(lái)看 Rmd 的工作目錄是完全沒(méi)有問(wèn)題的店雅。那問(wèn)題到底在哪里呢闹啦?酱畅?看著 file is not in PNG format
這個(gè)錯(cuò)誤提示,我久久不能釋?xiě)阉槲桑€是要搞掉它。
目前我在這個(gè)文檔中我引入了外部 3 張 png 圖片,我一個(gè)一個(gè)讀取試試。
我 Ca,怎么有失敗的。
> png::readPNG("fig/sbs_signature_overview.png")
[ reached getOption("max.print") -- omitted 3 matrix slice(s) ]
Warning message:
In png::readPNG("fig/sbs_signature_overview.png") :
libpng warning: iCCP: known incorrect sRGB profile
> png::readPNG("fig/sbs_signature_overview_nat_review.png")
Error in png::readPNG("fig/sbs_signature_overview_nat_review.png") :
file is not in PNG format
恍然大悟,之前我讀取正常的并不是我 knit 引起報(bào)錯(cuò)的。因?yàn)樗鼈兌际?png 文件扯俱,所以我覺(jué)得沒(méi)什么不同晴玖,也就沒(méi)有額外注意。
既然格式不對(duì)尔当,那就得想辦法知道報(bào)錯(cuò)圖片的格式侠碧。我試了下 jpeg::readJPEG()
瓷式,發(fā)現(xiàn)還是報(bào)錯(cuò)。這樣搞不行妒挎,鬼知道有多少種圖片格式鳞芙,得找個(gè)工具喳坠。
接著我找到了正確的工具 magick
御板。
一查,報(bào)錯(cuò)圖片還真不是 png 格式:
> error_file = magick::image_read("fig/sbs_signature_overview_nat_review.png")
> print(error_file)
format width height colorspace matte filesize density
1 WEBP 685 521 sRGB FALSE 18390 72x72
原來(lái)我以為網(wǎng)絡(luò)圖片另存為 .png 就成了 png 圖片惶楼。。铝穷。镊尺。
最后還是通過(guò)這個(gè)工具轉(zhuǎn)換生成一張 png 格式的,從根本上解決了問(wèn)題:
> right_png <- magick::image_convert(error_file, "png")
> right_png
format width height colorspace matte filesize density
1 PNG 685 521 sRGB FALSE 0 72x72
> magick::image_write(right_png, path = "fig/sbs_signature_overview_nat_review2.png", format = "png")
那么問(wèn)題又來(lái)了衣式,為什么使用在 RStudio 中使用 knitr::include_graphics()
預(yù)覽是正常的呢?在寫(xiě)到這里的時(shí)候瓮具,我突然想到預(yù)覽時(shí) knitr
應(yīng)該不是調(diào)用的 png
進(jìn)行讀取搭综,所以沒(méi)有報(bào)錯(cuò)条获。
現(xiàn)在回想起來(lái)有點(diǎn)想罵自己沒(méi)腦子帅掘,有兩個(gè)點(diǎn)如果注意了吱窝,我不會(huì)花這么多時(shí)間:
- 測(cè)試
png
讀取時(shí)應(yīng)該使用報(bào)錯(cuò)的圖片照激。 - 認(rèn)真理解報(bào)錯(cuò)信息六水。
但作為一個(gè)人,往往難以客觀準(zhǔn)確高效地看清問(wèn)題本質(zhì)咧欣。另一方面說(shuō),沒(méi)有愚蠢的操作轨帜,我也不會(huì)想盡辦法各種深挖魄咕,事后寫(xiě)篇文章記錄下了。
程序不會(huì)錯(cuò)蚌父,錯(cuò)的是我們的思維哮兰;bug 不可怕,可怕的它生出一堆 bugs(剛好看到 Y 叔今日推文)苟弛。