プログラミングトピック グラフの背景のカスタマイズ

業務システムにおけるグラフ仕様では、折れ線グラフや棒グラフの背景を、特定の値を境に色分けしたり、背景にデータと関連する画像を表示したりする場合があります。

JClass ServerChartでは、通常のプロパティ設定により、グラフをプロットする領域の背景色を指定できます。しかし、値領域ごとに塗り分けたり、画像を表示する際には、ランタイムに含まれるクラスを継承して、任意の描画を行う新しいグラフクラスを作成する必要があります。

今回の特集では、グラフ背景をカスタマイズする方法を、ソースコードや出力サンプルを交えて詳しくご紹介します。

1. グラフ全体の背景に画像を使用する

グラフ全体の背景に画像を表示する場合、比較的シンプルに出力できます。

サンプル画像

画像「サンプルチャート1」

com.klg.jclass.schart.JCServerChartを継承したクラスを作成し、背景を塗りつぶさないように設定します。paint()メソッドをオーバーライドしてイメージを描画した後、通常のようにグラフを描画します。

グラフ背景全体に画像を表示するクラスのサンプルコード(抜粋)
public class MyJCChart extends JCServerChart{
 
 ImageObserver image_observer;
 Image img;
 
 public MyJCChart( int type , Image image){
  
  super( type );
  
  // 背景を塗りつぶさない
  this.setOpaque(false);
  
  this.getDataView(0).setDataSource(
   new JCEditableDataSource(xData, yData, null, null, ""));
  
  this.img = image;
  
  this.image_observer = this;
  
  setSize( ImageWidth , ImageHeight );
  
  setForeground(Color.green);
  
 }
 
 public void paint(Graphics g){
  
  // イメージで背景を描画します
  g.drawImage( img , 0 , 0 , image_observer );
  
  // グラフを描画します
  super.paint( g );
  
 }
}

» Javaソースファイル : SampleChart01.java

2. プロット領域の背景に画像を使用する

プロット領域(com.klg.jclass.chart.PlotArea)とは、折れ線グラフや棒グラフにおいて、X軸とY軸の間の折れ線や棒が描かれる領域を指します。グラフ背景に画像を表示する際、1.のように全体に表示するのではなく、プロット領域のみに表示するケースもあります。

サンプル画像

画像「サンプルチャート2」

プロット領域にのみ画像を出力する場合も、基本的な手順は1.と同じです。ただし、画像を出力する際に、グラフ全体ではなく、プロット領域の座標に対して出力する点が異なります。プロット領域の座標を取得するには、プロット領域に軸や注釈を含んだ領域であるグラフ領域(com.klg.jclass.chart.JCChartArea)のgetPlotRect()メソッドを利用します。

プロット領域の座標を取得する際に、注意すべきことがあります。それは、encodeToPNGFile()のようなイメージ出力メソッドと同等の処理を実行した後でなければ、JCServerChartオブジェクト上に配置されたプロット領域やグラフ領域の有効な座標が取得できない、という点です。

JCServerChartには、イメージファイルを出力せずに座標を取得するために、doLayout()というメソッドが用意されています。あらかじめこのメソッドをコールすることで、JCServerChart上に配置されたオブジェクトが展開され、各オブジェクトの座標が取得できるようになります。なお、正しい座標を得るためには、このメソッドを実行する前にグラフに対してすべてのデータやプロパティが設定されている必要があります。

プロット領域の座標を取得するサンプルコード(抜粋)
private void CheckPlotSize(){
 
 // グラフ内のオブジェクトを一度展開して各座標を取得する用意をする
 doLayout();
 
 // プロット領域の始点座標(x値)
 x_plotpoint = getChartArea().getBounds().getX() + 
   getChartArea().getPlotRect().getX();
 
 // プロット領域の始点座標(y値)
 y_plotpoint = getChartArea().getBounds().getY() + 
   getChartArea().getPlotArea().getTop();

 // プロット領域の幅
 x_plotwidth = getChartArea().getPlotRect().getWidth();
  
 // プロット領域の高さの取得
 y_plotheight = getChartArea().getPlotRect().getHeight();
 
}

» Javaソースファイル : SampleChart02.java

3. プロット領域の背景をしきい値で塗り分ける

折れ線グラフなどで特定の値領域を強調するために、その部分の背景色を変えることがあります。例えば、y値がある値以上の領域の背景のみ、警告を表す赤にする、といった利用方法です。

サンプル画像

画像「サンプルチャート3」

このようなグラフを出力するには、データ値をグラフ上の座標に変換するメソッドを使用します。com.klg.jclass.chart.ChartDataViewクラスのdataCoordToCoord()メソッドは、x値とy値を引数として渡すことで、そのデータに対応する座標を取得できます。

このメソッドで取得したしきい値の座標と、2.のプロット領域の座標を組み合わせることで、データ値によるプロット領域の塗り分けを実現します。

プロット領域の背景をしきい値で塗り分けるサンプルコード(抜粋)
private void CheckPlotSize(){
 
 (中略)
 
 // 背景塗り分けを行う際の、ボーダーとなるデータの座標
 Point borderpoint = 
   getDataView(0).dataCoordToCoord( 0 , bordervalue );
 
 // PlotAreaのy値からボーダーとなるデータのy値までの差
 y_borderoffset = borderpoint.y - y_plotpoint;
 
}

» Javaソースファイル : SampleChart03.java

4. プロット領域のサイズを制御する

これまで、プロット領域の座標を元にしたカスタマイズ方法を説明してきました。このプロット領域の座標は、JClass ServerChartのランタイムクラスの実行結果として取得できます。これに対して、あらかじめ画像のサイズが仕様で固定されている場合などでは、逆にプロット領域のサイズを画像にあわせて調節する必要があります。プロット領域のサイズをユーザープログラムから制御するには、グラフ領域とのマージンを変更します。

プロット領域の固定が必要な例として、2つのグラフを並べて表示するケースを考えてみましょう。JClass ServerChartでは、軸や凡例など、グラフ上のオブジェクトや表示するテキストにより、プロット領域のサイズが動的に調整されます。そのため、2つのグラフを生成した場合、ほとんどの場合プロット領域の座標やスケールは異なっています。

しかし、一方のグラフのプロット領域のサイズを元に、もう一方のグラフのプロット領域のマージンを調節することで、データ数の異なる2つのグラフであっても、プロット領域の座標やスケールを合わせることができます。

サンプル画像

画像「サンプルチャート4」

画像「サンプルチャート5」

このサンプルでは、まずデータ数の多いグラフを作成し、そのプロット領域の末端のx座標を変数に退避しています。次に、データ数の少ないグラフを作成する際に、保存しておいた座標にあわせてプロット領域のサイズを変更しています。

また、Y軸の注釈のサイズにより、プロット領域のサイズが影響を受けないように、プロット領域左側のマージンを大きめに固定しています。

プロット領域のサイズを制御するサンプルコード(抜粋)
public class MyJCChart extends JCServerChart{
 
 (中略)
 
 public MyJCChart(int type , int flag ){
  
 (中略)
  
  // Y軸の注釈サイズによる影響を避けるため
  // プロット領域の左マージンを広く取る
  getChartArea().getPlotArea().setLeft(40);
  
  doLayout();
  
  // flag==0がデータ数の多いグラフ
  if(flag == 0){
    
    // データ数が少ないグラフの、X軸上最大値(4)の
    // データ数が多いグラフの上での座標を変数に退避
    Point borderpoint = getDataView(0).dataCoordToCoord( 4 , 0 );
    
    x_plotpoint = borderpoint.x;
    
  }else{
    
    // 保持しておいた座標を元に、データ数の少ないグラフの
    // プロット領域のサイズを調整
    double x_margin = GraphWidth - x_plotpoint - 
      ( GraphWidth - ( getChartArea().getBounds().getX() + 
      getChartArea().getBounds().getWidth() ) );
    
    getChartArea().getPlotArea().setRight( (int)x_margin );
    
  }
 }
}

» Javaソースファイル : SampleChart04.java

まとめ : JClass ServerChartのポテンシャルを引き出すAPI群

JClass ServerChartは、GUIデザイナだけで基本的なグラフ設計が可能です。しかし、データや画像によって背景を動的に変更するような、複雑なグラフを出力するには、デザイナの機能に加えてJavaプログラムとの連携が必要になります。JClass ServerChartのAPI群は、デザイナよりも多くのプロパティを、よりフレキシブルに設定できます。

今回紹介したサンプルは、いずれもAPIを用い、また継承クラスなど一般的なJavaプログラミングのテクニックを組み合わせて、デザイナ単体では設計できないグラフのカスタマイズを実現しています。

プロット領域の座標取得やサイズ制御は、背景のカスタマイズだけではなく、さまざまな場面で応用できます。例えば、グラフ上の任意の位置にラベルを表示したり、グラフイメージを他のHTMLの座標に同期させる場合も、ベースになるこれらのテクニックを押さえることで、柔軟に対応できるようになります。

JClass ServerChart APIを活用し、ユーザーニーズを満たすグラフ表現を実現してください。