この章では、書きたいグラフを画面上、あるいは印刷用紙といった出力デバイスの何処に配置するのか(たとえば、真ん中なのか、左上に寄せてなのか、それとも右下に小さく書くのか、など)、そしてそのグラフのスケールをどのように決めれば良いのかについて、説明する。第2章で紹介した PGENV
ルーチンを使うと、これを最も簡単に済ませることが出来て、デバイス上のグラフの位置やスケーリングを PGPLOT が「お任せ」で行ってくれる。しかしながら、PGENV
を使うと、たとえば目盛りの間隔やラベルの貼り方、あるいはグラフの配置などをユーザが指定することは出来ない。
これらをユーザが自由に指定するためには、以下に述べるような、『ビューサーフェス』(View Surface)、『ウィンドウ』(Window)、そして『ビューポート』(Viewport)といった幾つかの概念と、『ワールド座標』(World Coordinates) と『デバイス座標』( Device Coordinates) という2つの座標系について理解した上で、PGENV
の代わりに、これらを個別に制御するためのルーチンを使う必要がある。
たとえば、一つの変数に対するもう一つの変数の依存性をグラフに示すような場合を想定してみよう。ある物理量が時間の関数として得られていて、これを図にプロットする場合もこれに該当する。この場合の典型的なグラフの構成要素としては、種々の記号(たとえば点や三角形、円など)で示されるデータ群と、それに付ける誤差棒があるだろうし、場合によっては更にデータを線で結んだり、あるいは理論曲線を重ね書きしたりといったこともあるだろう。また、X、Y両座標軸にはラベルを付けて、座標のスケールを示すことも必要に違いない。
このような場合、プログラマ(プログラムを作る人=ユーザ)は以上のような様々な要素について、すべて矩形のデカルト座標系上で記述しなければならない。この際の唯一の制約は座標を"実数"(REAL
または REAL*4
)で与えなければならないということで、それさえ守られれば、それがどのような次元を持つ数値であっても構わない。
このように、プログラマが作図に便利な具合に勝手に想定して選ぶ座標系のことをワールド座標系と呼び、この座標系で定義される空間を ウィンドウ と呼ぶ。一方、画面や紙などの「大きさが予め決まっている」出力デバイス上に図をうまく収めるためには、プログラマがどのようなワールド座標を設定しても、最終的にそれには依存しないような所定の"物理的矩形座標"に変換して出力することが必要である。これを実現する第2の座標系がデバイス座標系であり、PGPLOT ではデバイスの左下隅が(0., 0.)、右上隅が (1., 1.) に当たるような、X軸(横方向)、Y軸(縦方向)ともに 0.〜1. の範囲の無次元座標空間で決められている。このデバイス座標系で定義される空間を、ビューポート と呼ぶ。
PGPLOT では、ビューポートとビューサーフェスという概念は一応使い分けられているようだが、特殊な用途を除くと両者を区別することに実質的な意味はないと思われるので、以下では、より一般的に良く用いられる「ビューポート」という言葉で統一することにする。
前述したような作図上の様々な要素は、おおむね全部、ユーザによって、ワールド座標系で指定される(中には例外もあるが)。したがって PGPLOT は、ワールド座標で指定された様々な要素の「位置」を、逐一デバイス座標系に「投影」して出力する訳である。この変換を機能させるためにユーザは予め、どのようなウィンドウ(ワールド座標系での矩形領域)を、どのようなビューポート(デバイス座標系での矩形領域=デバイス上の物理的位置)に対応させるかを宣言しておかねばならない。
ちなみに以上のような「2つの座標系」の考え方は、PGPLOT に限らず多くの作図ソフトウェアに共通する。
前述のような座標系の宣言を行うに際して、作図プログラムで先ず行わなければならないのは、PGPLOT に『どのようなデバイスを使うのか』を知らせることである。これは、関数 PGOPEN
または PGBEG
を呼ぶことで実現される。
どちらの場合も、ソースコード上でデバイス名を明記することが出来る。しかし、そうするとデバイスを切り替える場合(たとえば、画面に出したりプリンタに出したりする場合など)には、その度にソースコードを書き換えなければならない。PGPLOT では、これを避けて、実行時に出力デバイスを指定する方法も用意されている。通常は後者(実行時にデバイスを指定する)の方が便利なので、ここでもその方法のみを示す。
PGOPEN
と PGBEG
とでは厳密には動作が違うようだが、初等的な利用の範囲ではどちらでも良く、それぞれ
INTEGER PGOPEN IF (PGOPEN('?') .LE. 0) STOP
INTEGER PGBEG IER = PGBEG(0,'?',1,1) IF (IER.NE.1) STOP
のようにして使う。最近は、どちらかというと前者(PGOPEN)の方が推奨されているらしい。ちなみに、第2引数(文字型)が疑問符になっているところがミソで、こうしておくと、プログラムを実行した時に PGPLOT がデバイスを聞いてくる仕組みになっている。逆に、ソースコードの中でデバイス名を指定しておきたい時は、例えば PGBEG
の場合、
INTEGER PGBEG IER = PGBEG (0, 'plotfile.ps/PS', 1, 1)
のように指定する。この例では、PostScript プリンタ出力用の "plotfile.ps" という名前のファイルを作成し、そこに作図結果を出力することを宣言している。
また、すべての作図が完了した時には、最後に PGCLOS
あるいは PGEND
を呼んで PGPLOT の終了を宣言する。これは、
CALL PGCLOS
または
CALL PGEND
とすれば実現される。ともに、引数は必要ない。
一度に開けるデバイスは一つだけである。つまり、画面に図を書きながら「同時に」プリンタ出力用ファイルを作ることは出来ない。もし作図中に再び PGOPEN
や PGBEG
を呼ぶと(一々2通り書くのは面倒なので、これ以降、PGPLOT の開始は PGOPEN
で、また終了は PGCLOS
で行うものとする)、その時点でそれまでの作図結果は破棄され、新しい作図が開始される。
PGOPEN
が呼ばれたら、それから PGCLOS
が呼ばれるまでの間、プログラムはデバイスに自由にアクセスすることが出来る。
また、複数のページにわたってグラフを次々に描きたい場合、一つのページのグラフの作図が終了した時点で PGPAGE
を呼ぶと、新しいページに進むことが出来る(いわば改ページ用のルーチン)。具体的には、
CALL PGPAGE
とすれば良い。ちなみに、PGPAGE
を呼んでも、ビューポートやウィンドウの定義は保存される。したがって、同じスケーリングでデバイス上の同じ位置に図を描き続ける限り、再びこれらを定義し直す必要は無い。
ちなみにPGBEG
には4つの引数があり、このうち後ろの2つは、ビューポートを更に『パネル』と呼ばれる小さな単位に分割して別々に制御する時に使う。詳しくは、リファレンスマニュアルを参照して頂きたい。
ビューポートを定義するには、PGSVP
または PGVSIZ
を使う。PGSVP
は x、 y の両方向について 0. 〜 1. までの間の無次元座標を用いてデバイス上の図の物理的位置を定義するためのルーチンである。具体的には、
CALL PGSVP (XMIN, XMAX, YMIN, YMAX)
のように用いる。ここで、4つの引数は、定義したいビューポートの
をそれぞれ意味する。
前述の無次元座標系はデバイス上の物理的大きさ(紙の縦横の長さなど)をユーザに意識させることなく定義されるので、これを特に『正規化デバイス座標系』と呼ぶこともある。しかし単純にデバイス座標系と言えば、おおむねこの無次元座標系をさすことも多い。この正規化デバイス座標系では、左下隅が (0., 0. ) に相当し、右上隅が (1., 1. ) に相当する。
したがって、例えば、紙であれ画面であれデバイス上で許される大きさ一杯にグラフを描きたい時は
CALL PGSVP (0.0, 1.0, 0.0, 1.0)
と書けば良いし、また左上の4分の1の中にグラフを収めたい場合は
CALL PGSVP (0.0, 0.5, 0.5, 1.0)
と書けば良い。ここまで読んだ人の中には、「では、1ページの中に複数の図を描くことも出来るのか?」と思う人があるかも知れない。その通りで、デバイス上の位置を切り替えるたびに PGSVP
を呼んで新たなビューポートを定義すれば、これを実現することが出来る。画面(紙でも同じ)を縦横2×2の計4つの領域に分割して、それぞれの中に違うグラフを描きたいとすれば、4つの領域の1つをビューポートとして定義し、そこにグラフを描いた上で、今度は次の領域を新たなビューポートとして定義し、そこにグラフを描く・・・・ということを4回繰り返すことになる。
一方、PGVSIZ
は、PGSVP
のように 0.〜1. の無次元座標ではなく、物理的な単位(具体的にはインチ単位)でビューポートを定義するためのルーチンである。PGSVP
と同じように4つの引数をとる:
(例) CALL PGVSIZ (1.5, 9.5, 1.5, 6.5)
が、インチ単位で指定するところが異なる(この例では、幅8インチ、高さ5インチの空間にグラフを収めることになる)。使いたいデバイスの物理的大きさが予め分かっていて、長さをきちんと決めた通りにしたい場合は、PGVSIZ
を使えば良い。しかし、こちらを使うことは一般的には希で、とくに必要が無ければ PGSVP
を使う方が良かろう。
これらの他に、デバイスの上下左右に各々文字の高さの4倍だけの余白を残して、あとの全体をビューポートとして定義する PGVSTD
というルーチンもある。呼び方は
CALL PGVSTD
で、引数は必要ない。第2章で紹介した PGBEG
では、ユーザがビューポートを指定する必要がなかったが、これは PGVSTD
が PGBEG
の内部で呼ばれているからである。
ビューポートは、それを適用したい作図の具体的内容に入る(線を引いたり点を打ったりする)前に定義しなければならない。
一方、ウィンドウを定義するのには PGSWIN
を使う。このルーチンは4つの引数をとり、例えば
CALL PGSWIN (1975.0, 1984.0, 5.0, 20.0)
のように CALL される。この場合は、x (横)軸の範囲を 1975〜1984、y (縦)軸の範囲を 5.〜20. とそれぞれ指定していることになる。PGSWIN
の引数は実数(もしくは実数型変数)で与えなければならない。したがって各引数として数字を書く場合は、必ず小数点を付ける必要がある。
上の例では x 軸方向は左から右へ、y 軸方向は下から上へ向かって値が大きくなるような座標系が定義されているが、もし x 方向、y 方向の範囲を引数を入れ替えれば、それぞれの向きを逆転させることができる。例えば、上の例の代わりに
CALL PGSWIN (1975.0, 1984.0, 20.0, 5.0)
と指定すれば、y 方向の座標は下端が 20.、上端が 5. になる(つまり上下反対)。
ビューポートと同様にウィンドウも、それを適用したい作図の具体的作業に入る前に定義しなければならない。また、ビューポートとウィンドウは、どちらを先に定義しても構わない。すなわち、
CALL PGSVP ( 0.0, 1.0, 0.0, 1.0) CALL PGSWIN (1975.0, 1984.0, 20.0, 5.0)
でも
CALL PGSWIN (1975.0, 1984.0, 20.0, 5.0) CALL PGSVP ( 0.0, 1.0, 0.0, 1.0)
でも、その効果は同じである。ちなみに、第2章で紹介した PGBEG
では、ユーザには見えないが内部で x 軸と y 軸の両方向とも 0.0〜1.0 の範囲のウィンドウを定義するようにルーチンが CALL されている。
ウィンドウの縦横比がビューポートの縦横比と異なる場合、作図結果は縦または横方向に"圧縮"された感じになる。この圧縮を防ぐ一つの方法は、両者の縦横比が等しくなるように PGSVP
と PGSWIN
の引数の与え方に注意することである。しかし、この他に PGWNAD
を使う方法もあって、そうするとユーザが引数で与えたウィンドウと同じ縦横比になるようなビューポートを新たに定義し直してくれる。この場合、新しいビューポートは、古い(ユーザが元々指定した)ビューポートの内側に収まって、かつウィンドウと同じ縦横比になるように設定される。
グラフを描くと、しばしばビューポートの周囲に外枠を描いたり、その外枠にメモリや数値ラベルを付けたりする。PGBOX
を使うと、これを好みに応じて行うことができる。たとえば、
CALL PGBOX ('BCTN', 0.0, 0, 'BCNST', 0.0, 0)
のように CALL する。PGLAB
を使うと、図の下、左、上に好みのコメントを付けることができる。たとえば、
CALL PGLAB ('Epoch', 'Flux Density (Jy)', 'Variation of 3C345 at 10.7 GHz')
のように書くと、最初の2つが横縦両軸につける説明、最後の引数は図のタイトルとなる。他の作図ルーチンと異なり、PGBOX
や PGLAB
によって描かれる線や文字列は、クリッピング(ウィンドウの境界の外に出た図形要素を描かないこと)の対象とはならない。すなわち、ウィンドウの外にハミ出ていても、マスクされずに描かれる。PGLAB
は実は、文字列を描くためのもっと一般的なルーチンである PGMTXT
を内部で呼んでいる。ちなみに PGMTXT
を使うとビューポート内の任意の場所に文字列を描くことができるが、これについては第4章で述べる。
注釈用に必要なビューポート外のスペースの量は、PGBOX
に対して指定される引数の内容による。通常は文字の高さの4倍もあれば十分で、実際たとえば PGVSTD
で定義される標準ビューポートの周りには、この分だけの余白が確保される。その"文字列の高さ"は、PGSCH
を用いて変えることができる。
第2章で紹介した PGENV
は、実は
PGPAGE
、
PGSVP
、
PGSWIN
、
PGBOX
の4つのルーチンを一つにまとめたもので、たとえば
CALL PGENV (1975.0, 1984.0, 5.0, 20.0, 0, 0)
と書くと、
CALL PGPAGE CALL PGVSTD CALL PGSWIN (1975.0, 1984.0, 5.0, 20.0) CALL PGBOX ('BCNST', 0.0, 0, 'BCNST', 0.0, 0)
のような4つのルーチンを順番に呼ぶのと同じ効果が得られる。詳細は省略する。