日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

給你的 R Shiny debug 必看指南

 微笑如酒 2019-04-13

Finding your bug is a process of confirming the many things that you believe are true — until you find one which is not true.

—Norm Matloff

又到了 kaopubear 的專欄時間,本文較長圖多,真誠建議滑到文末 閱讀原文 體驗更加。閱讀更多內(nèi)容,也歡迎 閱讀原文 移步我的博客。


第一次接觸網(wǎng)頁開發(fā)是兩三年前的事,那時我曾經(jīng)問過計劃帶我入門前端的前輩:入門前端的標(biāo)準(zhǔn)是什么。他當(dāng)時用一種極平和的語氣和我說:學(xué)會dubug。幾年后的今天我即便也寫過一點網(wǎng)頁工具,但還是依然沒能入門。反思一下:一是 JavaScript 學(xué)的不好,二就是不敢說自己有多少 debug 的能力。

遂放棄。

最近因為需要又要涉及一點網(wǎng)頁工具開發(fā),同時因為需求整體和 R 交互比較多于是決定用 R 的 Shiny 來搞一搞。

寫了一個多星期我感覺 Shiny 確實解決了不熟悉前后端交互的人寫網(wǎng)頁的大多數(shù)問題,但如何 debug 的門檻還是擺在那里。比如前幾天一個高手和我吐槽寫 Shiny 時不知道改了什么突然不能正確運行了,更糟心的是還沒有任何報錯信息。當(dāng)然,后來經(jīng)過討論發(fā)現(xiàn)其實并非沒有報錯信息,只是那時他沒有找到而已。

這篇文章就結(jié)合最近學(xué)習(xí)的一點資料,大致聊聊在 Shiny 中 debug 的一些方法。

Shiny debug 主要有三個步驟,分別是調(diào)試(Debugging),追蹤(Tracing)和錯誤處理(Error handling)

  • Debugging: 所謂的調(diào)試就是猜,然后在你認(rèn)為可能有錯誤的地方設(shè)置一個斷點,再執(zhí)行接下來每個語句的時候就都可以檢查程序當(dāng)時所在的狀態(tài)。

  • Tracing:可以在運行程序的時候收集程序運行產(chǎn)生的信息而無需暫停程序,在診斷系統(tǒng)性問題時因為我們無法頻繁的中斷使用這一方式就比較合適。

  • Error handling: 在客戶端和服務(wù)器端找到錯誤的來源并確定原因。

Debugging 調(diào)試

breakpoints 斷點

說到「斷點」,我不由的想對 bug 說一句:

靜靜地陪你走了好遠(yuǎn)好遠(yuǎn),連眼睛紅了都沒有發(fā)現(xiàn)。

如果你知道哪一行的代碼有錯(這話本身就像bug)或者猜測很可能是哪里不對,就可以直接在所在行設(shè)置一個斷點。Rstudio 只需在行號左邊點一下鼠標(biāo)就會出現(xiàn)紅點提示標(biāo)記成功。開始運行 Shiny 程序后會在斷點處停止執(zhí)行,然后就可以開始逐步執(zhí)行進(jìn)行代碼調(diào)試了。

如上圖所示,我們在 40 和 41 行設(shè)置了兩個斷點,現(xiàn)在點擊 Run App,代碼運行會在 40 行處停下,綠色的箭頭指向 41 行,并且在 console 中會有 browse輸出,如下圖所示

這個時候我們可以方便的查看環(huán)境中已有的變量,例如這里已經(jīng)運行完畢的 x 變量。如果想繼續(xù)運行,可以點擊 console 里的 continue,程序又會向下運行。

現(xiàn)在環(huán)境中存在 x 和 bin 兩個變量,同時在 console 的 browse[2]> 處你可以進(jìn)行正常的 R 操作,例如查看變量內(nèi)容或者做個加法運算,甚至你可以修改當(dāng)前存在環(huán)境中的變量(當(dāng)然不推薦這么操作)。

說到缺點,目前 breakpoints 只可以在 Rstudio IDE 中使用,而且只能用于ShinyServer函數(shù)中;另外如果代碼很長顯然不停的斷點也很煩,同時它只能顯示發(fā)生了什么但是無法告訴你為什么有些事情沒有發(fā)生。

小結(jié)如下:

browser() 命令

其實從上面 console 的截圖也可以看到,斷點就是執(zhí)行了一次類 browser() 操作。但和斷點不同的是,browser() 本身可以被寫到任何地方。寫法如下圖所示:

說明:你現(xiàn)在從簡書看到的為本文的付費版本,如果需要可以付費繼續(xù)閱讀。當(dāng)然,完整的文章可以在我的個人博客免費閱讀,歡迎繼續(xù)查看。

甚至你還可以把 browser() 寫進(jìn)判斷語句中,只在某些特定的情況下執(zhí)行。例如下圖所示,在 input 中的 bins 小于 40 時候程序會正常的執(zhí)行,當(dāng)大于 40時才會自動停下,然后你就可以在調(diào)試器中查看具體的變量等信息。

小結(jié)如下

Tracing 追蹤

在許多情況下通過暫停執(zhí)行來找問題比較困難,相反需要我們在程序運行時觀察系統(tǒng)。對于 Shiny 的程序尤其如此,因為他不像 R 腳本那樣線性運行。

Showcase Mode

Shiny 在啟動時,runAPP() 有一個選項默認(rèn)是讀取配置文件中的設(shè)置,它就是 display.mode。如果我們設(shè)置為display.mode='showcase',在 Showcase 模式下,代碼將與應(yīng)用程序一起顯示,并且程序的 server 端代碼在執(zhí)行時會出現(xiàn)黃色的閃爍進(jìn)行提醒。這一功能對于可視化哪些部分代碼正在執(zhí)行非常有用。

如果想要默認(rèn)開啟這一功能,可以在該 Shiny 目錄下創(chuàng)建一個 DESCRIPTION 文件并寫入如下內(nèi)容:

DisplayMode: Showcase
Type: Shiny

小結(jié)如下

Reactive Log

在 Shiny 中經(jīng)常會用到響應(yīng)對象,當(dāng)開啟 Reactive Log 之后,程序運行時除了可以告訴你正在執(zhí)行哪些響應(yīng)之外,日志還可以幫助你可視化展示響應(yīng)對象之間的依賴關(guān)系。在開啟一個新的 R session 時首先配置 options(Shiny.reactlog=TRUE),然后在 Shiny app 中通過 Ctrl + F3 就可以啟動可視化的 Reactive Log 文件,也可以在運行Shiny 后使用 showReactLog 查看。詳細(xì)信息可以在 官方文檔 了解。

打印 tracing

在各種編程語言中,一個萬變不離其宗的調(diào)試技巧就是不停的輸出。在 PHP 里面是不停的 echo,在 R 里可以不停的 cat。使用 cat 可以幫助你在不終止程序的情況下查看變量值。在 Shiny 中,最好的方式是打印標(biāo)準(zhǔn)錯誤(stderr())。

# generate bins based on input$bins from ui.R
x    <- faithful[, 2
bins <- seq(min(x), max(x), length.out = input$bins + 1)
cat(file=stderr(), 'drawing histogram with', input$bins, 'bins''\n')

進(jìn)行上述修改后,運行 Shiny 每次調(diào)整 input 都會在 console 中打印輸出。如下圖所示

小結(jié)如下

Shiny Server 進(jìn)行 tracing

如果你的程序運行在 server 端而非本地,每次 Shiny 程序運行都會生成 log 文件,默認(rèn)的路徑是 /var/log/Shiny-server/*.log,而這一位置是可以在配置文件中通過log_dir進(jìn)行修改的。如果程序運行沒有出現(xiàn)問題,每次 Shiny 運行結(jié)束后文件會自動刪除,如果報錯了則會一直存在于 log 目錄等你去寵幸。log 文件的命名格式為<application directory name>-YYYMMDD-HHmmss-<port number or socket ID>.log 。

客戶端和服務(wù)器端 Tracing

一個 Shiny 程序包括 client (瀏覽器) 和 server (R 進(jìn)程) 兩部分。這兩者通過 websocket連接,websocket 接收來自客戶端的狀態(tài),例如輸入控件新的賦值,同時發(fā)布來自服務(wù)器端的狀態(tài)更改,例如新的輸出。在一些比較復(fù)雜的情況下,你可以通過打開 trace 來跟蹤 JSON 格式的 websocket 內(nèi)容。

如上圖所示,在輸出內(nèi)容中,SEND 表示從瀏覽器發(fā)送到 R session 的數(shù)據(jù);RECV 表示從 R session 發(fā)送到瀏覽器的數(shù)據(jù)。

這一部分目前還沒有實際用到,理解到位了可以再寫一些。

Errors 錯誤

跑程序最怕看到的就是報錯,但是真要有問題了最希望看到的就是明確的報錯。

R 報錯

在 Shiny 中大多數(shù)報錯信息都是由R引起的,在 0.13.0 之后的 Shiny 版本中已經(jīng)有了比較直觀的報錯形式,會直接給出哪里的程序出現(xiàn)了錯誤。這里首先人為引入一個報錯,當(dāng) input 大于 40 的時候停止程序并且拋出 too many bins 的報錯信息。

運行程序后調(diào)整輸入如果錯誤,可以觀察 console 的輸出內(nèi)容:

首先直接觀察顏色不同的部分,直接告訴我們 app.R 的 43 行代碼出現(xiàn)了問題。在報錯部分,每一行內(nèi)容前都有一個數(shù)字,例如1,82,165和167,其表示的是在調(diào)用棧(call stack)中的索引,可以看到這個例子中有接近170個調(diào)用棧。

JavaScript errors

目前 Shiny 有很多第三方 JavaScript 組件,有時如果使用上面幾種方式都沒有定位到錯誤相關(guān)問題或者沒有看到報錯信息,很可能是 JavaScript 中發(fā)生錯誤導(dǎo)致程序出現(xiàn)了bug。畢竟 Shiny 是個網(wǎng)頁應(yīng)用,各種和用戶的交互少不了 JavaScript 的使用。

要進(jìn)行 JavaScript 的調(diào)試在 Rstudio 就不靈了。如果你是通過 Rstudio 打開了一個單獨 Shiny 頁面,可以通過右鍵單擊 Shiny頁面,選擇Inspect element 進(jìn)入 JavaScript console;如果你的 Shiny 頁面是open in browser,也就是在瀏覽器中打開的,可以直接通過F12進(jìn)入開發(fā)者模式打開 JavaScript console 。

在 Shiny 中 UI 的每個部分都會有一個 id 參數(shù),這個 id 對應(yīng)的參數(shù)在瀏覽器中解析之后就是對應(yīng)著 HTML 標(biāo)簽中的 id。在 HTML 中,這個 id 是必須唯一(區(qū)別于name)。因此,在Shiny的ui中每一個id參數(shù)也必須唯一。解析效果如下圖所示:

如果你不小心在 UI 中寫入了兩個一樣的 id,在上圖中就有兩個標(biāo)簽的 id 都是 a,程序運行后在 Rstudio 并不會拋出什么錯誤,但是在 Shiny 頁面端的各種操作就進(jìn)行不了。如果不在開發(fā)者模式下進(jìn)行調(diào)試只能通過各種方法在 Rstudio 進(jìn)行測試,但是如果打開 JavaScript 的 console,就會看到其實已經(jīng)給出了明確的報錯信息。

當(dāng)然,Chrome 開發(fā)者工具的用法是在太多,這也是我在文章開頭提到的自己入門不了前端的原因之一。如果在你的 Shiny 中用到了大量 JavaScript 相關(guān)內(nèi)容,或者需要定制很多 CSS 相關(guān)的內(nèi)容,可以學(xué)習(xí)一下官方的開發(fā)者工具文檔。

至此,也就簡單的寫完了 R Shiny debug 的三個主要步驟,其中提到的每一個用法在實際使用中都需要進(jìn)一步深入學(xué)習(xí)。當(dāng)然,每一個方法用到的頻率也各有不同,可以根據(jù)個人的實際情況進(jìn)行后續(xù)的練習(xí)。

One more thing:shinyjs

寫到這里本來文章就可以結(jié)束了,但是似乎總有哪里不對。

為什么在 Rstudio 的 console 里就不能查看 JavaScript 的 log 信息。要知道 Rstudio GUI 本身使用的就是 QT框架,其中的很多部分都可以理解為一個網(wǎng)頁。從維基百科或者它自己的說明中都可以看出這一點。

不信的話你也可以在 Rstuido 的每個 pane 里右擊然后選擇Inspect element看看會出現(xiàn)什么,比如在 Console 中右擊

你會看到下面圖所示的內(nèi)容

既然如此,沒有理由不去解決這個不方便的問題。其實在 R 中有一個專門為 Shiny 提高 JavaScript 使用體驗開發(fā)的R包,叫做shinyjs。這個包的存在讓 Shiny 使用 JavaScript 變得強大和高效了很多。其中針對調(diào)試有兩個專門的函數(shù)。

showLog

Print any JavaScript console.log() messages in the R console, to make it easier and quicker to debug apps without having to open the JavaScript console.

這個函數(shù)類似于 JavaScript 中的console.log(),它可以把 JavaScript console 的信息顯示在R console 中而不需要再打開專門的 JavaScript console。

logjs

Print a message to the JavaScript console (mainly used for debugging purposes).

這個函數(shù)則可以把信息輸出到 JavaScript console 中方便進(jìn)行調(diào)試。

例如下面一段代碼:

library(ShinyJavaScript)

if (interactive()) {
    library(Shiny)
    ShinyApp(
        ui = fluidPage(
            useShinyJavaScript(),  # Set up ShinyJavaScript
            actionButton('btn''Click me')
        ),
        server = function(input, output) {
            observeEvent(input$btn, {
                # Change the following line for more examples
                logJavaScript(R.Version())
            })
        }
    )
}

運行后通過點擊 button ,就可以把 R.Vsrsion() 的信息輸出到 JavaScript console 中,如下圖所示:


嗯,先寫到這里吧。

我的學(xué)習(xí)材料

  • Chrome開發(fā)者工具

  • Debugging Shiny applications

  • Debugging with RStudio

  • shinyjs



    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多