GKSによる2次元グラフィックス

GKSを使ったプログラム例

1. まえおき

この授業で使うプログラムライブラリNCAR Graphicsは、GKS (Graphical Kernel System)という、ISO(国際標準化機構)の標準ともなっている規格に準拠したもので ある。GKSについては、鈴木(1991)の入門書があり、また、森(1991)でも扱われて いるが、まだ参考になる例文が少ないように思う。

筆者は、図形出力の教材を出力装置になるべく依存しない形で構成するため、 GKSを使ったプログラム例を用意し、実習に使ってきた。環境は、HITAC VOS3 (KGRAF)、FACOM MSP (GKS85)、Unix+X Window (xgks および NCAR Graphics)、 PC98およびAT互換機 MS-DOS (森、1991のプログラムを一部改造しMS Fortran 5.1のグラフィックライブラリを利用)などである。

ここでは、Unix上のNCAR Graphicsを利用する形にした例文を紹介する。

必要なものを自分の適当なディレクトリにコピーして、 次の手順で動かしてみていただきたい。(%は計算機側からのプロンプトを 代表させるために書いたものであり、キ−入力ではない。)

    % ncargf77 ie-gfa.f
    % ./a.out
    % ctrans gmeta
(これはFortranの場合であり、ncargf77のところが、C言語の場合はncargccとなる。) NCAR GraphicsはGKSのほかにたくさんの応用機能をもっているが、ここでは GKSの機能に限って使うことにする。しかし、ソースプログラムを見やすくする ため、GKS標準に含まれないNCAR Graphicsのルーチンを、次のものに限って 採用することにした。
opngks
GKSと1つの出力装置(ワークステーション番号1)の利用開始
clsgks
GKSと1つの出力装置(ワークステーション番号1)の利用終了
frame
1画面の終了 (ディスプレイ装置ではキー入力を待って画面消去、   プリンタでは次ページへ)
これは、次のような理由による。GKS利用開始・終了の手続きは、複数の装置を 使い分けられるように機能を分けてあるため、1つだけの出力装置を使う場合は かえってめんどうである。NCAR Graphicsでは原則として1つだけの出力装置を 使うので、これらの手続きを見かけ上簡単にできるようにしてある。 (C言語での関数名は、c_opngks, c_clsgks, c_frameとなっている。)

なお、NCAR GrahicsでないGKSを使う場合は、 opngks, clsgks, frameに相当するものをユーザー側で用意することになる。 そのサンプル(Fortran, C)を、 opnclsx.fほか (Fortran)、 c_opnclsx.cほか (C) として置く予定。 引き数の値は、実際に使うGKSライブラリと出力装置 によって変える必要がある。 opnclsx.f, c_opnclsx.cは、xgksというフリーソフトウェアの ライブラリを使ってX Windowの画面に出力する場合である。

2. 簡単な例

GKSの、従来のプロッタルーチン系のライブラリと違った 特徴としては、多角形のぬりつぶし(fill area、Fortranルーチン名 GFA)を初め から図形の基本要素のひとつとしていることがあげられるだろう。

最初の例として、ie-gfa.f [link] を見ていただきたい。この例文は、「家」の絵を かくものであり、鈴木(1991)の本の例文となんとなく似たものになってしまった。 ただし、鈴木(1991)で家の絵はセグメントというGKSの中ではわりあい高度な概念 の説明に出てくるのだが、ここではそうではない。家の形は南大沢(都立大学の 所在地)ふうである。配色は考えていないので「絵」としては未完成である。

Fortranには大文字と小文字の区別がないが、ここでは、Fortranのキーワード とGKSのルーチン名を大文字で、変数名やGKS以外のルーチン名を小文字にした。 また、変数は全部宣言することにし、これをチェックするために「IMPLICIT NONE」を入れた。

図形出力の開始、終了には、NCAR Graphicsのルーチンopngks, clsgksを使って いる。GKSのサブルーチンを呼ぶのは、この2つのルーチンの呼び出しの間でなけれ ばならない。また、1画面の終了にNCAR Graphicsのルーチンframeを使った。

このプログラムの核心は、サブルーチンGFAを呼ぶところである。GFAは、渡さ れた座標値をもつ点を順につないだ多角形の内部をぬりつぶす。引き数の1つめ (整数)は、多角形を構成する点の数で、三角形ならば3、四角形ならば4...とする。 2つめと3つめは実数型の配列で、それぞれ、x座標、y座標を入れておく。(GKSの 概念からみると「<xとyの値の組>の配列」のほうがよいのだが、Fortran 77には 配列以外の複合型変数を定義する方法がないので、この形になったらしい。) 「mado」に関しては、2重DOループの中で値を変更してはGFAを呼ぶということを くりかえしている。このようなことができるのが、図形出力手続きをFortran という手順立て言語の中から実行していることによる特徴である。

座標値と書いたが、どんな座標だろうか? GKSで扱われる座標系は2次元直交 直線座標系に限られているが、尺度はのびちぢみさせることができる。GFAなど、 GKSのほとんどのルーチンに渡される座標値は「世界座標」(WC)というものである が、この例では、GSELNT (select normalization transformation)を呼んでいない から、WCは自動的に「正規化装置座標」(NDC)と同じである。つまり、ある正方形 の画面を考えて、画面の左端を0、右端を1、下端を0、上端を1としたものである。

さらに、「ある正方形の画面」が実際の装置でどの位置にどの大きさで表示さ れるか、という問題がある。これはGKSではGSWKWNとGSWKVPというルーチンで調節 できるのだが、とりあえずは、NCAR Graphicsのプログラム ctrans で表示される 標準の大きさの正方形の画面を想定しておこう(画面をいっぱいに使えないという 欠点はあるが)。

あと説明していないルーチンはGSFAIS (set fill area interior style)とGSFACI (set fill area color index)である。これらは多角形ぬりつぶしの属性 (attributes)を指定するもので、GFAを呼ぶまえにあらかじめ呼んでおく。GSFAISの 引き数の値を1にすると、「むく」(solid)のぬりつぶしになる。(GSFAISを呼ぶのを 忘れると中空になってしまう! ライブラリがGKS標準に忠実であればだが。)

GSFACIはぬりつぶしの色の番号を指定する。例文では1番、2番、3番の色を使って、 相互に区別されることは確認したが、それがどんな色だったかは忘れてしまった。 GKS標準では、なん番がなに色であるかは決めていない。具体的に色を指定する場合 は、GSCR (set color representation)を使うことになっている。 次の節で紹介するテストプログラムを動かして、番号と色の対応を見ていただきたい。

さて、プログラム ie-gpl.f [link], ie-gpm.f [link], ie-gtx.f [link]は、それぞれGKSの基本要素 である折れ線(polyline,GPL)、記号群(polymarker, GPM)、文字列(text, GTX)を 出力してみるために作ったもので、絵としての完成度は ie-gfa.f よりさらに低い。 特にGPL, GPMの例文では、GFAの例文と同じ座標値を与えて何が起こるか見るように した。GPLで別々の4点の座標を与えたのでは四角形が閉じないことに注目していた だきたい。閉じさせるには最初の点をもう一度加えて5点としてGPLを使うか、 あるいはGSFAISで中空(0)を指定して(GPLではなく)GFAを使うか、ということ になる。

ie-wnvp.f [link] は、GKSの座標ののびちぢみ(正規化変換)を示すために作った例文で、 ie-gfa.f の作図内容をサブルーチンにして2回呼んでいる。これで同じ図形がかか れるわけだが、GSWN,GSVP, GSELNTを使って、x軸、y軸それぞれをのびちぢみさせて いる。正規化変換とは、世界座標(WC)から正規化装置座標(NDC)への変換で、WC上の 長方形「ウィンドウ」とNDC上の長方形「ビューポート」を同一視することによって 指定される。GSVPで指定するビューポートの4辺の座標値はNDCのものなので常に0と 1の間にあるが、GSWNで与えるウィンドウの座標値にはそのような制約はない。ただ し、左から右、下から上に座標値がふえるように与えなければならない。この例文 では、どういうウィンドウ・ビューポートを指定したかを見やすくするため、サブ ルーチンkakomiでウィンドウの端を示す長方形をかくことにした。GSWN, GSVPの値 をいろいろに変えてためしてみると、正規化変換がわかってくるのではないかと思 う。

3. 属性一覧

これまでの例でもわかるように、GKSでは、基本要素であるGPL, GPM, GFA, GTXの それぞれについて、いろいろな属性が設定されている。属性の値の指定は、基本要素 を作図する前におこなう。

例文 gplattr.f [link], gpmattr.f [link], gfaattr.f [link], gtxattr.f [link] では、4種類の基本要素の それぞれについて、おもな属性のうち、次にあげるものをいろいろに変えて表示 したものである。全部の属性について示すことは意図せず、1つの画面におさまる 程度にした。

・ gplattr ... GSLN    線の種類(実線か破線か) 
              GSLWSC  線の太さ(ある標準値に対する比で実数型で指定する)
               GSPLCI  線の色の番号
・ gpmattr ... GSMK    記号の種類(GKS標準では1番から5番までが決まっている)
              GSMKSC  記号の大きさ(ある標準値に対する比で実数型で指定する)
               GSPMCI  記号の色の番号
・ gfaattr ... GSFAIS  多角形領域の内部の様式(空白、むく、パタン、ハッチング)
               GSFASI  (ハッチングの場合の)もようの選択
               GSFACI  ぬりつぶしの色の番号
・ gtxattr ... GSTXAL  代表点に対する文字列の位置関係(縦、横それぞれの方向)
              GSCHH   文字の大きさ(WC座標の大きさで指定、ただし例文ではWC=NDC)
               GSTXCI  文字列の色の番号

(このほかによく使う文字列の属性として、文字の向きを示す GSCHUP (character up)があるが、これの使い方の例は省略している。 「GKSによるデータの可視化の例」の sanmenzu.fや、 等値線のプログラム例のcontmain.f の 中で、y軸の説明をy軸に沿って書くためにGSCHUPを使っている。)

なお、画面上に説明を加えるため、文字列以外の例文でもGTXを使っており、一方、 文字列の例文では代表点を示すためにGPMを使っているので、それらに関する属性 指定もプログラムには現われている。

また、gplattr.f には最後に「INCLUDE 'senbun.f'」という行があるが、これは Unix上の多くのFortran 77コンパイラの約束で、 ファイル senbun.f [link]の内容をこの 位置に取り込んでいっしょにコンパイルするという意味である。 PascalとC言語の例文では、メインプログラムの初めのほうで #include 文を使っている。(#includeはC言語では標準的機能だが、Pascalの場合は DEC Pascalの拡張機能である。)

senbun.f の内容は、2点を結ぶ線分をかくサブルーチンsenbunである。線分は 点の数が2である折れ線とみなせるのでGPLで作図することができるが、2点それ ぞれのx, y座標を代入してからGPLを呼び出すという手順をそのまま書くと、配列 宣言文を別としても5行になってしまう。(最近の多くのFortran 77コンパイラでは セミコロンを使って同じ行に書くことも許されているが)。これを見かけ上1行に 圧縮してソースプログラムの見通しをよくするため、このサブルーチンを組んだ。

同様に、gfaattr.f から取り込まれるファイル sikaku.f [link] には、 辺がx, y両軸に平行な長方形をかくサブルーチンsikakuが用意してある。

4. 円弧を含む例

GKSは線の基本要素をGPLだけとしたので、円周や円弧は標準に含まれていない。 ぬりつぶしについても、基本要素は多角形のGFAだけなので、円や扇型は含まれて いない。GKS標準には、一般化された図形出力要素(generalized drawing primitive, GGDP)というものがあって、この形式に合わせれば、GKS標準から違反せずにライブ ラリ作成者が新たな要素を定義することができる。しかし、GGDPの引き数の意味づけ はライブラリ作成者にまかされているので、これを使った応用プログラムを別の ライブラリ上で動かしても期待どおりの結果にならない。他の環境に移植しやすい プログラムを作りたい場合は、円を多角形で近似して、基本要素のGPLやGFAを使う ことをおすすめしたい。

seiza.f [link]は、 夜の空の北極の方向にカメラを向けて長時間露出をしてできる写真 を想定した、おおまかな絵である。この中で円弧のように見えているのは、実際に は、円周上をある角度間隔(たまたま2度だが、この値に特に意味はない)でサンプ リングした点を結んだ折れ線である。蛇足だが、点(xzero, yzero)を中心とし 半径rの円周上の点の座標は、

        x  = xzero + r * cos(theta)
        y  = yzero + r * sin(theta)
で、角度thetaをいろいろに変えることによって得られる。

5. 折れ線グラフと棒グラフ

GPLを使うと、わりあい簡単に折れ線グラフを作ることができる。

sunspot.data [link]は、 『理科年表』から引用した毎年の太陽黒点数の値である。

ここからのプログラム例では、この sunspot.data が、そのファイル名で、 datapath.fi [link] の中に dapath として書かれたpath名の下の sample というディレクトリに置かれていることを想定している。 datapath.fi をダウンロードしたうえで、 内容を自分がファイルを置く場所にあわせてなおして使ってほしい。

まず、データを読んで折れ線をかくところだけにした例文 oresen0.f [link] (ピリオドの前の最後の字はゼロ)について、 Fortranのソースプログラムに沿って説明する。

実行部の最初で、サブルーチン rddata を呼んで、データを読み込んでいる。 rddataのソースプログラムは説明を省略するが、 rddata.f [link]にあり、 わりあい汎用的に作ったつもりなので参考にしてほしい。 最初の引き数の文字列にファイル名、 次のnvmaxに配列の寸法を入れて呼ぶ。rddataから帰ってくると、引き数 n にデータ の個数が、xarrayの1番からn番までに年が、yarrayの1番からn番までに黒点数が はいっている。

次に、GSWN、GSVP、GSELNTを呼んで、正規化変換を設定している。 完成版のプログラム oresen.f [link] ではここで設定したウィンドウいっぱいにワクをかくのだが、データ点 がワクに接するとグラフがよみにくくなる(Cleveland, 1985)。そこで、GSWNで設定 するウィンドウの端のWC座標値(wxmin, wxmax, wymin, wymax) は、データがとり うる値よりも余裕をもって設定しておく。いっぽうビューポートの端のNDC座標値 (vxmin, vxmax, vymin, vymax)は、グラフの外側に注記を入れること、特に左側と 下側に軸の目盛りの値の数字を入れることを考慮して決めている。

あとは、属性を決めて折れ線をひくだけである。

oresen.f [link] では、折れ線をひく前に、目盛りつきのワクをかいている。また、 折れ線のあとで、y軸の値(黒点数)が0のところに補助線の横線をひき、図の上に 題名をつけている。

題名をつけるための「CALL GTX...」の前にある「CALL GSELNT(0)」に注意して いただきたい。0番の正規化変換を選択するとは、WCはNDCに等しいとみなすこと である。題名の文字列の位置や大きさは、グラフ上の「年」や「黒点数」の値に 関連させて決めるよりも、画面の中での相対位置で指定したほうがわかりやすい ので、このような方法をとっている。

目盛りつきのワクをかく部分waku2については、 別記事参照。

折れ線グラフのなかまに棒グラフがある。 bargr.f [link] では、同じ黒点数のデータ を読み、その値を11年ごとに平均して棒グラフで表示している。(黒点数の長期 変動傾向を見る目的には、「移動平均」して折れ線グラフにしたほうがいい だろう。これは単にグラフの例として見ていただきたい。) 棒の部分は、 サブルーチンsikaku (ファイル sikaku.f を利用し、長方形のぬりつぶしとして 表現した。あとはほぼ oresen.f と同じである。

参考文献


2000-04-26, 2005-08-10, 2012-05-13, 2020-08-16
増田 耕一
[目次へ]