ここは、技術情報、身の回りに起こった出来事を、「もしかしたらみんなの役に立つかもしれない」と思って書き留めておく場所です。

Image

jQueryとjqPlotで横棒グラフを作る

2013年4月1日
 

よくベンチマーク結果とか張ってるんですけど、やっぱりグラフで比較したいですよね。

ベンチマークといったら横棒グラフをよく見るので、それにしましょう。

普通はExcelで作ればいいんですかね?

なんの面白みもないのでjQueryで作りましょうか。

 

ステップ0 準備

jQueryで有名なグラフを描くプラグインはjqPlotです。

公式サイトから取ってきましょう。

一式取って来るとjQueryも含まれているようです。

jqPlotはプラグインで必要な機能を追加していく形式をとっていますので、プラグインのjsがいっぱいあります。

使うべきときに読み込んだり、置いたりしましょう。

ステップ1 横棒グラフを描く

こういうのは、公式のサンプルから取ってくるに限ります。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--[if lt IE 9]><script language="javascript" type="text/javascript" src="js/excanvas.min.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="js/jquery.min.js"></script>
<script language="javascript" type="text/javascript" src="js/jquery.jqplot.min.js"></script>
<link rel="stylesheet" type="text/css" href="js/jquery.jqplot.min.css" />
<script class="include" language="javascript" type="text/javascript" src="js/jqplot.barRenderer.min.js"></script>
<script class="include" language="javascript" type="text/javascript" src="js/jqplot.categoryAxisRenderer.min.js"></script>
<script class="include" language="javascript" type="text/javascript" src="js/jqplot.pointLabels.min.js"></script>
<!-- END: load jqplot -->
<title>横棒テスト</title>
</head>
<body>
<div id="chart1" style="width:600px; height:250px;"></div>
<script type="text/javascript">
$(document).ready(function(){
    // For horizontal bar charts, x an y values must will be "flipped"
    // from their vertical bar counterpart.
    var plot2 = $.jqplot('chart1', [
        [[2,1], [4,2], [6,3], [3,4]], 
        [[5,1], [1,2], [3,3], [4,4]], 
        [[4,1], [7,2], [1,3], [2,4]]], {
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            // Show point labels to the right ('e'ast) of each bar.
            // edgeTolerance of -15 allows labels flow outside the grid
            // up to 15 pixels.  If they flow out more than that, they 
            // will be hidden.
            pointLabels: { show: true, location: 'e', edgeTolerance: -15 },
            // Rotate the bar shadow as if bar is lit from top right.
            shadowAngle: 135,
            // Here's where we tell the chart it is oriented horizontally.
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        }
    });
});
</script>
</body>
</html>

 

そのままとってきて貼りました。

もう、ほとんど出来てるような感じですが。

まず、bodyタグの中にdivでグラフ用領域を指定してありますね。

そして、ドキュメント読み込み後に$.jqplotを実行しています。

結果は以下になります。

グラフ実行結果1

IE8以下用にexcanvas.min.jsを読み込んでいます。

jqplot.barRenderer.min.jsは棒グラフ用のプラグインです。

jqplot.categoryAxisRenderer.min.jsによって1~4のカテゴリに分けて各3本ずつ表示しています。これもプラグインです。

jqplot.pointLabels.min.jsは棒グラフの横の値を表示します。これもプラグインです。

ソースを見るとデータを記述している箇所とグラフ設定箇所が分かると思います。

ステップ1を実際に実行して見る場合はこちら

ステップ2 比較グラフっぽくする

ステップ1のグラフからちょっと改造します。

  • カテゴリ分けはベンチマークの各項目にする
  • 値は小数点OKにする
  • 縦幅が狭いので広げる
<body>
<div id="chart1" style="width:600px; height:400px;"></div>
<script type="text/javascript">
var CATE_PRO = 'プロセッサ';
var CATE_GRA = 'グラフィックス';
var CATE_GGR = 'ゲーム用グラフィックス';

$(document).ready(function(){
    var plot2 = $.jqplot('chart1', [
        [[7.8,CATE_PRO], [4.1,CATE_GRA], [6.5,CATE_GGR]], 
        [[5.2,CATE_PRO], [1.1,CATE_GRA], [3.2,CATE_GGR]], 
        [[4.3,CATE_PRO], [7.2,CATE_GRA], [1.5,CATE_GGR]]
		], 
		{
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'e', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        }
    });
});
</script>
</body>

 

body以外は同じなので省略します。

データの配列中からカテゴリを抜き取りました。

divのheightを広げました。

formatString:'%.1f' をpointLabelsに追加して小数点も表記するようにしました。

結果は以下になります。

グラフ実行結果2

 

かなりそれっぽい。

ステップ2を実際に実行して見る場合はこちら

ステップ3 凡例を表示する

各グラフが何のグラフなのか分からないので凡例を表示します。

<script type="text/javascript">
var CATE_PRO = 'プロセッサ';
var CATE_GRA = 'グラフィックス';
var CATE_GGR = 'ゲーム用グラフィックス';

$(document).ready(function(){
    var plot2 = $.jqplot('chart1', [
        [[7.8,CATE_PRO], [4.1,CATE_GRA], [6.5,CATE_GGR]], 
        [[5.2,CATE_PRO], [1.1,CATE_GRA], [3.2,CATE_GGR]], 
        [[4.3,CATE_PRO], [7.2,CATE_GRA], [1.5,CATE_GGR]]
		], 
		{
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'e', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        },
        series: [ {label: 'Celeron'}, {label: 'Pentium'} , {label: 'Xeon'}],
		legend: {
			show: true,
			placement: 'inside',
			location: 'ne'
		}
    });
});
</script>

 

seriesの部分が凡例の設定になります。

そこに、グラフの順に合わせてlabelを設定していきます。

設定のplacementはグラフ内か外か、locationは表示位置を東西南北で表記します。今回のneは北東の位置になります。

グラフ実行結果3

ステップ3を実際に実行して見る場合はこちら

ステップ4 データ部分を分ける

データ部分とグラフ設定部分を分けないと更新するとき面倒です。

分けます。

<script type="text/javascript">
var CATE_PRO = 'プロセッサ';
var CATE_GRA = 'グラフィックス';
var CATE_GGR = 'ゲーム用グラフィックス';

// データ書きやすいように
var cpu = [
	{
		name: 'Cereron',
		val_pro: 3.5,
		val_gra: 7.2,
		val_ggr: 6.3
	},
	{
		name: 'Pentium',
		val_pro: 3.6,
		val_gra: 7.0,
		val_ggr: 6.1
	}
];

// グラフ用に変換
var data = [];
var srs = [];

for (var i = 0; i < cpu.length; i ++) {
	data.push([
		[cpu[i].val_pro,CATE_PRO],
		[cpu[i].val_gra,CATE_GRA],
		[cpu[i].val_ggr,CATE_GGR]
	]);
	srs.push({label: cpu[i].name});
}

$(document).ready(function(){
    var plot2 = $.jqplot('chart1', data, 
		{
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'e', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        },
        series: srs,
		legend: {
			show: true,
			placement: 'inside',
			location: 'ne'
		}
    });
});
</script>

 

最初に各データをオブジェクトとして記述することにしました。

そして、それをjqPlotのデータと凡例に変換しています。

グラフ実行結果4

一応これでグラフに関しては完成です。

ステップ4を実際に実行して見る場合はこちら

ステップ5 グラフを画像化する

jqPlotはグラフを画像化することも出来ます。

これなら画像として保存もできますね。

<body>
<div id="chart1" style="width:600px; height:400px;"></div>
画像化
<div id="img_chart1" style="width:600px; height:400px;"></div>
<script type="text/javascript">
var CATE_PRO = 'プロセッサ';
var CATE_GRA = 'グラフィックス';
var CATE_GGR = 'ゲーム用グラフィックス';

// データ書きやすいように
var cpu = [
	{
		name: 'Cereron',
		val_pro: 3.5,
		val_gra: 7.2,
		val_ggr: 6.3
	},
	{
		name: 'Pentium',
		val_pro: 3.6,
		val_gra: 7.0,
		val_ggr: 6.1
	}
];

// グラフ用に変換
var data = [];
var srs = [];

for (var i = 0; i < cpu.length; i ++) {
	data.push([
		[cpu[i].val_pro,CATE_PRO],
		[cpu[i].val_gra,CATE_GRA],
		[cpu[i].val_ggr,CATE_GGR]
	]);
	srs.push({label: cpu[i].name});
}

$(document).ready(function(){
    var plot2 = $.jqplot('chart1', data, 
		{
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'e', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        },
        series: srs,
		legend: {
			show: true,
			placement: 'inside',
			location: 'ne'
		}
    });
	
	var imgdata = $('#chart1').jqplotToImageStr({});
	var elem = $('<img/>').attr('src', imgdata);
	$('#img_chart1').append(elem);
});
</script>
</body>

 

画像用のdivもbodyに用意しておきます。

$.jqplotを実行した後にjqplotToImageStrを実行して、imgタグを作っています。

結果はこちら。※IE8以下(excanvas.js)では画像化はできません。

グラフ実行結果5

上が元々のグラフ、下が画像化したものになります。

ブラウザ上でしたら違いが分かります。

ステップ5を実際に実行して見る場合はこちら(IE8以下は画像が出ません)

 

ということで、グラフを作ることができました。

よかったよかった。

 

と、ここで日にちが空いて、

 

ちょっと気になることが何点かあったので、直してみました。

 

凡例を逆に表示する

横棒グラフで凡例を出すと、グラフの順と逆に出るんですよね。

それを修正するにはグラフを作った後、凡例をjQueryで逆にします。

$(document).ready(function(){
    var plot2 = $.jqplot('chart1', data, 
		{
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'e', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        },
        series: srs,
	legend: {
		show: true,
		placement: 'inside',
		location: 'ne'
	}
    });
	
	// 凡例を逆に
	var legend = $("table.jqplot-table-legend tbody");
	legend.children().each(function(i, tr){legend.prepend(tr)});
	
	var imgdata = $('#chart1').jqplotToImageStr({});
	var elem = $('<img/>').attr('src', imgdata);
	$('#img_chart1').append(elem);
});

 

ソース中の「凡例を逆に」のコメント下2行です。ちゃんと以下のように凡例がグラフと同じ順に表示されます。

jqPlotの凡例を逆に表示する

 

背景色を変える

なんか、黄色っぽいので変えてみます。

    var plot2 = $.jqplot('chart1', data, 
		{
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'e', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        },
        series: srs,
	legend: {
		show: true,
		placement: 'inside',
		location: 'ne'
	},
	// 背景色
 	grid: {
                background: "#eeeeee"
        }
	});

 

背景色の部分のgridで指定しています。結果はこちら。

jqplot背景色を指定

 

値の色を黒に

背景色をグレーにしたら、値が目立たなくなりました。

値の色を指定しましょう。

パラメタにはないのでcssで変更しなければいけないようです。

$(document).ready(function(){
    var plot2 = $.jqplot('chart1', data, 
        {
        seriesDefaults: {
            renderer:$.jqplot.BarRenderer,
            pointLabels: { show: true, location: 'w', edgeTolerance: -15, formatString:'%.1f' },
            shadowAngle: 135,
            rendererOptions: {
                barDirection: 'horizontal'
            }
        },
        axes: {
            yaxis: {
                renderer: $.jqplot.CategoryAxisRenderer
            }
        },
        series: srs,
        legend: {
            show: true,
            placement: 'inside',
            location: 'ne'
        },
        // 背景色
        grid: {
                background: "#eeeeee"
            }
    });
    
    // 文字色
    $('.jqplot-point-label').css({'color':'black'});

    // 凡例を逆に
    var legend = $("table.jqplot-table-legend tbody");
    legend.children().each(function(i, tr){legend.prepend(tr)});
    
    var imgdata = $('#chart1').jqplotToImageStr({});
    var elem = $('<img/>').attr('src', imgdata);
    $('#img_chart1').append(elem);
});

 

グラフを作成し、その後文字色をjQueryのcssで変更しています。

ついでに、pointLabelsの指定を変えて値をグラフの中に入れました。

結果はこちら。

jqPlot文字色変更

見やすくなったので、良しとしましょう。