FlexのColumnChartとLineChartを組み合わせてみる

2011.08.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

FlexのColumnChartとLineChartを組み合わせてQC7つ道具パレート図を作ってみました。
パレート図は障害の原因を要因別にして件数を棒グラフ、累積比を折れ線グラフで示した図です。
要因は件数が多い順に左から並べられます。

[SWF]http://public-blog-dev.s3.amazonaws.com/wp-content/uploads/2011/08/SampleChart.swf, 500, 310[/SWF]

このサンプルを見るにはFlash Playerがインストールされている必要があります。


ポイントは以下の2点です。
①dataTipFunctionは一番親のColumnChartに設定するので、
ColumnChart、LineChartどちらでロールオーバーしても同じ情報が表示されてます。
ですのでdataTipFunction内でどちらなのか判別しています。

②AxisRendererを複数設定することによって左右に軸を表示します。
棒グラフが件数で累積比が%なので同じ軸にはできず左右に軸を表示しました。

以下がサンプルのソースです。
Flex SDK 4.5.1を使っています。

<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
			   initialize="initializeHandler(event)">
	
	<fx:Script>
		<![CDATA[
			import mx.charts.HitData;
			import mx.charts.series.items.ColumnSeriesItem;
			import mx.collections.ArrayCollection;
			import mx.events.FlexEvent;
			import mx.events.ListEvent;
			import mx.formatters.NumberBaseRoundType;
			import mx.formatters.NumberFormatter;
			
			private var total:int = 0;
			private var formatter:NumberFormatter;
			
			[Bindable] 
			public var dataAC:ArrayCollection = new ArrayCollection( [
				{reason: "要因1", count: 56},
				{reason: "要因2", count: 32},
				{reason: "要因3", count: 24},
				{reason: "要因4", count: 17},
				{reason: "要因5", count: 15},
				{reason: "要因6", count: 6}]);
			
			private function initializeHandler(event:FlexEvent):void{
				
				// 件数を合算する
				var p:int = 0;
				for each(var o:Object in dataAC) {
					p += o.count;
					o.accumulate = p;
					total += o.count;
				}
				
				//NumberFormatterの初期化
				formatter = new NumberFormatter();
				formatter.precision = 2;
				formatter.rounding = NumberBaseRoundType.NEAREST;
			}
			
			/**
			 * 折れ線グラフのparseFunction
			 */
			private function lineChartParseFunction(str:String):Object {
				return int(str) / total * 100;
			}
			
			/**
			 * dataTipFunction
			 */
			private function dataTipFunction(hitData:HitData):Object {
				
				var item:Object = hitData.item;
				var count:int = item.count;
				
				if(hitData.chartItem is ColumnSeriesItem) {
					// 棒グラフの場合
					return hitData.item.reason + 
						"\n発生件数:" + count;
				} else {
					// 折れ線グラフの場合
					var percent:Number = item.accumulate / total * 100;
					return "累積構成比:" + formatter.format(percent) + "%";
				}
			}
			
		]]>
	</fx:Script>
	
	
	<s:VGroup paddingTop="10" paddingLeft="10">
		<s:HGroup width="100%">
			<s:Label text="発生件数"/>
			<s:Spacer width="100%"/>
			<s:Label text="累積構成比(%)"/>
		</s:HGroup>
		
		<mx:ColumnChart id="chart" height="300" width="500"
						showDataTips="true" dataProvider="{dataAC}"
						dataTipFunction="dataTipFunction">
			
			<mx:horizontalAxis>
				<mx:CategoryAxis categoryField="reason"/>
			</mx:horizontalAxis>
			
			<mx:verticalAxisRenderers>
				<mx:AxisRenderer placement="left" axis="{axis1}"/>
				<mx:AxisRenderer placement="right" axis="{axis2}"/>
			</mx:verticalAxisRenderers>
			
			<mx:series>
				<mx:ColumnSeries yField="count" xField="reason" displayName="件数">
					<mx:verticalAxis>
						<mx:LinearAxis id="axis1" baseAtZero="true" />
					</mx:verticalAxis>
				</mx:ColumnSeries>
				
				<mx:LineSeries yField="accumulate" xField="reason" displayName="累積構成比" radius="10" >            
					<mx:verticalAxis>
						<mx:LinearAxis id="axis2" baseAtZero="true" 
									   parseFunction="lineChartParseFunction"/>
					</mx:verticalAxis>
				</mx:LineSeries>
			</mx:series>
		</mx:ColumnChart>
		
		<mx:Legend dataProvider="{chart}" direction="horizontal"/>
		
	</s:VGroup>
</s:Application>