【公告】網站目前停止所有的課程訂閱服務,原有學員權益不受影響,造成不便還請見諒,我們正在打造更多課程以及圖書,包含 Python 為主的課程主題,未來將會合併且擴充目前的課程內容,提供全新課程訂閱服務,感謝學員的支持。

金融股價資料的 SVG 圖形化輸出

商業圖表的描繪,必須透過程式化控制的技巧,將取得的資料轉換成為對應的圖表,JSON是目前最通用的資料格式,例如以下的資料:

prices = [
    { "Year": 101, "Price": 80 }, { "Year": 102, "Price": 120 },
    { "Year": 103, "Price": 250 }, { "Year": 104, "Price": 150 },
    { "Year": 105, "Price": 350 }, { "Year": 106, "Price": 310 }];

這是一組陣列,其中包含六組虛擬的JSON格式資料,表示某上市公司特定年度的平均股價,從 101 年到 106 年,每一組資料中, Year 表示年份, Price 表示股價,每一組資料都可以利用陣列索引格式 prices[index] 的格式將其取出。透過 for 迴圈可以非常方便的解析其中的內容,例如以下的程式碼:

for(key in prices){
    var p = prices[key] ;
    var year = p.Year ;
    var price = p.Price ;
    content += ("Year:"+year+","+ "Price:"+price) + "\n" ;
}

其中每一次 for 迴圈取出的 key 是prices 的索引鍵值,透過於中括弧傳入 key 可以回傳某個特定索引鍵對應的資料,每一筆資料再經由 Year 與 Price 屬性,取得對應的屬性值即可取出所有的資料內容。

以下列舉完整的範例程式碼:

<body>
    <textarea id="xcontent" cols="60" rows="8" style="font-size:1.4em;"></textarea>
    <script>
        prices = [
            { "Year": 101, "Price": 80 }, { "Year": 102, "Price": 120 },
            { "Year": 103, "Price": 250 }, { "Year": 104, "Price": 150 },
            { "Year": 105, "Price": 350 }, { "Year": 106, "Price": 310 }];

        var content = "" ; 
        for(key in prices){
            var p = prices[key] ;
            var year = p.Year ;
            var price = p.Price ;
            content += ("Year:"+year+","+ "Price:"+price) + "\n" ;
        }
        document.getElementById("xcontent").textContent = content;
    </script>
</body>

在 body 配置多行文字方塊 textarea ,以以方便呈現取出的陣列資料。

接下來的 Script 區塊中,首先配置測試用的 JSON 陣列格式資料 prices ,利用迴圈逐一取出其中六筆 JSON 格資料,然後以斷行符號合併成列舉格式的長字串,儲存於變數 content ,最後設定為文字方塊的內容顯示在畫面上。



比對 prices 陣列的內容,顯示在輸出結果中。

由於我們已經具備程式化控制 svg 元素的能力,現在針對其中取出的資料,逐一轉換成對應的圖形輸出,以 Year 屬性為 x 軸座標,而 Price 屬性為 y 軸座標,描繪成圓形輸出,顯示六組資料的分佈。

</body>
    <svg id="csvg" width="800" height="450"
         style="background-color:#ecf0fc;">
    </svg>
    <script>
        var ns = "http://www.w3.org/2000/svg";
        var svg = document.getElementById("csvg");
        var r = 2;
        prices = [
            { "Year": 101, "Price": 80 }, { "Year": 102, "Price": 120 },
            { "Year": 103, "Price": 250 }, { "Year": 104, "Price": 150 },
            { "Year": 105, "Price": 350 }, { "Year": 106, "Price": 310 }];
         
        for (key in prices) {
            var p = prices[key] ;
            var x = (p.Year-100)*100 ;
            var y = p.Price ;
            //以圓形表示每一組資料
            var circle = document.createElementNS(ns, "circle");
            circle.setAttributeNS(null, "cx", x);
            circle.setAttributeNS(null, "cy", y);
            circle.setAttributeNS(null, "r", r);
            circle.setAttributeNS(null, "fill", "#ff0000");
            svg.appendChild(circle);
            //描繪文字顯示資料內容
            var ptag = "Year:"+ p.Year +  " - Price:"+ p.Price ;
            var text =  document.createElementNS(ns, "text");
            text.setAttributeNS(null, "x", x+10);
            text.setAttributeNS(null, "y", y);
            text.setAttributeNS(null, "fill", "#000");
            text.textContent = ptag ;
            svg.appendChild(text);
        }
    </script>
</body>

首先配置一組 svg 元素,以支援圖形描繪。

在 for 選圈中,根據上述的說明,逐一取出每一組 JSON 格式資料,並轉換成為要描繪的圖形圓心座標, x 座標值是取得每一個年度減掉 100 後的值再乘上 100以擴展 x 軸的座標值,而 y 軸座標值則直接以表示股票價格的 Price 屬性值作表示。

接下來依序建立圓形描繪所需的屬性。

最後一段程式碼,則將取出的資料,依序以 text 標籤進行呈現,由於作為標示,因此 x 座值加上 10 以偏離圓形的所在位置。



在輸出結果中,每一組資料現在透過圓形在特定的座標位置呈現,並標示其代表的資料值,我們完成了最簡單的資料圖像化設計。

最後以實際的資料進行示範,金融領域每天產生的大量資料,非常適合轉換為各種圖表,這裏來看比較簡單的數據,以下是台積電歷年平均股價的 JSON 格式資料:

var yprices =[{ "Year": "83", "aprice": "159.04" }, { "Year": "84", "aprice": "128.43" }, { "Year": "85", "aprice": "63.83" }, { "Year": "86", "aprice": "109.45" }, { "Year": "87", "aprice": "100.74" }, { "Year": "88", "aprice": "120.01" }, { "Year": "89", "aprice": "146.30" }, { "Year": "90", "aprice": "77.74" }, { "Year": "91", "aprice": "67.42" }, { "Year": "92", "aprice": "56.42" }, { "Year": "93", "aprice": "52.36" }, { "Year": "94", "aprice": "54.08" }, { "Year": "95", "aprice": "61.34" }, { "Year": "96", "aprice": "65.52" }, { "Year": "97", "aprice": "56.44" }, { "Year": "98", "aprice": "55.48" }, { "Year": "99", "aprice": "62.01" }, { "Year": "100", "aprice": "72.09" }, { "Year": "101", "aprice": "84.08" }, { "Year": "102", "aprice": "104.09" }, { "Year": "103", "aprice": "122.53" }, { "Year": "104", "aprice": "139.84" }, { "Year": "105", "aprice": "166.36" }, { "Year": "106", "aprice": "210.09" }];

同樣的,利用 for 迴圈將其中的資料逐一取出,並且配置 svg 標籤,進行圖表的實作,由於我們希望建立一個比較完整的圖表,因此預先配置需要的基礎圖表:

<svg id="csvg" width="800" height="450" style="background-color:#ecf0fc;">
    <line x1="100" y1="50" x2="100" y2="350" stroke="#000" stroke-width="0.5"></line>
    <line x1="100" y1="350" x2="700" y2="350" stroke="#000" stroke-width="0.5"></line>
    <text x="30" y="50">(股價)</text>
    <text x="700" y="375">(年度)</text>
    <text x="400" y="25" text-anchor="middle" fill="#4169e1" font-size="20"> 台積電(2330)歷年股價 </text>
    <line x1="100" y1="100" x2="700" y2="100" stroke="#a0b4f0" stroke-width="0.5"></line>
    <text x="50" y="100">250</text>
    <line x1="100" y1="150" x2="700" y2="150" stroke="#a0b4f0" stroke-width="0.5"></line>
    <text x="50" y="150">200</text>
    <line x1="100" y1="200" x2="700" y2="200" stroke="#a0b4f0" stroke-width="0.5"></line>
    <text x="50" y="200">150</text>
    <line x1="100" y1="250" x2="700" y2="250" stroke="#a0b4f0" stroke-width="0.5"></line>
    <text x="50" y="250">100</text>
    <line x1="100" y1="300" x2="700" y2="300" stroke="#a0b4f0" stroke-width="0.5"></line>
    <text x="50" y="300">50</text>
</svg>

這會建立包含x、y 軸的內容,接下來利用 JavaScript ,逐一解析 JSON 陣列中的每一筆資料,描繪股價變化圖。

for (key in yprices) {
    var cx = 100 + (yprices[key].Year - yprices[0].Year + 1) * 23;
    var cy = 350 - yprices[key].aprice;
    // 1. 以每一筆資料的年度與股價為座標描繪圓形顯示股價分佈
    var circle = document.createElementNS(ns, "circle");
    circle.setAttributeNS(null, "cx", cx);
    circle.setAttributeNS(null, "cy", cy);
    circle.setAttributeNS(null, "r", r);
    circle.setAttributeNS(null, "fill", "#ff0000");
    svg.appendChild(circle);
    // 2. 連接每一個年度的價格顯示股價波動
    if (x1 != -1) {
        var line = document.createElementNS(ns, "line");
        line.setAttributeNS(null, "x1", x1);
        line.setAttributeNS(null, "y1", y1);
        line.setAttributeNS(null, "x2", cx);
        line.setAttributeNS(null, "y2", cy);
        line.setAttributeNS(null, "stroke", "#4169e1");
        svg.appendChild(line);
    }
    x1 = cx;
    y1 = cy;
    // 3. x 年度值
    var text = document.createElementNS(ns, "text");
    text.textContent = yprices[key].Year;
    text.setAttributeNS(null, "x", cx);
    text.setAttributeNS(null, "y", 360);
    text.setAttributeNS(null, "transform", "rotate(75," + cx + ",360)")
    svg.appendChild(text);
    // 4. y 股價
    var liney = document.createElementNS(ns, "line");
    liney.setAttributeNS(null, "x1", cx);
    liney.setAttributeNS(null, "y1", 345);
    liney.setAttributeNS(null, "x2", cx);
    liney.setAttributeNS(null, "y2", 350);
    liney.setAttributeNS(null, "stroke", "#4169e1");
    svg.appendChild(liney);
}

for 迴圈每一取出的資料會執行四個動作,每一個動作是一段程式碼。

第一段程式描繪圓形以呈現股價的分佈,第二段程式碼以直線連接各組資料輸出股價波動情形。

第三段以及第四段,則進一步在 基礎圖形的 x 軸與 y 軸上,顯示年度以及股價標示。



輸出結果中,我們可以看到數字轉換成圖表的輸出結果,相較於數字可以更容易看出股價的波動情形。




沒有留言: