Autocomplete Demo
71 | 108 | 109 |Press ctrl-. to activate autocompletion. Built
110 | on top of the show-hint
111 | and javascript-hint
112 | addons.
├── source ├── video.md ├── code.md ├── people.md ├── science.md ├── article.md ├── hardware.md ├── preface.md ├── software.md ├── pdffooter.htm ├── focus.md ├── md0.js ├── Makefile ├── convert.exe ├── mimetex.exe ├── tex2img.bat ├── title.md ├── metadata.xml ├── editor.md ├── header.htm ├── footer.htm ├── license.md ├── reflink.md9 ├── article5.md ├── focus1.md ├── article2.md ├── home.md ├── article6.md ├── info.md ├── article1.md ├── article7.md ├── article4.md ├── focus3.md ├── article3.md ├── focus4.md └── focus2.md ├── img ├── R.jpg ├── JsLab.jpg ├── Octave.jpg ├── SciPy.jpg ├── azure1.jpg ├── azure2.jpg ├── azure3.jpg ├── azure4.jpg ├── azure5.jpg ├── azure6.jpg ├── azure7.jpg ├── azure8.jpg ├── cover.jpg ├── vis3D.jpg ├── visNet.jpg ├── c3chart.jpg ├── coverA4.png ├── JsLabCurve.jpg ├── JsLabHist.jpg ├── JsLabPlot.jpg ├── jsLabC3Graph.jpg ├── JsLabIntelliSense.jpg └── CodeMirrorJsComplete.jpg ├── book ├── A4.pdf ├── A4.epub ├── ipad.epub └── ipad.pdf ├── submit └── 利用 SQL Compact Edition 免費建立擁有 DataBase 的 Azure Websites.doc ├── README.md ├── htm ├── code.html ├── hardware.html ├── people.html ├── science.html ├── software.html ├── preface.html ├── video.html ├── article.html ├── discuss.html ├── video1.html ├── focus.html ├── title.html ├── editor.html ├── license.html ├── article5.html ├── focus1.html ├── discuss1.html ├── home.html ├── article6.html ├── info.html ├── article2.html ├── article1.html ├── article7.html ├── article4.html ├── focus3.html ├── article3.html ├── focus4.html └── focus2.html └── css └── pmag.css /source/video.md: -------------------------------------------------------------------------------- 1 | # 影音頻道 2 | -------------------------------------------------------------------------------- /source/code.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/people.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/science.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/article.md: -------------------------------------------------------------------------------- 1 | # 程式人文集 2 | 3 | -------------------------------------------------------------------------------- /source/hardware.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/preface.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 3 | 4 | -------------------------------------------------------------------------------- /source/software.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/pdffooter.htm: -------------------------------------------------------------------------------- 1 |
# 影音頻道
17 |# 影音頻道
17 |# 影音頻道
17 |# 影音頻道
17 |# 影音頻道
17 |本期的「程式人雜誌」探討的焦點是我在建構 JsLab 這個「JavaScript 的科學計算平台」上所採用的開放原始碼專案,以及建構這個專案過程中所學到的一些經驗與心得,透過這樣的心得分享,或許可以讓「程式人」對科學計算與開放原始碼的使用有更多的瞭解也說不定。
23 |---- (「程式人雜誌」編輯 - 陳鍾誠)
24 |本雜誌許多資料修改自維基百科,採用 創作共用:姓名標示、相同方式分享 授權,若您想要修改本書產生衍生著作時,至少應該遵守下列授權條件:
23 |另外、當本雜誌中有文章或素材並非採用 姓名標示、相同方式分享 時,將會在該文章或素材後面標示其授權,此時該文章將以該標示的方式授權釋出,請修改者注意這些授權標示,以避免產生侵權糾紛。
28 |例如有些文章可能不希望被作為「商業性使用」,此時就可能會採用創作共用:姓名標示、非商業性、相同方式分享 的授權,此時您就不應當將該文章用於商業用途上。
29 |最後、懇請勿移除公益捐贈的相關描述,以便讓愛心得以持續散播!
30 |什麼叫記憶體衛生處理?讓我們先看個故事再做說明。
23 |阿誠是某高科技公司的工程師,他負責 使用儀器量測新產品實驗數據,有位同事阿堅和他很要好,常常去實驗室找他聊天,其實阿堅是另一家公司派來長期臥底的間諜,專門探詢公司最新研發的產品。公司有一台極輕巧的溫度監控儀,阿誠常使用它對新產品零件溫度監控,實驗完畢後,資料當然改存到電腦中,並且依據儀器說明書上,資料清除步驟清資料。一天阿堅向阿誠借用這儀器,其實他是把儀器拿給儀器駭客進行逆向工程,去解碼原始實驗資料。
24 |從這故事,你學到了什麼?有許多科技公司對資訊安全非常在意,連清理資料也要徹底破壞!
25 |大家都知道在 電腦上刪除檔案,只不過是把檔案搬移到資源回收筒,隨時可以檔案還原,稍微注意的人,還會清除資源回收筒的檔案,更高竿的會再進行衛生處理,徹底洗掉不要的資料。
26 |一般資料庫,清除資料的做法是破壞資料索引,簡單的說,利用一個索引指示有多少資料在資料庫中,如果索引為N,表示有N筆資料在其中,使用者可以循序用指令將資料取出。當索引為零時,也表示資料庫資料清除。這方法雖然快速簡單,可是欠缺資料安全性,為避免上述事件發生,除了一般清除,還要另外設計徹底清除功能。換個例子說明,也就是上完廁所,除了擦屁股,沖水之外,不要忘記馬桶順便刷一刷洗一洗,徹底做個衛生處理。
27 |很多人都曾經使用過「科學計算軟體」,特別是對於進行學術研究的人員而言,這些軟體可以說是不可或缺的。
23 |在工程領域,最常被使用的科學計算軟體是 MatLab,這個軟體從「矩陣運算」出發,建構出了龐大的函式庫,讓使用者可以輕易的透過 Matlab 進行電腦實驗。
24 |另外、在社會科學與統計學領域,很多人會用 SPSS、SAS 等軟體做統計分析,這兩個軟體是從統計出發的科學計算工具。
25 |事實上、開放原始碼領域也有對應的科學計算軟體,像是 R 與 Octave 都是 Open Source 的科學計算軟體。
26 |
圖、Octave 軟體的官方網站
28 |R 與 SPSS、SAS 的出發點較類似,是從機率統計領域開始建構的,而 Octave 則完全模仿 Matlab 的語法,試圖建構一個與 Matlab 語言相容的科學計算平台,讓 Matlab 的程式資源也可以被 Octave 社群所使用。
30 |
圖、R 軟體的官方網站
32 |在開源的科學計算軟體中, R 軟體 的使用者似乎是最多的,但是由於 R 採用的程式語言 S3 並非 OpenSource 程式領域的主流,因此也有人試圖用 Python 等語言去建構出科學計算的環境,像是 SciPy 就整合了 numpy 、sympy、Matplotlib、
34 |
圖、SciPy 的官方網站
36 |雖然已經有了這麼多開放原始碼的科學計算軟體,而且我本身也是 R 的使用者,但是、我仍然感到遺憾!
38 |因為我沒辦法找到建構在 JavaScript 語言上的科學計算軟體,所以、我打算自己建造一個,這個計劃就稱為 JsLab (JavaScript Laboratory)。
39 |在下列文章中,我將介紹自己為何要建構 JsLab 專案,如何建構 JsLab 專案,並與大家分享我在建構 JsLab 專案時所學到的一些經驗與心得。
40 |機器語言,是由什麼語言寫的? -- https://www.facebook.com/groups/programmerMagazine/permalink/780470388636346/
是否有文章介紹如何做出一個程式語言?一個程式語言設計的極限是什麼? -- https://www.facebook.com/groups/programmerMagazine/permalink/780457841970934/
程式人雜誌是一個結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎程式人認養專欄、或者捐出您的網誌。
18 || 出刊年月 | 23 |epub | 24 |ipad:PDF | 25 |A4:PDF | 26 |單頁 HTM | 27 |全部下載 | 28 |
|---|---|---|---|---|---|
| 2014年11月 | 33 |epub | 34 |ipad.pdf | 35 |A4.pdf | 36 |pmag.html | 37 |github | 38 |
程式人雜誌預定於每個月 1 日出刊,您可以從下列網址取得程式人雜誌的所有內容 (包含當月最新出刊的雜誌)。
69 | 72 |竭誠歡迎程式人投稿,或者成為本雜誌的專欄作家,現在就可以加入 程式人雜誌社團 一同共襄盛舉。
74 |本雜誌編輯為「陳鍾誠 (@ccckmit)」,若要聯絡編輯,請寄信到 。
80 | 在只有免費服務才使用 的這個世代,如果只是一個Demo的小型網站自然不想使用到雲端的SQL DB來做為DataBase (其實只是不想花一個月150左右的DB費用XD)
鑑於想要使用免費Azure Websites,但又想要連接資料庫的人要怎麼做呢?
24 |只能每個月砸150台幣買DB了嗎!?
25 |當然是 NO!
26 |今天就來教大家利用SQL Compact Edition不花一毛錢使用擁有 DataBase 的 Azure Websites 吧!
27 |以下看圖說故事開始:
28 |為你的專案加入兩個Nuget套件,分別是
30 |
36 | <connectionStrings> </connectionStrings> 區段中<add name ="DefaultConnection" connectionString ="Data Source=|DataDirectory|CompactDB.sdf" providerName ="System.Data.SqlServerCe.4.0" />
39 | 其中 Data Source=|DataDirectory|CompactDB.sdf 可得到相對路徑的 App_Data.sdf
40 |
42 | 注意:這裡我將檔名改為.sdf檔,因為.sdf 很適合小型專案使用,不需要用到.mdf
45 |
47 | 若你用的和我一樣是MVC的CodeFirst則是改掉你的連線字串後,讓DB自己產生出來,但是這之後有一個很重要的步驟!真的很重要!我卡在這邊很久!操作如下:
49 |產生DB後→點選右上角顯示所有檔案→找到你的CompactDB.sdf→右鍵加入至專案
50 |
52 | 左下新增→接著如圖選擇建立網站
55 |
57 | 建好網站後,點選你的網站,點選上方設定,拉到下面,填入剛剛的連接字串,選擇"自訂",按下方儲存
60 |
62 | 到儀表板,點選下載發行設定檔,將其儲存在電腦中
65 |
67 | 對你的專案按右鍵→發行→匯入→選到剛剛的設定檔→確定→發行
70 |
72 | 然後就發行成功囉!完成 網址參考
74 |希望有幫助到大家 的錢包 !XD
程式人雜誌是一個結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎程式人認養專欄、或者捐出您的網誌,如果您願意成為本雜誌的專欄作家,請加入 程式人雜誌社團 一同共襄盛舉。
29 |我們透過發行這本雜誌,希望讓大家可以讀到想讀的書,學到想學的技術,同時也讓寫作的朋友的作品能產生良好價值 – 那就是讓讀者根據雜誌的價值捐款給慈善團體。 讀雜誌做公益也不需要有壓力,您不需要每讀一本就急著去捐款,您可以讀了十本再捐,或者使用固定的月捐款方式,當成是雜誌訂閱費,或者是季捐款、一年捐一次等都 OK ! 甚至是單純當個讀者我們也都很歡迎!
30 |本雜誌每期參考價:NT 50 元,如果您喜歡本雜誌,請將書款捐贈公益團體。例如可捐贈給「羅慧夫顱顏基金會 彰化銀行(009) 帳號:5234-01-41778-800」。(若匯款要加註可用「程式人雜誌」五個字)
31 |給專欄寫作者: 做公益不需要有壓力。如果您願意撰寫專欄,您可以輕鬆的寫,如果當月的稿件出不來,我們會安排其他稿件上場。
33 |給網誌捐贈者: 如果您沒時間寫專欄或投稿,沒關係,只要將您的網誌以 [創作共用的「姓名標示、非商業性、相同方式分享」授權] 並通知我們,我們會自動從中選取需要的文章進行編輯,放入適當的雜誌當中出刊。
34 |給文章投稿者: 程式人雜誌非常歡迎您加入作者的行列,如果您想撰寫任何文章或投稿,請用 markdown 或 LibreOffice 編輯好您的稿件,並於每個月 25 日前投稿到程式人雜誌社團 的檔案區,我們會盡可能將稿件編入隔月1號出版程式人雜誌當中,也歡迎您到社團中與我們一同討論。
35 |如果您要投稿給程式人雜誌,我們最希望的格式是採用 markdown 的格式撰寫,然後將所有檔按壓縮為 zip 上傳到社團檔案區給我們, 如您想學習 markdown 的撰寫出版方式,可以參考 看影片學 markdown 編輯出版流程 一文。
36 |如果您無法採用 markdown 的方式撰寫,也可以直接給我們您的稿件,像是 MS. Word 的 doc 檔或 LibreOffice 的 odt 檔都可以,我們 會將這些稿件改寫為 markdown 之後編入雜誌當中。
37 |您也可以擔任程式人雜誌的編輯,甚至創造一個全新的公益雜誌,我們誠摯的邀請您加入「開放公益出版」的行列,如果您想擔任編輯或創造新雜誌,也歡迎到 程式人雜誌社團 來與我們討論相關事宜。
39 || 公益團體 | 48 |聯絡資訊 | 49 |服務對象 | 50 |捐款帳號 | 51 |
|---|---|---|---|
| 財團法人羅慧夫顱顏基金會 | 56 |http://www.nncf.org/ 02-27190408分機 232 |
62 | 顱顏患者 (如唇顎裂、小耳症或其他罕見顱顏缺陷) | 63 |銀行:009彰化銀行民生分行 帳號:5234-01-41778-800 |
64 |
| 社團法人台灣省兒童少年成長協會 | 67 |http://www.cyga.org/ 04-23058005 |
73 | 單親、隔代教養.弱勢及一般家庭之兒童青少年 | 74 |銀行:新光銀行 戶名:台灣省兒童少年成長協會 帳號:103-0912-10-000212-0 |
75 |
雖然 d3.js 很強大,但是卻並不容易使用,如果我們只是要畫一些簡易的圖形,可以採用延伸自 d3.js 的 c3.js 。
42 |C3.js 的使用非常的簡單,而且互動性很強大。舉例而言,以下是 C3.js 的一個範例,您將滑鼠游標移到圖形上,會顯示對應軸線的資料表格,這讓使用者可以很清楚的看到圖形所對應的數據,這是非常具有互動性的顯示方式。
43 |
圖、C3.js 的一個繪圖範例
45 |您可以點選下列網址試試看這個範例,應該可以感覺到 C3.js 好用的地方。
47 | 50 |而且、要產生上述的圖形,也只需要短短幾行簡單的資料與程式,其程式碼如下所示:
51 |var chart = c3.generate({
52 | data: {
53 | columns: [
54 | ['data1', 30, 20, 50, 40, 60, 50],
55 | ['data2', 200, 130, 90, 240, 130, 220],
56 | ['data3', 300, 200, 160, 400, 250, 250],
57 | ['data4', 200, 130, 90, 240, 130, 220],
58 | ['data5', 130, 120, 150, 140, 160, 150],
59 | ['data6', 90, 70, 20, 50, 60, 120],
60 | ],
61 | type: 'bar',
62 | types: {
63 | data3: 'spline',
64 | data4: 'line',
65 | data6: 'area',
66 | },
67 | groups: [
68 | ['data1','data2']
69 | ]
70 | }
71 | });
72 | 從以上的範例中,您應該可以看到 C3 這個架構的優點,相較於 D3 而言, C3 容易使用多了。
73 |但是、 C3 並沒有辦法完全發揮 D3 的功能,像是筆者就沒看到 C3 具有任何可以繪製統計 box chart 的功能,因此對於某些較少見的情況而言,我們還是得直接採用 D3 ,另外 C3 的文件說明並不完整,這是筆者所看到的 C3 框架之缺陷。
74 |Press ctrl-. to activate autocompletion. Built
110 | on top of the show-hint
111 | and javascript-hint
112 | addons.
d3.js 是一個在瀏覽器裏使用的互動式繪圖框架,使用 HTML、CSS、JavaScript 與 SVG (Scalable Vector Graphics) 等技術。
42 |d3.js 專案起始於 2011 年,是從 Protovis 專案修改過來的,通常我們會用 D3 來產生 SVG 或 CSS 的繪圖結果,在瀏覽器上檢視時還可以利用 SVG 或 CSS 與使用者進行互動。
43 |d3.js 的用法有點像 jQuery,都是透過選擇器來進行選取後操作的,舉例而言、下列指令可以選出所有 p 標記的節點並將顏色修改為 lavender (淡紫色、熏衣草)。
44 | d3.selectAll("p")
45 | .style("color", "lavender");
46 | 我們可以透過「標記 tag、類別 class、代號 identifier、屬性 attribute、或位置 place 來選取節點,然後進行新增、刪除、修改等動作,然後透過設定 CSS 的轉移 (transition) 屬性,讓繪圖的結果可以和使用者進行互動,舉例而言、以下程式就會讓網頁裡的 p 標記節點逐漸地改變為紫色。 (d3.js 預設的改變速度為 250ms 完成轉換)
47 | d3.selectAll("p")
48 | .transition()
49 | .style("color", "pink");
50 | 由於 SVG 裏的標記也是 HTML 的一部分, d3 的指令也可以選取 SVG 裏的內容,以下來自 Mike Bostock 網站的 範例 顯示了這個狀況:
51 |<svg width="720" height="120">
52 | <circle cx="40" cy="60" r="10"></circle>
53 | <circle cx="80" cy="60" r="10"></circle>
54 | <circle cx="120" cy="60" r="10"></circle>
55 | </svg>
56 | ...
57 | <script>
58 | var circle = d3.selectAll("circle");
59 | circle.style("fill", "steelblue");
60 | circle.attr("r", 30);
61 | </script>
62 | d3.js 的主要 API 包含下列幾類:
63 |而以下的專案則是延伸自 d3.js 的套件,
78 |甚至還有人專門為 d3.js 寫了一本書,而且這本書還有中文版。
89 |函數指標陣列,這是一種 C/C++ 程式語言的高階設計技巧,希望能有較高的執行效能。 我以 Arduino 當作測試平台,比較兩種程式設計技巧,發現與我的認知有些差異。
42 |先看傳統設計方式,用 switch case 執行不同功能:
43 |//
44 | // Author: Bridan
45 | // http://4rdp.blogspot.com
46 | // Date: 2014/09/27
47 | //
48 | // Brief: Test switch case
49 | //
50 |
51 | void setup() {
52 | Serial.begin(9600);
53 | while (!Serial) {
54 | ; // wait for serial port to connect. Needed for Leonardo only
55 | }
56 |
57 | TCCR1A = 0x00; // Normal mode, just as a Timer
58 | TCCR1B &= ~_BV(CS12); // no prescaling
59 | TCCR1B &= ~_BV(CS11);
60 | TCCR1B |= _BV(CS10);
61 | }
62 |
63 | void loop() {
64 | byte i;
65 |
66 | TCNT1 = 0; // reset timer
67 | for (i=0 ; i<3 ; i++) {
68 | switch (i) {
69 | case 0:
70 | Serial.println("CASE 0");
71 | break;
72 | case 1:
73 | Serial.println("CASE 1");
74 | break;
75 | case 2:
76 | Serial.println("CASE 2");
77 | break;
78 | }
79 | }
80 | Serial.println(TCNT1);
81 | }
82 | switch case 3 個時,編譯 2410 bytes,執行 6092 ~ 6100 timer clock switch case 4 個時,編譯 2430 bytes,執行 8136 ~ 8146 timer clock switch case 5 個時,編譯 2458 bytes,執行 10185 ~ 10195 timer clock
83 |將上面程式修改成函數指標陣列,以查表方式直接跳到執行的程式:
84 |//
85 | // Author: Bridan
86 | // http://4rdp.blogspot.com
87 | // Date: 2014/09/27
88 | //
89 | // Brief: Test Array of Function Pointers
90 | //
91 |
92 | void setup() {
93 | Serial.begin(9600);
94 | while (!Serial) {
95 | ; // wait for serial port to connect. Needed for Leonardo only
96 | }
97 |
98 | TCCR1A = 0x00; // Normal mode, just as a Timer
99 | TCCR1B &= ~_BV(CS12); // no prescaling
100 | TCCR1B &= ~_BV(CS11);
101 | TCCR1B |= _BV(CS10);
102 | }
103 |
104 | void FUNC0(void) {
105 | Serial.println("CASE 0");
106 | }
107 | void FUNC1(void) {
108 | Serial.println("CASE 1");
109 | }
110 | void FUNC2(void) {
111 | Serial.println("CASE 2");
112 | }
113 |
114 | void (*TABLE_JUMP[])(void) = {
115 | FUNC0,
116 | FUNC1,
117 | FUNC2
118 | };
119 |
120 | void loop() {
121 | byte i;
122 |
123 | TCNT1 = 0; // reset timer
124 | for (i=0 ; i<3 ; i++) {
125 | (*TABLE_JUMP[i])();
126 | }
127 | Serial.println(TCNT1);
128 | }
129 | TABLE 3 個時,編譯 2438 bytes,執行 6082 ~ 6096 timer clock TABLE 4 個時,編譯 2470 bytes,執行 8130 ~ 8142 timer clock TABLE 5 個時,編譯 2504 bytes,執行 10176 ~ 10194 timer clock
130 |以往我所用過的 compiler,switch case 相當於很多 if ... else ... 的組合,條件一個一個比較,數值越大的條件,花費比較的時間越多,以上面的例子在比較方面所費的時間 = 1 + 2 + 3 + ... + N,而函數指標陣列查表時間約 = 1 x N,比 switch case 有效率,這部分與結果相符 (比較條件太少,不易看出差異)。
131 |至於程式碼大小,發現越多條件狀況,以函數指標陣列方式設計比 switch case 程式碼多?因為不清楚 Arduino compiler 如何設計,無法進一步評論,但直覺 Arduino compiler 缺少這方面最佳化處理。
132 |在建構 jsLab 科學計算平台的過程中,由於要讓使用者在 JavaScript 程式編輯上有更好的感受,而不是只能依賴死板板的 textarea 區塊,所以我們找了幾個用 javascript 建構的網頁版程式碼編輯器,像是 Ace、Atom、EditArea 與 CodeMirror 等專案,最後我們認為 CodeMirror 最適合我們使用,因為 CodeMirror 的資源完整,而且具有支援 JavaScript 語言 IntelliSense 功能的插件。
42 |CodeMirror 支援超過六十種語言的上色與編輯功能,包含 HTML、XML、Javascript、Python、Ruby、C/C++/C#、.... 等等,您可以參考下列網頁。
49 |另外、 CodeMirror 還支援了下列的特色功能。
53 |其中我們最需要的是 JavaScript 的 Intellisense 功能,該功能的範例網址如下:
73 |可惜的是,該範例使用 Ctrl-Space 做為 Intellisense 的功能鍵,但是這個按鍵與繁體中文 windows 的輸入法切換功能相衝,所以沒辦法正常運作,因此我們將該範例的 「Ctrl-Space」 改為 「Ctrl-.」 ,以避免這種衝突的情況,修改版的範例的網址與程式碼如下。
77 | 80 |<!doctype html>
81 |
82 | <title>CodeMirror: Autocomplete Demo</title>
83 | <meta charset="utf-8"/>
84 | <link rel=stylesheet href="../doc/docs.css">
85 |
86 | <link rel="stylesheet" href="../lib/codemirror.css">
87 | <link rel="stylesheet" href="../addon/hint/show-hint.css">
88 | <script src="../lib/codemirror.js"></script>
89 | <script src="../addon/hint/show-hint.js"></script>
90 | <script src="../addon/hint/javascript-hint.js"></script>
91 | <script src="../mode/javascript/javascript.js"></script>
92 |
93 | <div id=nav>
94 | <a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a>
95 |
96 | <ul>
97 | <li><a href="../index.html">Home</a>
98 | <li><a href="../doc/manual.html">Manual</a>
99 | <li><a href="https://github.com/marijnh/codemirror">Code</a>
100 | </ul>
101 | <ul>
102 | <li><a class=active href="#">Autocomplete</a>
103 | </ul>
104 | </div>
105 |
106 | <article>
107 | <h2>Autocomplete Demo</h2>
108 | <form><textarea id="code" name="code">
109 | function getCompletions(token, context) {
110 | var found = [], start = token.string;
111 | function maybeAdd(str) {
112 | if (str.indexOf(start) == 0) found.push(str);
113 | }
114 | function gatherCompletions(obj) {
115 | if (typeof obj == "string") forEach(stringProps, maybeAdd);
116 | else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
117 | else if (obj instanceof Function) forEach(funcProps, maybeAdd);
118 | for (var name in obj) maybeAdd(name);
119 | }
120 |
121 | if (context) {
122 | // If this is a property, see if it belongs to some object we can
123 | // find in the current environment.
124 | var obj = context.pop(), base;
125 | if (obj.className == "js-variable")
126 | base = window[obj.string];
127 | else if (obj.className == "js-string")
128 | base = "";
129 | else if (obj.className == "js-atom")
130 | base = 1;
131 | while (base != null && context.length)
132 | base = base[context.pop().string];
133 | if (base != null) gatherCompletions(base);
134 | }
135 | else {
136 | // If not, just look in the window object and any local scope
137 | // (reading into JS mode internals to get at the local variables)
138 | for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
139 | gatherCompletions(window);
140 | forEach(keywords, maybeAdd);
141 | }
142 | return found;
143 | }
144 | </textarea></form>
145 |
146 | <p>Press <strong>ctrl-.</strong> to activate autocompletion. Built
147 | on top of the <a href="../doc/manual.html#addon_show-hint"><code>show-hint</code></a>
148 | and <a href="../doc/manual.html#addon_javascript-hint"><code>javascript-hint</code></a>
149 | addons.</p>
150 |
151 | <script>
152 | var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
153 | lineNumbers: true,
154 | extraKeys: {"Ctrl-.": "autocomplete"},
155 | mode: {name: "javascript", globalVars: true}
156 | });
157 | </script>
158 | </article>
159 | 不過、雖然 CodeMirror 支援了 JavaScript 的 Intellisense 功能,但是卻不徹底,對於像是字串之類的語法,他可以顯示提示函數與訊息,但對於變數的部分,卻無法正確提示,以下是一個可以正確提示的範例。
160 |
圖、CodeMirror 可以正確提示的 JavaScript 編輯範例
162 |如果需要更進一步的正確提示功能,恐怕還是得修改 CodeMirror 的 ../addon/hint/javascript-hint.js 模組才行。
雖然 CodeMirror 已經算不錯了,不過我想還有進步空間,但大體來說 CodeMirror 已經是很好的網頁程式編輯器了。
165 |不過、如果您需要的是可以加上「粗體、斜體、字型、超連結、....」等功能,那就不是 CodeMirror 所具備的功能了,這種功能是 RichText Editor 才具備的,您可以參考下列文章中的 RichText 編輯器。
166 | 169 |為了要用 JavaScript 建構出科學計算平台,我們創建了以下的 JsLab 開放原始碼專案。
42 | 45 |我們大量的採用了 JavaScript 的開放原始碼函式庫,像是在「機率統計」領域採用了 jStat 這個專案,在繪圖領域採用了 d3.js、c3.js、vis.js 等等,這些專案的網址如下。
46 |JsLab 科學計算平台的核心,是一組基於 jStat 專案的重新封裝,我們將 jStat 重新封裝成類似 R 函式庫的介面,並且加上了一些 jStat 當中所沒有的功能,特別是統計檢定的部份,形成了 R.js 這個 JavaScript 程式,讓 JavaScript 也能擁有類似 R 軟體的機率統計函式庫。
53 |我們雖然使用了 d3.js 這個繪圖函式庫進行 2D 繪圖,但由於 d3.js 並不容易使用,所以我們採用了 c3.js 這個基於 d3 的延伸套件,簡化 d3 繪圖函式庫的使用,讓我們不需瞭解太多繪圖的細節就能寫出 JsLab 的繪圖函式庫。
54 |舉例而言、下列的圖形就是依靠 c3.js 所繪製的,只不過我們將 c3.js 進一步封裝到 JsLab 的 G.js 這個的繪圖函式庫當中而已。
55 |
57 | 以下是我們將 c3.js 重新封裝成 G.js 的程式碼片段。
59 |檔案: G.js
60 |var C3G=function() {
61 | this.g = {
62 | data: {
63 | xs: {},
64 | columns: [ /*["x", 1, 2, 3, 4 ]*/ ],
65 | type: "line",
66 | types : {}
67 | },
68 | axis: {
69 | x: {
70 | label: 'X',
71 | tick: { fit: false, format:d3.format(".2f") }
72 | },
73 | y: { label: 'Y',
74 | tick : { format: d3.format(".2f") }
75 | }
76 | },
77 | bar: { width: { ratio: 0.9 } },
78 | };
79 | this.varcount = 0;
80 | this.xrange(-10, 10);
81 | this.step = 1;
82 | this.setrange = false;
83 | }
84 | ....
85 | C3G.prototype.hist = function(x, options) {
86 | var name = R.opt(options, "name", this.tempvar());
87 | var mode = R.opt(options, "mode", "");
88 | var step = R.opt(options, "step", this.step);
89 | var from = R.opt(options, "from", this.xmin);
90 | var to = R.opt(options, "to", this.xmax);
91 | this.g.data.types[name] = "bar";
92 | this.g.data.xs[name] = name+"x";
93 | var xc = R.steps(from+step/2.0, to, step);
94 | var n = (to-from)/step + 1;
95 | var count = R.repeats(0, n);
96 | for (var i in x) {
97 | var slot=Math.floor((x[i]-from)/step);
98 | if (slot>=0 && slot < n)
99 | count[slot]++;
100 | }
101 | this.g.data.columns.push([name+"x"].concat(xc));
102 | var total = R.sum(count);
103 | if (mode === "normalized")
104 | count = R.apply(count, function(c) { return (1.0/step)*(c/total); });
105 | this.g.data.columns.push([name].concat(count));
106 | }
107 | ...
108 | C3G.prototype.show = function() {
109 | if (typeof(module)==="undefined")
110 | return c3.generate(this.g);
111 | }
112 | 另外、由於 d3.js 並沒有支援 3D 曲面圖形的繪製,所以我們又引入了 vis.js 這個繪圖函式庫來完成 3D 圖形的繪製工作。
113 |以下是我們將 vis.js 封裝成 G.js 的程式碼片段
114 |檔案: G.js
115 |...
116 | VISG.prototype.curve3d = function(f, box) {
117 | // Create and populate a data table.
118 | var data = new vis.DataSet();
119 | // create some nice looking data with sin/cos
120 | var counter = 0;
121 | var steps = 50; // number of datapoints will be steps*steps
122 | var axisMax = 314;
123 | var axisStep = axisMax / steps;
124 | for (var x = 0; x < axisMax; x+=axisStep) {
125 | for (var y = 0; y < axisMax; y+=axisStep) {
126 | var value = f(x,y);
127 | data.add({id:counter++,x:x,y:y,z:value,style:value});
128 | }
129 | }
130 | this.graph = new vis.Graph3d(box, data, this.options);
131 | }
132 | ...
133 | G.curve3d = function(f) {
134 | G.visg.curve3d(f, G.box);
135 | }
136 | 接著、為了讓使用者編輯程式可以更容易,我們採用了這個 JavaScript 開源線上編輯器專案,該專案之援類似微軟 Visual Studio 的 IntelliSense 這樣的函數提示功能,
137 |
圖、JsLab 當中的程式碼上色與 IntelliSense 功能
142 |以下是我們將 codemirror 封裝成 E.js (Editor) 的完整程式碼。
144 |檔案: E.js
145 |"use strict";
146 |
147 | U.use("../js/codemirror/lib/codemirror.js", "CodeMirror");
148 | U.use("../js/codemirror/addon/hint/show-hint.js");
149 | U.use("../js/codemirror/addon/hint/javascript-hint.js");
150 | U.use("../js/codemirror/mode/javascript/javascript.js");
151 |
152 | E = {};
153 |
154 | if (typeof module!=="undefined") module.exports = E;
155 |
156 | E.editor = null;
157 |
158 | E.loadEditor = function(codebox) {
159 | E.codebox = codebox;
160 | E.editor = CodeMirror.fromTextArea(codebox, {
161 | lineNumbers: true,
162 | extraKeys: {"Ctrl-.": "autocomplete"},
163 | lineWrapping: true,
164 | styleActiveLine: true,
165 | mode: {name: "javascript", globalVars: true}
166 | });
167 |
168 | E.editor.on('update', function(instance){
169 | E.codebox.value = instance.getValue();
170 | });
171 | }
172 | 未來、我們可能會進一步整合更多的函式庫,目前預計在「矩陣運算領域」會採用了 jStat 與 numeric.js 等函式庫,而在數位訊號語音處理領域可能會採用 DSP.js,影像處理領域可能採用 CamanJS 等等,這些函式庫的網址如下:
173 |目前、網路上的 JavaScript 的函式庫還持續的急速增長中,我們相信之後會有更多更好用的 JavaScript 科學計算函式庫出現,我們只要能將這些好用的函式庫整合進來,就能創建一個完整的科學計算平台了,而這也正是 JsLab 計劃所想要達成的目標。
179 |由於 JavaScript 是瀏覽器當中唯一能使用的官方語言,因此我們認為未來 JavaScript 的發揮空間將會越來越大,就像 Jeff Atwood 在 2007 年所提出的 Atwood's Law 所說的:
180 |181 |183 |Any application that can be written in JavaScript, will eventually be written in JavaScript.
182 |
換句話說 -- 「任何可以寫成 JavaScript 的應用程式,最後都會被寫成 JavaScript」。
184 |如果 Atwood's Law 成立的話,那基於 JavaScript 的科學計算平台就應該要出現啊!
185 |我們正在以行動來實現 Atwood 的話,這個行動的代號就是 JsLab 。
186 |雖然前述的 d3.js 與 c3.js 可以做到繪圖功能,但是這兩個函式庫強調的是互動性介面,而不是繪圖功能的部份。
42 |於是、我找到了 vis.js 這個專注於繪圖的函式庫,這個函式庫雖然再互動性上表現得沒有 c3 那麼好,但是在繪圖功能上卻非常的完整,該有的圖型幾乎都有,特別是有關「 3D 地形圖」、「網路線圖」和的部份,是 C3 所不具備的功能,因此我們拿 vis.js 來繪製這兩類的圖形。
43 |您可以點選下列連結,看看 vis.js 的眾多範例,相信您會對這個繪圖框架感到印象深刻的。
44 |舉例而言、以下網頁是用來繪製 3D 地形圖的完整原始碼,
48 |網址:http://visjs.org/examples/graph3d/example01_basis.html
49 |
圖、用 Vis.js 繪製 3D 圖形
51 |以下是上述範例的完整 HTML 檔案。
53 |<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
54 | <html>
55 | <head>
56 | <title>Graph 3D demo</title>
57 |
58 | <style>
59 | body {font: 10pt arial;}
60 | </style>
61 |
62 | <script type="text/javascript" src="../../dist/vis.js"></script>
63 |
64 | <script type="text/javascript">
65 | var data = null;
66 | var graph = null;
67 |
68 | function custom(x, y) {
69 | return (Math.sin(x/50) * Math.cos(y/50) * 50 + 50);
70 | }
71 |
72 | // Called when the Visualization API is loaded.
73 | function drawVisualization() {
74 | // Create and populate a data table.
75 | data = new vis.DataSet();
76 | // create some nice looking data with sin/cos
77 | var counter = 0;
78 | var steps = 50; // number of datapoints will be steps*steps
79 | var axisMax = 314;
80 | var axisStep = axisMax / steps;
81 | for (var x = 0; x < axisMax; x+=axisStep) {
82 | for (var y = 0; y < axisMax; y+=axisStep) {
83 | var value = custom(x,y);
84 | data.add({id:counter++,x:x,y:y,z:value,style:value});
85 | }
86 | }
87 |
88 | // specify options
89 | var options = {
90 | width: '600px',
91 | height: '600px',
92 | style: 'surface',
93 | showPerspective: true,
94 | showGrid: true,
95 | showShadow: false,
96 | keepAspectRatio: true,
97 | verticalRatio: 0.5
98 | };
99 |
100 | // Instantiate our graph object.
101 | var container = document.getElementById('mygraph');
102 | graph = new vis.Graph3d(container, data, options);
103 | }
104 | </script>
105 | </head>
106 |
107 | <body onload="drawVisualization();">
108 | <div id="mygraph"></div>
109 |
110 | <div id="info"></div>
111 | </body>
112 | </html>
113 | 而在網路圖方面,您甚至可以指定每個節點應該呈現的圖片,以下是一個繪製電腦網路圖的範例。
114 |
圖、用 vis.js 繪製電腦網路圖
119 |以下是上述範例的完整 HTML 檔案。
121 |<!doctype html>
122 | <html>
123 | <head>
124 | <title>Network | Images</title>
125 |
126 | <style type="text/css">
127 | body {
128 | font: 10pt arial;
129 | }
130 | #mynetwork {
131 | width: 600px;
132 | height: 600px;
133 | border: 1px solid lightgray;
134 | }
135 | </style>
136 |
137 | <script type="text/javascript" src="../../dist/vis.js"></script>
138 | <link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
139 |
140 | <script type="text/javascript">
141 | var nodes = null;
142 | var edges = null;
143 | var network = null;
144 |
145 | var DIR = 'img/refresh-cl/';
146 | var LENGTH_MAIN = 150;
147 | var LENGTH_SUB = 50;
148 |
149 | // Called when the Visualization API is loaded.
150 | function draw() {
151 | // Create a data table with nodes.
152 | nodes = [];
153 |
154 | // Create a data table with links.
155 | edges = [];
156 |
157 | nodes.push({id: 1, label: 'Main', image: DIR + 'Network-Pipe-icon.png', shape: 'image'});
158 | nodes.push({id: 2, label: 'Office', image: DIR + 'Network-Pipe-icon.png', shape: 'image'});
159 | nodes.push({id: 3, label: 'Wireless', image: DIR + 'Network-Pipe-icon.png', shape: 'image'});
160 | edges.push({from: 1, to: 2, length: LENGTH_MAIN});
161 | edges.push({from: 1, to: 3, length: LENGTH_MAIN});
162 |
163 | for (var i = 4; i <= 7; i++) {
164 | nodes.push({id: i, label: 'Computer', image: DIR + 'Hardware-My-Computer-3-icon.png', shape: 'image'});
165 | edges.push({from: 2, to: i, length: LENGTH_SUB});
166 | }
167 |
168 | nodes.push({id: 101, label: 'Printer', image: DIR + 'Hardware-Printer-Blue-icon.png', shape: 'image'});
169 | edges.push({from: 2, to: 101, length: LENGTH_SUB});
170 |
171 | nodes.push({id: 102, label: 'Laptop', image: DIR + 'Hardware-Laptop-1-icon.png', shape: 'image'});
172 | edges.push({from: 3, to: 102, length: LENGTH_SUB});
173 |
174 | nodes.push({id: 103, label: 'network drive', image: DIR + 'Network-Drive-icon.png', shape: 'image'});
175 | edges.push({from: 1, to: 103, length: LENGTH_SUB});
176 |
177 | nodes.push({id: 104, label: 'Internet', image: DIR + 'System-Firewall-2-icon.png', shape: 'image'});
178 | edges.push({from: 1, to: 104, length: LENGTH_SUB});
179 |
180 | for (var i = 200; i <= 201; i++ ) {
181 | nodes.push({id: i, label: 'Smartphone', image: DIR + 'Hardware-My-PDA-02-icon.png', shape: 'image'});
182 | edges.push({from: 3, to: i, length: LENGTH_SUB});
183 | }
184 |
185 | // create a network
186 | var container = document.getElementById('mynetwork');
187 | var data = {
188 | nodes: nodes,
189 | edges: edges
190 | };
191 | var options = {
192 | stabilize: false // stabilize positions before displaying
193 | };
194 | network = new vis.Network(container, data, options);
195 | }
196 | </script>
197 | </head>
198 |
199 | <body onload="draw()">
200 |
201 | <div id="mynetwork"></div>
202 |
203 | </body>
204 | </html>
205 | 透過這兩個範例,相信您應該可以感覺到 vis.js 的誠意,這真的是一個相當棒的繪圖函式庫啊!
206 |我自從開始用 R 學習機率統計之後,就覺得這樣的科學計算平台真的很棒。
42 |但可惜的是、我現在所使用的主力語言是 JavaScript,因為 JavaScript 是瀏覽器的唯一語言,而且有了 node.js 這樣的平台之後,可以通吃客戶端與伺服端兩方的應用。
43 |於是我想要用 JavaScript 創造出一個類似 R 的環境,並且可以在 Web 上執行,所以就創造了 jsLab 專案。
44 |但是、為了讓 jsLab 能支援那些機率統計功能,我必須尋找用 JavaScript 語言撰寫的機率統計函式庫。
45 |在 2012 年我就注意到了 jStat 這個支援機率模型的函式庫,當時這個函式庫還有專屬的網站,但是現在這個函式庫連網站都不見了,還好在 github 裏還有一份原始碼,網址如下:
46 |jStat 在機率模型的部分支援還算完整,但是在統計檢定的部分就相當薄弱,雖然也支援矩陣運算等功能,但是在 JavaScript 語言上, jStat 的矩陣運算支援並不算特別好的。
50 |因此、我們決定將 jStat 重新包裝,成為一個新的 javascript 檔案,稱為 R.js ,這是 jsLab 專案的主要程式碼之一, R.js 的網址如下。
51 | 54 |您可以看到在 R.js 檔案裏,能夠呼叫 jStat 完成的部分,我們都盡可能的交給 jStat 來做,而 jStat 在這部份也確實做得很不錯。
55 |檔案: R.js
56 |...
57 | // 均等分布
58 | R.runif=function(n, a, b) { return R.calls(n, jStat.uniform.sample, a, b); }
59 | R.dunif=function(x, a, b) { return jStat.uniform.pdf(x, a, b); }
60 | R.punif=function(q, a, b) { return jStat.uniform.cdf(q, a, b); }
61 | R.qunif=function(p, a, b) { return jStat.uniform.inv(p, a, b); }
62 | // 常態分布
63 | R.rnorm=function(n, mean, sd) { return R.calls(n, jStat.normal.sample, mean, sd); }
64 | R.dnorm=function(x, mean, sd) { return jStat.normal.pdf(x, mean, sd); }
65 | R.pnorm=function(q, mean, sd) { return jStat.normal.cdf(q, mean, sd); }
66 | // R.qnorm=function(p, mean, sd) { return R.q2x(p, function (q) { return R.pnorm(q, mean, sd);});}
67 | R.qnorm=function(p, mean, sd) { return jStat.normal.inv(p, mean, sd); }
68 | // 布瓦松分布
69 | R.rpois=function(n, l) { return R.calls(n, jStat.poisson.sample, l); }
70 | R.dpois=function(x, l) { return jStat.poisson.pdf(x, l); }
71 | R.ppois=function(q, l) { return jStat.poisson.cdf(q, l); }
72 | R.qpois=function(p, l) { return jStat.poisson.inv(p, l); }
73 |
74 | // F 分布
75 | R.rf=function(n, df1, df2) { return R.calls(n, jStat.centralF.sample, df1, df2); }
76 | R.df=function(x, df1, df2) { return jStat.centralF.pdf(x, df1, df2); }
77 | R.pf=function(q, df1, df2) { return jStat.centralF.cdf(q, df1, df2); }
78 | R.qf=function(p, df1, df2) { return jStat.centralF.inv(p, df1, df2); }
79 | // T 分布
80 | R.rt=function(n, dof) { return R.calls(n, jStat.studentt.sample, dof); }
81 | R.dt=function(x, dof) { return jStat.studentt.pdf(x, dof); }
82 | R.pt=function(q, dof) { return jStat.studentt.cdf(q, dof); }
83 | R.qt=function(p, dof) { return jStat.studentt.inv(p, dof); }
84 | ...
85 | 不過、在離散的機率分布上面,jStat 就支援的比較不好,而且沒有支援像 inv 這類的函數,於是我們就得自己來補足,以下是我們用 jStat 與自己寫的程式所合成的一些離散分布原始碼。
86 |...
87 | R.sample1=function(a, p) {
88 | var r = Math.random();
89 | var u = R.repeats(1.0, a.length);
90 | p = R.def(p, R.normalize(u));
91 | var psum = 0;
92 | for (var i in p) {
93 | psum += p[i];
94 | if (psum > r)
95 | return a[i];
96 | }
97 | return null;
98 | }
99 |
100 | R.sample=function(x, n, p) { return R.calls(n, R.sample1, x, p); }
101 |
102 | // 二項分布
103 | R.rbinom=function(n, N, p) { return R.calls(n, jStat.binomial.sample, N, p); }
104 | R.dbinom=function(x, N, p) { return jStat.binomial.pdf(x, N, p); }
105 | R.pbinom=function(k, N, p) { return jStat.binomial.cdf(k, N, p); }
106 | R.qbinom=function(q, N, p) {
107 | for (var i=0; i<=N; i++) {
108 | if (R.pbinom(i, N, p) > q) return i;
109 | }
110 | return N;
111 | }
112 |
113 | // 負二項分布
114 | R.rnbinom=function(n, N, p) { return R.calls(n, jStat.negbin.sample, N, p); }
115 | R.dnbinom=function(x, N, p) { return jStat.negbin.pdf(x, N, p); }
116 | R.pnbinom=function(k, N, p) { return jStat.negbin.cdf(k, N, p); }
117 | // R.qnbinom=function(p, N, q) { return jStat.negbin.inv(p, N, q); }
118 | R.qnbinom=function(q, N, p) {
119 | for (var i=0; i<N; i++) {
120 | if (R.pnbinom(i, N, p) > q) return i;
121 | }
122 | return N;
123 | }
124 | ...
125 | 另外、由於 jStat 在統計檢定方面的函數也很薄弱,所以我們撰寫了以下這個檢定的抽象函數,實作時只要補足「 q2p, o2q, h, df」等函數,就可以做出一個檢定功能了。
126 |...
127 | R.test = function(o) { // name, D, x, mu, sd, y, alpha, op
128 | var D = o.D;
129 | var x = o.x;
130 | var alpha = R.opt(o, "alpha", 0.05);
131 | o.op = R.opt(o, "op", "=");
132 |
133 | var pvalue, interval;
134 | var q1 = D.o2q(o); // 單尾檢定的 pvalue
135 |
136 | if (o.op === "=") {
137 | if (q1>0.5) q1 = 1-q1; // (q1>0.5) 取右尾,否則取左尾。
138 | pvalue= 2*q1; // 對稱情況:雙尾檢定的 p 值是單尾的兩倍。
139 | interval = [D.q2p(alpha/2, o, "L"), D.q2p(1-alpha/2, o, "R")];
140 | } else {
141 | if (o.op === "<") { // 右尾檢定 H0: q < 1-alpha,
142 | interval = [ D.q2p(alpha, o, "L"), Infinity ];
143 | pvalue = 1-q1;
144 | }
145 | if (o.op === ">") { // 左尾檢定 H0: q > alpha
146 | interval=[-Infinity, D.q2p(1-alpha, o, "R")];
147 | pvalue = q1;
148 | }
149 | }
150 |
151 | return { name: o.name,
152 | h: D.h(o),
153 | alpha: alpha,
154 | op: o.op,
155 | pvalue: pvalue,
156 | ci : interval,
157 | df : D.df(o),
158 | report: function() { R.report(this) }
159 | };
160 | }
161 | ...
162 | 舉例而言,以下這個物件 t1 實作了 R.test 中所需要的函數,因此我們就可以透過「 o.D = t1; t = R.test(o); 這兩行指令呼叫 R.test 函數,完成單樣本的 t 檢定工作。
var t1 = { // 單樣本 T 檢定 t = (X-mu)/(S/sqrt(n))
164 | h:function(o) { return "H0:mu"+o.op+o.mu; },
165 | o2q:function(o) {
166 | var x = o.x, n = x.length;
167 | // t=(X-mu)/(sd/sqrt(n))
168 | var t = (R.mean(x)-o.mu)/(R.sd(x)/Math.sqrt(n));
169 | return R.pt(t, n-1);
170 | },
171 | // P(X-mu/(S/sqrt(n))<t) = q ; 信賴區間 P(T<q)
172 | // P(mu > X-t*S/sqrt(n)) = q ; 這反而成了右尾檢定,所以左尾與右尾確實會反過來
173 | q2p:function(q, o) {
174 | var x = o.x, n = x.length;
175 | return R.mean(x) + R.qt(q, n-1) * R.sd(x) / Math.sqrt(n);
176 | },
177 | df:function(o) { return o.x.length-1; }
178 | }
179 | ...
180 | R.ttest = function(o) {
181 | var t;
182 | if (typeof o.y === "undefined") {
183 | o.name = "ttest(X)";
184 | o.D = t1;
185 | t = R.test(o);
186 | t.mean = R.mean(o.x);
187 | t.sd = R.sd(o.x);
188 | } else {
189 | 目前我們已經在 R.js 中加入了大部份的機率分布、還有基本的「有母數」檢定功能,之後會再加入「無母數檢定的功能」。
190 |另外、我們也已經加入了基本的圖表繪製功能在 G.js 當中,於是形成了 jsLab 專案的基本架構,希望之後還能找到更多更棒的 JavaScript 科學計算函式庫,讓 JavaScript 語言也能 成為科學計算的良好平台。
191 |雖然已經有很多科學計算軟體,像是 MatLab、 Mathematica、SPSS、SAS 等等,而且也有像 R、Octave、SciPy 等開放原始碼的科學計算軟體,但就是沒有以 JavaScript 為主的科學計算軟體。
42 |於是我們決定要用 JavaScript 建構一個科學計算軟體,所以、JsLab 計劃就誕生了,關於 JsLab 的用法,可以參考下列的展示影片。
43 |下圖是我們已經上傳到 github 上的 JsLab 專案之執行畫面,該程式是一個純粹用 HTML+JavaScript 建構的網頁,網址如下:
47 | 50 |您可以連結到該網頁上直接使用該平台,雖然現在還沒有很強大,不過已經可以使用了。
51 |
圖、JsLab 的執行畫面 -- 繪製 3D 函數圖
53 |在上述網頁中,我預設在編輯器裏放入了一個展示程式如下, JsLab 會執行該程式後將結果放在訊息視窗,並將繪圖部份顯示在右邊的窗框中。
55 |檔案: curve3D.js
56 |function f(x, y) {
57 | return (Math.sin(x/50) * Math.cos(y/50) * 50 + 50);
58 | }
59 | G.curve3d(f);
60 | 您可以將程式貼到該網頁的程式編輯區,然後按下執行即可得到執行結果。舉例而言、您可以貼上下列程式到編輯區。
61 |檔案: curveT.js
62 |G.curve(fx(dt, 3), {name:"dt(3)", step:0.1});
63 | G.curve("dt(x,10)",{name:"dt(10)", step:0.1});
64 | G.curve(fx(dt, 25),{name:"dt(25)", step:0.1});
65 | 然後按下執行的 run 按鈕,就可以看到下列的曲線圖。
66 |
圖、JsLab 的執行畫面 -- 繪製 2D 曲線圖
68 |或者您也可以將下列程式貼到程式區,然後按下執行的 run 按鈕,就可以看到所繪出的散點圖。
70 |檔案: plot1.js
71 |Ax = R.rnorm(100, 10, 1);
72 | Ay = R.rnorm(100, 0, 0.5);
73 | Bx = R.rnorm(100, 0, 1);
74 | By = R.rnorm(100, 0, 0.5);
75 | G.plot(Ax, Ay, {name:"A"});
76 | G.plot(Bx, By, {name:"B"});
77 | 
圖、JsLab 的執行畫面 -- 隨機取樣後繪製散點圖
79 |當然、如果您將程式存檔在自己的電腦,那麼您也可以按下「選擇檔案」的按鈕,接著選取想要執行的檔案,就可以將程式上傳並執行,以下是我們透過上傳的方式執行 hist.js 程式的結果。
81 |檔案: hist.js
82 |var x = rnorm(1000, 5, 2);
83 | G.hist(x, {name:"x", mode:"normalized"});
84 | G.curve("dnorm(x, 5,2)", {name:"N(5,2)", step:0.2});
85 | 
圖、JsLab 的執行畫面 -- 隨機取樣後繪製統計長條圖
87 |如果您並不想使用瀏覽器介面,也不需要繪製圖形,那麼您也可以採用 node.js 的命令列執行方式,直接引用 JsLab 背後的函式庫,像是 R.js 進行科學計算的動作,以下是我們在 node.js 中使用 R.js 進行隨機抽樣的一個範例。
89 |檔案: sample.js
90 |var U = require("../source/U");
91 | U.use("../source/R", "R");
92 |
93 | log("=======二項分布測試===========");
94 | log("pbinom(7, 12, 0.4)="+pbinom(7, 12, 0.4)); // > pbinom(7, 12, 0.4) [1] 0.9426901
95 | log("qbinom(0.9, 12, 0.4)="+qbinom(0.9, 12, 0.4)); // > qbinom(0.9, 12, 0.4)[1] 7
96 | log("qbinom(0.95, 12, 0.4)="+qbinom(0.95, 12, 0.4)); // > qbinom(0.95, 12, 0.4)[1] 8
97 |
98 | log("=======常態分布抽樣===========");
99 | log("rnorm="+rnorm);
100 | log("rnorm(5, 2, 1)="+str(rnorm(5,2,1)));
101 | var y = rnorm(25, 0, 2);
102 | log("y="+str(y));
103 |
104 | log("=======模擬丟銅板 100 次===========");
105 | log("sample([正, 反], 100)="+sample(["正", "反"], 100));
106 |
107 | log("=======模擬擲骰子 100 次===========");
108 | log("sample([1,2,3,4,5,6], 100)="+sample([1,2,3,4,5,6], 100));
109 | 執行結果
110 |D:\Dropbox\Public\jslab\test>node sample.js
111 | use ../source/R name=R
112 | use ../js/jstat.js name=jStat
113 | =======二項分布測試===========
114 | pbinom(7, 12, 0.4)=0.9426900787200003
115 | qbinom(0.9, 12, 0.4)=7
116 | qbinom(0.95, 12, 0.4)=8
117 | =======常態分布抽樣===========
118 | rnorm=function (n, mean, sd) { return R.calls(n, jStat.normal.sample, mean, sd);
119 | }
120 | rnorm(5, 2, 1)=[2.0748,2.3562,3.014,3.6833,4.1393]
121 | y=[-0.3756,1.2935,-1.9635,0.5446,0.6514,2.7079,-1.2434,-4.8451,1.0937,2.5094,0.1
122 | 423,4.6915,1.3294,-1.3275,1.0153,2.5058,-2.5361,1.7784,3.908,-2.2349,0.186,-2.17
123 | 17,-1.4398,0.0423,1.2014]
124 | =======模擬丟銅板 100 次===========
125 | sample([正, 反], 100)=正,正,反,反,正,正,反,正,反,反,正,正,反,反,正,正,正,反,反,
126 | 正,反,正,反,反,反,反,正,正,正,反,反,反,正,反,正,反,反,正,反,正,正,正,反,正,反,反
127 | ,正,反,反,正,正,正,正,正,正,正,正,正,反,反,正,正,反,反,反,反,反,反,正,反,反,正,
128 | 反,正,反,反,正,反,正,反,反,反,正,正,反,反,正,正,正,正,反,正,反,反,正,正,反,反,反
129 | ,正
130 | =======模擬擲骰子 100 次===========
131 | sample([1,2,3,4,5,6], 100)=3,2,4,6,5,2,4,4,5,5,1,5,1,1,2,1,4,1,1,2,1,4,1,6,1,4,6
132 | ,5,1,4,1,6,1,1,2,6,1,5,1,3,3,1,3,4,2,5,6,4,3,5,2,4,3,1,2,1,6,3,2,4,1,2,1,4,2,6,3
133 | ,5,4,5,4,4,1,4,2,6,2,4,5,2,3,5,1,3,3,2,3,2,1,3,5,3,2,5,3,6,2,4,1,2
134 | 另外、目前我們也還持續的在增加 JsLab 函式庫的功能,像是我們正在為 R.js 加上各種統計檢定的功能,以下是採用 node.js 環境執行檢定的一些案例。
135 |由於 jStat 函式庫並沒有支援這些統計檢定的函數,因此筆者只好自行撰寫,為了撰寫這些檢定的程式,我甚至將 R 的原始碼給翻了出來,網址如下:
136 | 139 |以下是我們對這些檢定功能的一些測試範例,大部分的功能都有對應的 R 操作與執行結果,這樣我們就能利用 R 軟體來驗證我們所寫的檢定函數是否正確了。
140 |檔案: rtest.js
141 |var U = require("../source/U");
142 | U.use("../source/R", "R");
143 |
144 | // x = rnorm(10, 5, 2)
145 | var x = [7.169890 ,2.188864 , 2.963868 ,7.790631 ,2.474261 ,7.694849 ,1.585007 ,4.087697 ,3.051643 ,4.697559];
146 | // y = rnorm(10, 4,2)
147 | var y = [4.9627295,6.0336209,-0.4610221,7.3744023,2.4804347,7.2053190,3.5558563,3.6505476,2.2200754,5.3021459];
148 | // py = x + rnorm(10, 1, 2)
149 | var py= [9.829046 ,2.491387 ,6.037504 ,5.709755 ,5.461208 ,7.345603 ,3.040538 ,4.856838 ,3.195437 ,7.079105];
150 |
151 | log("x="+str(x));
152 | log("y="+str(y));
153 |
154 | ttest({x:x, mu:6, alpha:0.05, op:"="}).report();
155 |
156 | /*
157 | > t.test(x, mu=6, alpha=0.05)
158 |
159 | One Sample t-test
160 |
161 | data: x
162 | t = -2.1732, df = 9, p-value = 0.05781
163 | alternative hypothesis: true mean is not equal to 6
164 | 95 percent confidence interval:
165 | 2.674155 6.066699
166 | sample estimates:
167 | mean of x
168 | 4.370427 */
169 |
170 | ttest({x:x, mu:6, alpha:0.05, op:"<"}).report();
171 |
172 | /*
173 | > t.test(x, mu=6, alternative="greater")
174 |
175 | One Sample t-test
176 |
177 | data: x
178 | t = -2.1732, df = 9, p-value = 0.9711
179 | alternative hypothesis: true mean is greater than 6
180 | 95 percent confidence interval:
181 | 2.995873 Inf
182 | sample estimates:
183 | mean of x
184 | 4.370427
185 | */
186 |
187 | ttest({x:x, mu:6, alpha:0.05, op:">"}).report();
188 |
189 | /*
190 | > t.test(x, mu=6, alternative="less")
191 |
192 | One Sample t-test
193 |
194 | data: x
195 | t = -2.1732, df = 9, p-value = 0.02891
196 | alternative hypothesis: true mean is less than 6
197 | 95 percent confidence interval:
198 | -Inf 5.744981
199 | sample estimates:
200 | mean of x
201 | 4.370427
202 | */
203 |
204 | ztest({x:x, mu:6, sd:2.5, alpha:0.05, op:"="}).report();
205 |
206 | ttest({x:x, y:y, mu:1, alpha:0.05, varequal:true, op:"="}).report();
207 |
208 | /*
209 | > t.test(x, y, mu=1, conf.level=0.95, var.equal=T, alternative="two.sided");
210 |
211 | Two Sample t-test
212 |
213 | data: x and y
214 | t = -0.8012, df = 18, p-value = 0.4335
215 | alternative hypothesis: true difference in means is not equal to 1
216 | 95 percent confidence interval:
217 | -2.122363 2.398395
218 | sample estimates:
219 | mean of x mean of y
220 | 4.370427 4.232411 */
221 |
222 | ttest({x:x, y:py, mu:-1, alpha:0.05, paired:true, op:"="}).report();
223 |
224 | /*
225 | > t.test(x, py, mu=-1, conf.level=0.95, paired=T)
226 |
227 | Paired t-test
228 |
229 | data: x and py
230 | t = -0.252, df = 9, p-value = 0.8067
231 | alternative hypothesis: true difference in means is not equal to -1
232 | 95 percent confidence interval:
233 | -2.33885689 0.07042649
234 | sample estimates:
235 | mean of the differences
236 | -1.134215 */
237 |
238 | ttest({x:x, y:y, mu:1, alpha:0.05, op:"="}).report();
239 |
240 | /*
241 | > t.test(x, y, mu=1, conf.level=0.95, alternative="two.sided");
242 |
243 | Welch Two Sample t-test
244 |
245 | data: x and y
246 | t = -0.8012, df = 17.985, p-value = 0.4335
247 | alternative hypothesis: true difference in means is not equal to 1
248 | 95 percent confidence interval:
249 | -2.122495 2.398527
250 | sample estimates:
251 | mean of x mean of y
252 | 4.370427 4.232411
253 | */
254 |
255 | ftest({x:x, y:y}).report();
256 |
257 | /*
258 | > var.test(x,y)
259 |
260 | F test to compare two variances
261 |
262 | data: x and y
263 | F = 0.9445, num df = 9, denom df = 9, p-value = 0.9337
264 | alternative hypothesis: true ratio of variances is not equal to 1
265 | 95 percent confidence interval:
266 | 0.2346094 3.8026974
267 | sample estimates:
268 | ratio of variances
269 | 0.9445362
270 | */
271 |
272 | var vx = [175, 176, 173, 175, 174, 173, 173, 176, 173, 179];
273 | vartest({x:vx, sd:2, alpha:0.05, op:"="}).report();
274 | // R 軟體沒有此函數,測試請看湯銀才 143 頁
275 | // 信賴區間 (1.793, 12.628)
276 |
277 | binomtest({x:7, n:12, p:0.4, op:">"}).report();
278 |
279 | /*
280 | > binom.test(x=7, n=12, p=0.4, alternative="less")
281 |
282 | Exact binomial test
283 |
284 | data: 7 and 12
285 | number of successes = 7, number of trials = 12, p-value = 0.9427
286 | alternative hypothesis: true probability of success is less than 0.4
287 | 95 percent confidence interval:
288 | 0.0000000 0.8189752
289 | sample estimates:
290 | probability of success
291 | 0.5833333
292 | */
293 |
294 | binomtest({x:7, n:12, p:0.4, op:"<"}).report();
295 | /*
296 | > binom.test(x=7, n=12, p=0.4, alternative="greater")
297 |
298 | Exact binomial test
299 |
300 | data: 7 and 12
301 | number of successes = 7, number of trials = 12, p-value = 0.1582
302 | alternative hypothesis: true probability of success is greater than 0.4
303 | 95 percent confidence interval:
304 | 0.3152378 1.0000000
305 | sample estimates:
306 | probability of success
307 | 0.5833333
308 | */
309 |
310 |
311 |
312 | binomtest({x:7, n:12, p:0.4}).report(); // 有誤,p-value 與 R 不同
313 |
314 | /*
315 | > binom.test(x=7, n=12, p=0.4)
316 |
317 | Exact binomial test
318 |
319 | data: 7 and 12
320 | number of successes = 7, number of trials = 12, p-value = 0.2417 ==> R.js ??? error : pvalue : 0.1146
321 | alternative hypothesis: true probability of success is not equal to 0.4
322 | 95 percent confidence interval:
323 | 0.2766697 0.8483478
324 | sample estimates:
325 | probability of success
326 | 0.5833333
327 | */
328 |
329 |
330 | proptest({x:91, n:100, p:0.9, correct:false}).report();
331 |
332 | /* 1-sample proportions test without continuity correction
333 |
334 | data: 91 out of 100, null probability 0.9
335 | X-squared = 0.1111, df = 1, p-value = 0.7389
336 | alternative hypothesis: true p is not equal to 0.9
337 | 95 percent confidence interval:
338 | 0.8377379 0.9519275
339 | sample estimates:
340 | p
341 | 0.91 */
342 |
343 | proptest({x:23, n1:102, y:25, n2:135, correct:false}).report();
344 |
345 | /*
346 | > success = c(23, 25)
347 | > total = c(102, 135)
348 | > prop.test(success, total)
349 |
350 | 2-sample test for equality of proportions with continuity correction
351 |
352 | data: success out of total
353 | X-squared = 0.3615, df = 1, p-value = 0.5477
354 | alternative hypothesis: two.sided
355 | 95 percent confidence interval:
356 | -0.07256476 0.15317478
357 | sample estimates:
358 | prop 1 prop 2
359 | 0.2254902 0.1851852
360 | */
361 |
362 | proptest({x:8, n1:100, y:12, n2:200, op:"<", correct:false}).report();
363 |
364 | /*
365 | > prop.test(c(8,12), c(100,200), alternative="greater", correct=F)
366 |
367 | 2-sample test for equality of proportions without continuity
368 | correction
369 |
370 | data: c(8, 12) out of c(100, 200)
371 | X-squared = 0.4286, df = 1, p-value = 0.2563
372 | alternative hypothesis: greater
373 | 95 percent confidence interval:
374 | -0.03248088 1.00000000 => R.js ??? [-0.0303,Infinity]
375 | sample estimates:
376 | prop 1 prop 2
377 | 0.08 0.06
378 | */
379 | 執行結果
380 |D:\Dropbox\Public\jslab\test>node rtest
381 | use ../source/R name=R
382 | use ../js/jstat.js name=jStat
383 | x=[7.1699,2.1889,2.9639,7.7906,2.4743,7.6948,1.585,4.0877,3.0516,4.6976]
384 | y=[4.9627,6.0336,-0.461,7.3744,2.4804,7.2053,3.5559,3.6505,2.2201,5.3021]
385 | =========== report ==========
386 | name : "ttest(X)"
387 | h : "H0:mu=6"
388 | alpha : 0.05
389 | op : "="
390 | pvalue : 0.0578
391 | ci : [2.6742,6.0667]
392 | df : 9
393 | mean : 4.3704
394 | sd : 2.3712
395 | =========== report ==========
396 | name : "ttest(X)"
397 | h : "H0:mu<6"
398 | alpha : 0.05
399 | op : "<"
400 | pvalue : 0.9711
401 | ci : [2.9959,Infinity]
402 | df : 9
403 | mean : 4.3704
404 | sd : 2.3712
405 | =========== report ==========
406 | name : "ttest(X)"
407 | h : "H0:mu>6"
408 | alpha : 0.05
409 | op : ">"
410 | pvalue : 0.0289
411 | ci : [-Infinity,5.745]
412 | df : 9
413 | mean : 4.3704
414 | sd : 2.3712
415 | =========== report ==========
416 | name : "ztest(X)"
417 | h : "H0:mu=6 when sd=2.5"
418 | alpha : 0.05
419 | op : "="
420 | pvalue : 0.0393
421 | ci : [2.9008,5.8401]
422 | df : 10
423 | =========== report ==========
424 | name : "ttest(X,Y,mu=1,varequal=true) (pooled)"
425 | h : "H0:mu1=mu2"
426 | alpha : 0.05
427 | op : "="
428 | pvalue : 0.4335
429 | ci : [-2.1224,2.3984]
430 | df : 18
431 | mean : "mean(x)=4.3704 mean(y)=4.2324"
432 | sd : "sd(x)=2.3712 sd(y)=2.4399"
433 | =========== report ==========
434 | name : "ttest(x,y,mu=-1,paired=true)"
435 | h : "H0:mu1=mu2"
436 | alpha : 0.05
437 | op : "="
438 | pvalue : 0.8067
439 | ci : [-2.3389,0.0704]
440 | df : 9
441 | mean : "mean(x-y)=-1.1342"
442 | sd : "sd(x-y)=1.684"
443 | =========== report ==========
444 | name : "ttest(x,y,mu=1,varequal=false), Welch t-test"
445 | h : "H0:mu1=mu2"
446 | alpha : 0.05
447 | op : "="
448 | pvalue : 0.4335
449 | ci : [-2.1225,2.3985]
450 | df : 17.9854
451 | mean : "mean(x)=4.3704 mean(y)=4.2324"
452 | sd : "sd(x)=2.3712 sd(y)=2.4399"
453 | =========== report ==========
454 | name : "ftest(X, Y)"
455 | h : "H0:σ1/σ2=1"
456 | alpha : 0.05
457 | op : "="
458 | pvalue : 0.9337
459 | ci : [0.2346,3.8027]
460 | df : [9,9]
461 | ratio : 0.9445
462 | =========== report ==========
463 | name : "chisqtest(X)"
464 | h : "H0:σ1=σ"
465 | alpha : 0.05
466 | op : "="
467 | pvalue : 0.9644
468 | ci : [1.7926,12.6278]
469 | df : 9
470 | =========== report ==========
471 | name : "binomtest({x:7,n:12,p:0.4,op:">"})"
472 | h : "H0:p>0.4"
473 | alpha : 0.05
474 | op : ">"
475 | pvalue : 0.9427
476 | ci : [0,0.819]
477 | df : 1
478 | p : 0.5833
479 | =========== report ==========
480 | name : "binomtest({x:7,n:12,p:0.4,op:"<"})"
481 | h : "H0:p<0.4"
482 | alpha : 0.05
483 | op : "<"
484 | pvalue : 0.1582
485 | ci : [0.3152,1]
486 | df : 1
487 | p : 0.5833
488 | =========== report ==========
489 | name : "binomtest({x:7,n:12,p:0.4})"
490 | h : "H0:p=0.4"
491 | alpha : 0.05
492 | op : "="
493 | pvalue : 0.2417
494 | ci : [0.2767,0.8483]
495 | df : 1
496 | p : 0.5833
497 | =========== report ==========
498 | name : "proptest({x:91,n:100,p:0.9,correct:false}), zprop1"
499 | h : "H0:p=0.9"
500 | alpha : 0.05
501 | op : "="
502 | pvalue : 0.7389
503 | ci : [0.8377,0.9519]
504 | df : 1
505 | p : 0.91
506 | =========== report ==========
507 | name : "proptest({x:23,n1:102,y:25,n2:135,correct:false,p:0.5}), zprop2"
508 | h : "H0:p1-p2=0"
509 | alpha : 0.05
510 | op : "="
511 | pvalue : 0.4446
512 | ci : [-0.063,0.1436]
513 | df : 1
514 | p : [0.2255,0.1852]
515 | =========== report ==========
516 | name : "proptest({x:8,n1:100,y:12,n2:200,op:"<",correct:false,p:0.5}), zprop2
517 | "
518 | h : "H0:p1-p2<0"
519 | alpha : 0.05
520 | op : "<"
521 | pvalue : 0.2563
522 | ci : [-0.0303,Infinity]
523 | df : 1
524 | p : [0.08,0.06]
525 |