ウェブでグラフをお気楽に動的に生成したいときはGoogle Chart APIがとても便利です。それではこのGoogle Chart APIの使い方を勉強しましょう。とりあえず下のURLをブラウザにコピペしてみましょう。
http://chart.apis.google.com/chart?cht=lc&chs=300x200&chxt=x,y&chxtc=0,5|1,5&chxr=0,0,1.0E2|1,0,5.35E1&chds=0,5.35E1&chtt=Premium&chco=00FF00&chd=t:0,0,7.05E-6,2.59E-3,6.39E-2,4.54E-1,1.64E0,3.99E0,7.55E0,1.21E1,1.75E1,2.33E1,2.94E1,3.57E1,4.21E1,4.86E1

すると下のようなグラフがでてくるはずです。
(このグラフもGoogle Chart APIで直接生成しています。)
Google Chart API実験

Google Chart APIとはこのようにURLにパラメータをいろいろ貼りつけてポンとチャートを作るサービスです。もちろん無料です。さまざまなことができるのですが、今日は一番良く使いそうなライン・チャートを勉強します。

http://chart.apis.google.com/chart?

この後にどんどんパラメータをわたしてやります。

cht=lc これはこのチャートの種類がライン・チャートですよとGoogleに教えています。
chs=300x200 300ピクセルx200ピクセルのチャートを作ります。
chxt=x,y 目盛りはx軸とy軸に用意します。
chxtc=0,5|1,5 x軸の補助目盛りとy軸の補助メモリをそえぞれ5ピクセルにします。
chxr=0,0,1.0E2|1,0,5.35E1 x軸(0)の範囲は0.0〜100、y軸(1)の範囲は0.0〜53.5です。
chds=0,5.35E1 y軸のスケールを教えてやります。
chtt=Premium チャートのタイトルです。
chco=00FF00 線の色です。

chd=t:0,0,7.05E-6,2.59E-3,6.39E-2,4.54E-1,1.64E0,3.99E0,7.55E0,1.21E1,1.75E1,2.33E1,2.94E1,3.57E1,4.21E1,4.86E1
最後のところでyの値を全部教えます。xの値を指定しなくていいのはこのライン・チャートではyのデータは等間隔にx軸上に並んでいると仮定されるからです。
ここがちょっとわかりにくいところなんですが、y軸の目盛りに何を指定しようとも、デフォルトではy軸は0が一番下で100が一番上になっていることです。chxrによるy軸の範囲の指定はあくまで見た目を変えるだけなのです。

そこで0〜100になるように元のデータを加工するか、y軸のスケールを明示的に変えてやる必要があります。後者のほうが簡単で、chdschxrと同じにしてやればOKです。

最後に参考のために、ライン・チャート用のURLを生成するJavaのクラスをコピペしておくので、必要な方は使ってみてください。バグを見つけたり、改善したりしたら教えてくれたらありがたいです(笑)。

参考資料
Google Chart Tools / Image Charts (aka Chart API)
Googleプログラミング入門、掌田津耶乃


Google Chart API 入門 その1 ライン・チャート
Google Chart API 入門 その2 その他のチャート
Google Chart API 入門 その3 数式


/**
* A class to generate a URL Get request for a line chart with Google API Chart
*
* @author Kazuki Fujisawa
*
*/
public class googleXYChart
{
 /**
  * @param xyData
  *
  * xyData[0][0,1,...n]: x date set, xyData[1][0,1,...n]: y date set.
  * x data points have to be placed evenly and in ascending order across the x-axis.
  */
 public googleXYChart(
   double[][] xyData
   )
 {
  data = xyData;
  numData = xyData[0].length;
  setXrange();
  setYrange();
 }

 /**
  * @param xSize chart x-size
  * @param ySize chart y-size
  */
 public void setSize(int xSize, int ySize)
 {
  x_size = xSize;
  y_size = ySize;
 }

 /**
  * @param chartTitle chart title
  * Space is +, eg., Kazuki Fujisawa is "Kazuki+Fujisawa"
  */
 public void setTitle(String chartTitle)
 {
  title = chartTitle;
 }

 /**
  * @param lineColor chart color
  * Red: FF0000, Green: 00FF00, Blue: 0000FF
  */
 public void setColor(String lineColor)
 {
  color = lineColor;
 }

 /**
  * @return A URL Get request
  */
 public String getChartURL()
 {
  String url = "http://chart.apis.google.com/chart?cht=lc&";
  url += "chs=" + Integer.toString(x_size) + "x" + Integer.toString(y_size)+ "&";
  url += "chxt=x,y&";
  url += "chxtc=0,5|1,5&";
  url += "chxr=0," + getStrEfficientRound(x_start,4) + "," + getStrEfficientRound(x_end,4) + "|";
  url += "1," + getStrEfficientRound(y_start,4) + "," + getStrEfficientRound(y_end,4) + "&";
  url += "chds=" + getStrEfficientRound(y_start,4) + "," + getStrEfficientRound(y_end,4) + "&";

  if(title!=null)
  {
   url += "chtt=" + title + "&";
  }

  if(color!=null)
  {
   url += "chco=" + color + "&";
  }

  url += "chd=t:";
  for(int i=0;i   {
   url += getStrEfficientRound(y[i],5);
   
   if(i!=numData-1)
   {
    url += ",";
   }
   else
   {
    url += "";    
   }
  }

  return url;
 }
 
 /**
  * @param value double value which will be rounded and converted into a String.
  * @param effectiveDigit effective digit for the rounding
  * @return String in the form of #.###E# like 1.2345E6
  */
 public static String getStrEfficientRound(double value, int effectiveDigit)
 {
  if(value == 0.0)
  {
   return "0";
  }
  
  int valueDigit = 0;
  double absValue = Math.abs(value);
  String sign = null;
  if(value < 0.0)
  {
   sign = "-";
  }
  else
  {
   sign = "";
  }
  
  valueDigit = (int)Math.floor(Math.log10(absValue));
    
  if(valueDigit < -10)
  {
   return "0";
  }

  double effNumber = absValue / Math.pow(10.0, (double)valueDigit);
  effNumber = (int)Math.round(effNumber*Math.pow(10.0, (double)(effectiveDigit-1)));
  effNumber = effNumber/Math.pow(10.0, (double)(effectiveDigit-1));

  String z = Double.toString(effNumber);
  
  if(z.length() <= effectiveDigit+1)
  {
   return sign + z + "E" + Integer.toString(valueDigit);
  }
  else
  {
   return sign + z.substring(0,effectiveDigit+1) + "E" + Integer.toString(valueDigit);
  }
 }

 private void setXrange()
 {
  x_start = data[0][0];
  x_end = data[0][numData-1];
 }

 private void setYrange()
 {
  setYminYmax();
  y = data[1];
  
  if((yMax-yMin)==0.0)
  {
   if(yMax==0.0)
   {
    y_start = -1.0;
    y_end = 1.0;
   }
   else
   {
    y_start = 0.0;
    y_end = yMax * 2.0;
   }
  }
  else
  {
   y_start = yMin;
   y_end = (yMax - yMin) * 0.1 + yMax;
  }
 }
 
 private void setYminYmax()
 {
  yMin = data[1][0];
  yMax = data[1][0];
  
  for(int i=0;i   {
   if(yMin > data[1][i])
   {
    yMin = data[1][i];
   }
   
   if(yMax < data[1][i])
   {
    yMax = data[1][i];
   }
  }
 }
 
 private int numData = 0;
 private double[][] data = null;
 private double[] y = null;
 private double yMin = 0;
 private double yMax = 100;
 private String title = null;
 private String color = null;
 private int x_size = 300;
 private int y_size = 160;
 private double x_start = 0;
 private double x_end = 100;
 private double y_start = 0;
 private double y_end = 1;
}