如何畫Flot堆疊折線圖、堆疊直條圖和堆疊橫條圖

當你有多組資料需要看到隨著時間變化的趨勢走向又需要看各組資料的累加總和時,這時候選擇用堆疊圖來呈現是最適合的,除了上述的優點外,堆疊圖還可以看各組資料的大小比例.這裡我們用了3個網站的一個月內DNS查詢次數來作範例資料.

堆疊圖範例 (DNS Query)

堆疊圖資料

因為Flot不支援堆疊圖,所以必須加入堆疊圖的外掛程式jquery.flot.stack.js,此範例會用到的檔案清單如下.
   
<script type="text/javascript" src="/js/jquery-1.8.3.min.js"></script>      
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="/js/flot/excanvas.min.js"></script><![endif]-->   
<script type="text/javascript" src="/js/flot/jquery.flot.js"></script>
<script type="text/javascript" src="/js/flot/jquery.flot.axislabels.js"></script>
<script type="text/javascript" src="/js/flot/jquery.flot.stack.js"></script>
<script type="text/javascript" src="/js/flot/jshashtable-2.1.js"></script>    
<script type="text/javascript" src="/js/flot/jquery.numberformatter-1.2.3.min.js"></script>
        
接著我們將網站的DNS查詢資料建立成如下的陣列格式,因為我們是用時間格式資料,所以建立了一個gd()函式用來取得javascript timestamps.這個範例我們用了3筆資料,為了簡化說明,我們這裡只顯示1筆資料出來,後面2筆資料格式都是一樣的,資料格式程式碼如下.
   
    var data = [
        [gd(2012, 1, 1), 208557], [gd(2012, 1, 2), 125068], [gd(2012, 1, 3), 931208], [gd(2012, 1, 4), 450040], 
        [gd(2012, 1, 5), 761180], [gd(2012, 1, 6), 744526], [gd(2012, 1, 7), 707095], [gd(2012, 1, 8), 601316],
        [gd(2012, 1, 9), 187495], [gd(2012, 1, 10), 716189], [gd(2012, 1, 11), 587141], [gd(2012, 1, 12), 147266], 
        [gd(2012, 1, 13), 574670], [gd(2012, 1, 14), 175881], [gd(2012, 1, 15), 272519], [gd(2012, 1, 16), 211131],
        [gd(2012, 1, 17), 637015], [gd(2012, 1, 18), 794050], [gd(2012, 1, 19), 399010], [gd(2012, 1, 20), 799942], 
        [gd(2012, 1, 21), 595768], [gd(2012, 1, 22), 717126], [gd(2012, 1, 23), 414923], [gd(2012, 1, 24), 462479],
        [gd(2012, 1, 25), 674334], [gd(2012, 1, 26), 20312], [gd(2012, 1, 27), 675892], [gd(2012, 1, 28), 808655], 
        [gd(2012, 1, 29), 194543], [gd(2012, 1, 30), 664716], [gd(2012, 1, 31), 980720]
    ];

    function gd(year, month, day) {
        return new Date(year, month - 1, day).getTime();
    }
        

堆疊圖選項

當你要畫堆疊圖時需要設定series.stack為true,這樣Flot就會以堆疊圖呈現,另外我們做的是堆疊折線圖,我們可以設定series.lines.fill為true,讓圖表用顏色填滿區塊,程式碼如下.
   
    series: {
        stack: true,
        lines: {
            show: true,
            fill: true
        }
    }
        
x軸和y軸部份我們一樣在<head>裡加入jquery.flot.axislabels.js檔案後用設定axis.axisLabel設定軸標籤名稱還有其它如字型大小及字型樣式等,因為我們是用時間格式資料,所以xaxis.mode必須設定用"time",因為資料是抓一個月份的資料,所以xaxis.tickSize設定成[3, "day"],3表示刻度標籤以每隔3天顯示,而"day"而表示以日期顯示,xaxis.tickLength我們設定為10,表示刻度線以高度10像素來顯示.而axis.color設定成"black",這表示刻度標籤的顏色,因為Flot預設的標籤顏色為灰色的,我們改成黑色的比較明顯.

另外yaxis.tickFormatter用來自行定義刻度標籤的格式.x軸及y軸選項程式碼如下.
   
    xaxis: {
        mode: "time",
        tickSize: [3, "day"],
        tickLength: 10,
        color: "black",
        axisLabel: "Date",
        axisLabelUseCanvas: true,
        axisLabelFontSizePixels: 12,
        axisLabelFontFamily: 'Verdana, Arial',
        axisLabelPadding: 10
    }

    yaxis: {
        color: "black",
        axisLabel: "DNS Query Count",
        axisLabelUseCanvas: true,
        axisLabelFontSizePixels: 12,
        axisLabelFontFamily: 'Verdana, Arial',
        axisLabelPadding: 3,
        tickFormatter: function (v, axis) {
            return $.formatNumber(v, { format: "#,###", locale: "us" });
        }
    }
        
選項的最後我們設定了網格的選項,因為我們有用到提示框的功能,所以grid.hoverable必須設為true才能顯示,此外我們還設定了圖表外框寬度grid.borderWidth,以及背景使用漸層色呈現grid.backgroundColor.
   
    grid: {
        hoverable: true,
        borderWidth: 2,        
        backgroundColor: { colors: ["#EDF5FF", "#ffffff"] }
    }
        

完成堆疊圖

最後一樣呼叫$.plot函式把資料及選項帶進去即完成.當你在畫堆疊折線圖時,其實就是把折線圖畫出來後設定series.stack:true及series.lines.fill:true而已,相信不會太難.下面我們還會介紹堆疊直條圖及堆疊橫條圖.
   
    $(document).ready(function () {
        $.plot($("#flot-placeholder"), dataset, options);
        $("#flot-placeholder").UseTooltip();
    });
        

堆疊圖直條圖

堆疊直條圖範例 (DNS Query)
我們沿用上面堆疊折線圖的程式碼,改成堆疊直條圖,只需要改選項裡的幾個地方,第一個將series.lines改成series.bars,然後只留下show屬性,另外再加上bars.align設定成"center"讓條圖對齊中央,還有bars.barWidth設定成24 * 60 * 60 * 600, 為什麼這樣設定barWidth,因為我們x軸是用時間格式資料的,也就是以毫秒為單位,所以24 * 60 * 60 * 1000就等於一天,不過最後我們是乘以600不是1000,因為我們不想讓條圖相互貼在一起,讓條圖之間留點空隙看起來比較好看.
   
    series: {
        stack: true,
        bars: {
            show: true
        }
    }

    bars: {
        align: "center",
        barWidth:24 * 60 * 60 * 600
    }
        

堆疊圖橫條圖

堆疊橫條圖範例 (DNS Query)
橫條圖就需要點功夫了,因為橫條圖是y軸顯示時間,x軸為數字,首先你要先把資料建立出來如下.
   
    var data = [
        [569106, gd(2012, 1, 1)], [743944, gd(2012, 1, 2)], [120865, gd(2012, 1, 3)], [890208, gd(2012, 1, 4)], 
        [259723, gd(2012, 1, 5)], [177150, gd(2012, 1, 6)], [32430, gd(2012, 1, 7)], [274054, gd(2012, 1, 8)],
        [63435, gd(2012, 1, 9)], [994514, gd(2012, 1, 10)], [885453, gd(2012, 1, 11)], [289791, gd(2012, 1, 12)],
        [411717, gd(2012, 1, 13)], [95324, gd(2012, 1, 14)], [646479, gd(2012, 1, 15)], [448868, gd(2012, 1, 16)],
        [669678, gd(2012, 1, 17)], [909944, gd(2012, 1, 18)], [675965, gd(2012, 1, 19)], [281272, gd(2012, 1, 20)], 
        [629781, gd(2012, 1, 21)], [330138, gd(2012, 1, 22)], [802835, gd(2012, 1, 23)], [139079, gd(2012, 1, 24)],
        [187101, gd(2012, 1, 25)], [354332, gd(2012, 1, 26)], [361090, gd(2012, 1, 27)], [78171, gd(2012, 1, 28)],
        [452212, gd(2012, 1, 29)], [404369, gd(2012, 1, 30)], [63509, gd(2012, 1, 31)]
    ];
        
接著設定bars.horizontal為true,若這裡沒設定就會顯示成直條圖,然後再設定yaxis.mode為"time",表示y軸以時間格式顯示,另外我們還設定了yaxis.min及yaxis.max,如此可限制y軸刻度顯示的最大及最小值.完整的選項程式碼如下.
   
    var options2 = {
        series: {
            stack: true,
            bars: {
                show: true
            }
        },
        bars: {
            lineWidth: 1,
            barWidth: 24 * 60 * 60 * 450,
            horizontal: true
        },
        xaxis: {
            color: "black",
            axisLabel: "Date",
            axisLabelUseCanvas: true,
            axisLabelFontSizePixels: 12,
            axisLabelFontFamily: 'Verdana, Arial',
            axisLabelPadding: 10,
            tickFormatter: function (v, axis) {
                return $.formatNumber(v, { format: "#,###", locale: "us" });
            }
        },
        yaxis: {
            mode: "time",
            tickSize: [3, "day"],
            min: gd(2012, 1, 1),
            max: gd(2012, 1, 31),
            tickLength: 10,        
            color: "black",
            axisLabel: "DNS Query Count",
            axisLabelUseCanvas: true,
            axisLabelFontSizePixels: 12,
            axisLabelFontFamily: 'Verdana, Arial',
            axisLabelPadding: 3
        },
        grid: {
            hoverable: true,
            borderWidth: 2,
            backgroundColor: { colors: ["#EDF5FF", "#ffffff"] }
        }
    };
        

練習

本章的完整範例程式碼可以在這裡找到並做線上練習 Go to Example Tester