Gambas 2.0で簡単なグラフを描く

 3年ほど前データベースの開発が容易になるツールとして紹介したGambasの最新版Gambas 2.0が、近々リリースされる。そこで、最新版が持っている便利な機能の一つ、グラフ機能を紹介しよう。

 まず、Gambasの最新版をダウンロードしインストールする。起動はコマンドラインから。コマンドはgambas2だ。起動したGambas 2.0のツールボックスを見ると、Containerセクションに、この版から導入された新しいオブジェクトDrawingAreaがある。新しいフォームを作って、このDrawingAreaオブジェクトを挿入する。新しいGUIのスナップショットを用意したので、参考にして欲しい。

gambas.png
Gambas Development GUI

 ここで、DrawingAreaオブジェクトのプロパティーを一部設定しておく必要がある。オブジェクトを右クリックしPropertiesを選ぶ。あるいは、F4キーを押す。プロパティーが表示されたら、その一つCachedをTrueにする。こうしないと、グラフを作ってもオブジェクトには何も表示されないのだ。なお、ここでグラフの背景色を設定しておいてもよい。場所はBackgroundセクション。色はSystemタブ(あらかじめGambasが用意した色の中から選択)またはFreeタブ(自分で色を作成する)で指定する。

 以上で、グラフを作成する準備が整った。新しいフォームをダブルクリックすると、コード・エディターが開く。ここにサブルーチンを書いていくのだが、次に示すForm_Openの骨格はあらかじめ用意されている。

PUBLIC SUB Form_Open()
draw_chart()
END

SUB draw_chart()
END

 まず、draw_chartの骨格を作ろう。冒頭でDrawingAreaオブジェクトを初期化し、

DrawingArea1.Clear
draw.Begin(DrawingArea1)

 (データを描画し)、最後に描画セッションを終了する。

draw.End

 これにグラフのX軸とY軸の描画を加え、実行可能なサブルーチンにすると、次のようになる。

SUB draw_chart()
'Define the variables that we'll need
DIM origin_x AS Integer
DIM origin_y AS Integer
DIM max_x AS Integer
DIM max_y AS Integer
DIM x_string AS String
DIM y_string AS String

'Initialize the DrawingArea object
DrawingArea1.Clear
draw.Begin(DrawingArea1)

'Set the text that we're going to use for the axis titles
x_string = "Value"
y_string = "Date"

'Define the origin for the chart
origin_x = Len(x_string) * 10
origin_y = DrawingArea1.ClientHeight - 30

'Define the length or each axis
max_x = DrawingArea1.Width
max_y = DrawingArea1.Height * -1

'Draw each axis
draw.Line(origin_x, origin_y, max_x, origin_y)
draw.Line(origin_x, origin_y, origin_x, max_y)

'Finish with the DrawingArea object
draw.End
END

 ここでオブジェクトを実行すると、画面に水平線と垂直線が描かれるはずだ。

 次に、縦軸と横軸の名称を追加しよう。場所は、draw.End文の前だ。

draw.Text(x_string, 0, origin_y + max_y * 0.90)
draw.Text(y_string, max_x * 0.90, origin_y + 10)

 次にデータを用意する。ここでは、Yahoo! Financeの財務情報データベースを利用することにし、一例として、Novellの株価をMySQLデータベースに取り込もう。

/*Start of file*/
drop database if exists gambas_data;
/*Create the database*/
create database if not exists gambas_data;
/*Create the data structure*/
create table if not exists gambas_data.company_details (
id int auto_increment,
name varchar(50),
code varchar(10),
primary key (id)
);
create table if not exists gambas_data.company_history (
id int auto_increment,
company_id int,
value float,
date date,
primary key (id)
);
/*Create user accounts*/
GRANT select,insert,delete,update ON gambas_data.*
TO bainm@localhost IDENTIFIED BY 'mypassword';
/*Load default data*/
insert into gambas_data.company_details (name, code) values ('Novell', 'NOVL');
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/01',7.65);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/02',7.72);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/03',7.57);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/04',7.67);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/05',7.66);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/08',7.79);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/09',7.93);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/10',8.06);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/11',7.86);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/12',7.89);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/15',7.88);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/16',7.86);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/17',7.85);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/18',7.82);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/19',7.6);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/22',7.65);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/23',7.62);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/24',7.53);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/25',7.51);
insert into gambas_data.company_history (company_id, date, value) values (1,'07/10/26',7.5);
/*End of file*/

 このデータを使うには、gb.dbをアプリケーションのコンポーネントとして追加しておかなければならない。Project→Properties→Componentsの順にクリックし、データベースに接続する。

PRIVATE conn AS NEW Connection
PRIVATE FUNCTION make_connection() AS Boolean
WITH conn
.Type = "mysql"
.Host = "localhost"
.Login = "bainm"
.Password = "mypassword"
.Name = "gambas_data"
END WITH
TRY conn.Open
IF ERROR THEN
Message("Cannot Open Database. Error = " & Error.Text)
RETURN FALSE
END IF
RETURN TRUE
END

 次に、この接続が使えるようにForm_Openサブルーチンを変更する。

PUBLIC SUB Form_Open()
IF make_connection() = TRUE THEN
 draw_chart()
END IF
END

 このコードは、データベースに接続できたことを確認してグラフを描く。接続に失敗したときは、エラーの発生を通知するメッセージ・ボックスを表示する。

 これで、SQL文を使ってデータベースから情報を取り出せるはずだ。

DIM sql AS String
DIM res AS Result

sql = " select date,value from company_history"
res = conn.Exec(sql)

 結果はResultに格納される。プログラムの中では、このResultのデータを使う。

FOR EACH res
    'process your results here.
 NEXT

 さて、取得したデータをグラフにしよう。だが、その前に縦軸と横軸の目盛りを決めておかなければならない。X軸の目盛りは表示する項目の数によって、Y軸の目盛りはデータベースから取得したデータの最大値によって変わるからだ。

sql = "select max(value) as max_val from company_history"
res = conn.Exec(sql)
max_val = res!max_val
y_interval = 0.90 * origin_y / max_val

sql = " select date,value from company_history"
res = conn.Exec(sql)
x_interval = Int(0.85 * max_x / res.Count)

 見やすくするため、Y軸は高さの90%、X軸は幅の85%の範囲内にデータが納まるようにする。これで棒グラフを描く準備ができた。

FOR EACH res
   x_pos = x_pos + x_interval
   y_pos = origin_y - res!value * y_interval
   draw.LineWidth = 0.90 * x_interval
   draw.ForeColor = color.red
   draw.Line(origin_x + x_pos, origin_y, origin_x + x_pos, y_pos)
NEXT

 ここで、LineWidthとForeColorは棒の幅と色だ。この状態で実行すると、次のようなグラフが表示されるはずだ。

 次に、X軸とY軸に数字を入れよう。Y軸は簡単だ。

draw.ForeColor = color.black
draw.Text(Round(max_val, -2), 0, origin_y - max_val * y_interval)

 ラベルが多すぎると重なってしまうが、X軸は要注意だ。そこで、ラベルを飛び飛びに入れることにする。ここでは4つごとにした。

x_pos = 0
y_miss = 0
FOR EACH res
    x_pos = x_pos + x_interval
    y_miss = y_miss + 1
    SELECT CASE y_miss
     CASE 1
      draw.ForeColor = color.black
      draw.Text(res!date, origin_x + x_pos, origin_y)
     CASE 4
      y_miss = 0
    END SELECT
NEXT

 これで完成した。実行すれば、きれいな棒グラフが描かれるはずだ。

 折れ線グラフも同じようにして描ける。棒グラフではX軸から上にデータの高さまで棒を描いたが、折れ線グラフでは1つ前の位置から現在の位置に直線を描くという違いがあるだけだ。

draw.LineWidth = 1
draw.ForeColor = color.black
y_last = origin_y
x_pos = origin_x
FOR EACH res
  y_pos = origin_y - res!value * y_interval
  x_pos = x_pos + x_interval
  IF (x_pos - x_interval) > origin_x THEN
   draw.Line(x_pos - x_interval, y_last, x_pos, y_pos)
  END IF
  y_last = y_pos
NEXT

 これに、いろいろな飾りを付けることもできる。

  • 表示データを切り替えるためのコンボ・ボックス
  • 折れ線グラフと棒グラフを切り替えるためのラジオ・ボタン
  • 表題
  • 複数のデータ系列の色分け

データ系列が複数ある場合のグラフ

 次に、複数のデータ系列をグラフにしてみよう。ここでは、NovellとMicrosoftなど、数社の株価を比較できるようにする。まず、draw_chartサブルーチンを、企業コードが指定できるように変更する。

SUB draw_chart(company_symbols AS String[])

 次に、Form_Openを、draw_chartが必要なデータを入手できるように変更する。

PUBLIC SUB Form_Open()
IF make_connection() = TRUE THEN
draw_chart(Array("NOVL", "MSFT"))
END IF
END

 Y軸の目盛りを計算する際に使う最高値は、ここではグラフにする企業の株価全体で考える必要がある。そこで、SQL文を次のように変更する。

sql = "select max(value) as max_val from company_history where" &
" company_id in (select id from company_details where " &
" code in ( '" & company_symbols.Join("','") & "'))"

 SQLに不慣れな場合はPRINT (sql)を挿入するとよい。実行時に、次のようにSQL文がGambasコンソール・ウィンドウに表示される。

select max(value) as max_val from company_history
where company_id in (select id from company_details where code in ( 'NOVL','MSFT'))

 これをコピーして直接データベースに適用すれば、求めているデータが得られたかどうかを確認できる。

 次に、棒グラフを描くコードを削除(あるいはコメント化)し、折れ線グラフを描くコードを挿入する。FOR EACHループの中に入っているのは、各企業のデータを描くためだ。

FOR EACH symbol IN company_symbols
'All of our code for displaying the line chart for the relevant company
NEXT

 そして、データを入手するSQLを変更する。

sql = "select date,value from company_history where" &
" company_id in (select id from company_details where " &
" code = '" & symbol & "')"

 ここで、アプリケーションを実行してみよう。企業の数だけ折れ線が描かれるはずだ。しかし、どの折れ線がどの企業を表しているのかわからない。そこで、簡単なSELECT CASE文を挿入して色分けしよう。ループで折れ線を描くたびに線の色を順次変更するのだ。

SELECT CASE chart_color
CASE color.black
chart_color = color.red
CASE color.red
chart_color = color.green
CASE color.green
chart_color = color.yellow
CASE ELSE
chart_color = color.black
END SELECT

draw.ForeColor = chart_color

 もちろん、このコードはFOR EACHループの中、各企業の折れ線を描く直前に置く必要がある。そして、各企業の記号を対応する色で表示すれば完成だ。

IF x_pos = origin_x THEN
draw.Text(symbol, 0, y_pos)
END IF

 ここでIF文になっているのは、記号が初回の反復でだけ表示されるようにするためだ。コードは新しいxとyの位置が計算された直後に置く必要がある。これで、指定した企業の株価を比較する簡易なグラフは完成だ。

 このように、Gambas 2.0アプリケーションでは、データを簡単かつ短時間でグラフにすることができる。

 簡単なものからずっと凝ったものまで、さまざまなグラフを含むGambas 2.0プロジェクトを用意した。私のサイトから入手できるので、参考にして欲しい。

Linux.com 原文