Canvas は ListPlot などのプロットを表示する領域として用いられます。単なるグラフの表示ならば、ListPlot などを使うだけで充分なのですが、場合によっては Canvas に対して直接作用を及ぼす必要が生じます。例えば、描かれた図形の一部をクリックして何かある動作を行ったり、図形の移動や属性の変更を行うなどの仕事です。ここでは簡単な例をもとにこのような Canvas 特有の操作について説明します。
Canvas に描かれる部品はいくつかのアイテム(item)に分類されます。下の表はそれらのアイテムの一覧です。
| アイテム | 描かれる図形 |
| Arc | 扇形、弦、弓形 |
| Bitmap | イメージ |
| Line | 線分 |
| Oval | 楕円 |
| Polygon | 多角形 |
| Rectangle | 長方形 |
| Text | 文字列 |
| Window | 他の部品をはめ込む枠 |
これらのアイテムは Canvas 上に例えば次のように作成されます。
FFS;
w = Window[];
c = Canvas[w, Width -> 300, Height -> 300];
c[Create$Rectangle] = {50, 50, 250, 250, Tags -> "rectarc rectoval"};
c[Create$Oval] = {50, 50, 250, 250, Fill -> "blue", Stipple -> "gray25", Tags -> "rectoval"};
c[Create$Arc] = {50, 50, 250, 250, Style -> "pieslice", Fill -> "red", Start -> 60, Extent -> 90, Tags -> "rectarc"};
TkWait[];
この例では Rectangle, Oval, Arc の3つのアイテムを下図のように描きます。
このように、Canvas にあるアイテムを追加するには
Canvasシンボル[Create$アイテム] = {パラメータ1, ..., パラメータn,
属性1 -> 値1, 属性2 -> 値2, ...}
のように書きます。ここで パラメータ1, ..., パラメータn, は一組またはそれ以上の座標です。これらは別々に書いても、リストにまとめても構いません。上の例では Create$Rectangle の 4 個の引き数がこのパラメータに当たります。次に属性の指定を必要に応じて行います。 パラメータ達は必ず属性の指定よりも先に書かなければなりません。
Canvas では座標の指定は Window の座標の指定と同様に左上隅を (0, 0) とし、右下に増加する座標で、単位はピクセルです。この座標と、CanvasDrawer の座標とは別のものなので、混同しないようにしてください。
ひとつの Canvas に対して、製作された各アイテムには製作順にアイテム番号が自動的につけられます。この番号は 1 から順に 1 ずつ増加します。途中で Delete などの操作でアイテムが消去されても、同じ番号が再利用されることはありません。この番号は後に各アイテムに対して様々な操作を及ぼすときに使われます。
Canvas のアイテムには Tags という属性があり、各アイテムをグループに分けて、名称を付けることができます。これにより後でグループ毎に様々な操作を与えることが容易にできます。名称は空白、{}、() などを含まない任意の文字列です。
ひとつのアイテムが複数のグループに所属することも可能です。例えば上の例では、Rectangle には "rectarc" と "rectoval" の二つのグループが指定されています (書き方が多少妙ですがこうしてください)。
例えば、上の例でさらに
c[Move] = {"rectoval", 30, -20};
c[Update];
Tagsでグループ化したアイテム達の移動。RectangleとOvalを含む グループ ( "rectoval") が(30, -20)だけ移動しました。
Arc は扇形、弓形、弧を描きます。Create$Arcはその Arc の弧を一部とする惰円の外接長方形の二つの対角頂点の座標を最初の 4 つのパラメータとします。
表にその属性を掲げます。
| 属性 | 値 | デフォルト | 効果 |
| Extent | 角度(度) | 360 | 弧の反時計方向の開き角 |
| Fill | 色 | 無指定 | 内部色 |
| Outline | 色 | "black" | 輪郭線の色 |
| Start | 角度(度) | 0 | 弧の開始角、反時計方向に計る |
| Stipple | ビットマップ | 塗りつぶしのビットマップ | |
| Style | "pieslice", "chord", "arc" | "pieslice" | それぞれ扇形、弓形、弧の選択 |
| Tags | 文字列 | そのアイテムにつけるタグ達 | |
| Width | 数値(ピクセル) | 1 | 輪郭線の幅 |
また、次の例は図の様な結果になります。
w = Window[];
c = Canvas[w, Width -> 380, Height -> 140];
styles = {"pieslice", "chord", "arc"};
x = 20;
Scan[
(c[Create$Arc] = {x, 20, x + 80, 100,
Style -> #, Fill -> "red",
Start -> -30, Extent -> -120};
c[Create$Text] = {x + 40, 120,
Text -> #};
x += 120)&,
styles];
Arcの3種のStyle
Bitmap は Canvas 上にビットマップ (\rref{bitmap} 参照) を表示します。Create$Bitmap} は位置をを指定するひと組の座標をパラメータとします。また、その座標と Bitmap との相対位置は属性 Anchor で指定します。Bitmap の属性は表に掲げます。
| 属性 | 値 | デフォルト | 効果 |
| Anchor | "c" "n" "ne" "e" "se" "s" "sw" "w" "nw" | "c" | 座標との相対位置 |
| Background | 色 | 無指定 | 背景色 |
| Bitmap | ビットマップ | ビットマップ (文字列または "@ファイル名") | |
| Foreground | 色 | "black" | 前景色 |
| Tags | 文字列 | そのアイテムにつけるタグ達 |
Bitmapの属性
また、次の例は下の図を作ります。
w = Window[];
c = Canvas[w, Width -> 600, Height -> 100];
bitmap = {"error", "gray25", "gray50", "hourglass",
"info", "questhead", "question", "warning"};
x = 50;
Scan[(
c[Create$Bitmap]={x, 40, Bitmap -> #};
c[Create$Text]={x, 70, Text -> "\""//#//"\""};
x += 70)&,
bitmap];
| 属性 | 値 | デフォルト | 効果 |
| Anchor | "c" "n" "ne" "e" "se" "s" "sw" "w" "nw" | "c" | 座標との相対位置 |
| Image | イメージ | イメージ | |
| Tags | 文字列 | そのアイテムにつけるタグ達 |
Imageの属性
Line は折線を描きます。Create$Line} のパラメータは座標を
, ... と順に並べたものです。属性 Smooth が True のときは各点はスプライン曲線で結ばれ、False のときは直線で結ばれます。属性 CapStyle と JoinStyle は線分の端部と接合部の形状を指定します (図 \rref{lineexample} 参照) 。Line の属性は表 \rref{lineattrib} に掲げます。また、次の例は 図 \rref{lineexample} を作ります。
w = Window[];
c = Canvas[w, Width -> 640, Height -> 270];
options = {
CapStyle -> "butt",
CapStyle -> "projecting",
CapStyle -> "round",
JoinStyle -> "bevel",
JoinStyle -> "miter",
JoinStyle -> "round"};
{x, y} = {20, 90};
Scan[(
c[Create$Line] = {x, y, x + 110, y - 60, x + 180, y,
Width -> 20, #};
c[Create$Text] = {x + 90, y + 20,
Text -> #[[1]]//" -> \""//#[[2]]//"\""};
x += 210;
If[x > 500, x = 20; y += 120])&,
options];
| 属性 | 値 | デフォルト | 効果 |
| Arrow | "none" "first" "last" "both" | "none" | 矢頭の有無 |
| ArrowShape | {接続部長,全長, 全幅} | 矢頭の形状(ピクセル) | |
| CapStyle | "butt" "projecting" "round" | "butt" | 端部の形状 |
| Fill | 色 | "black" | 線の色 |
| JoinStyle | "bevel" "miter" "round" | "round" | 接合部の形状 |
| Smooth | True False | False | True: スプライン、False: 折線 |
| SplineSteps | 数値 | スプラインの線分数 | |
| Stipple | ビットマップ | 塗りつぶしのビットマップ | |
| Tags | 文字列 | そのアイテムにつけるタグ達 | |
| Width | 数値(ピクセル) | 1 | 線の幅 |
Lineの属性
LineのCapStyleとJoinStyle属性
Oval は楕円を描きます。Create$Ovalはその惰円の外接長方形の二つの対角頂点の座標を最初の4つのパラメータとします。
| 属性 | 値 | デフォルト | 効果 |
| Fill | 色 | 無指定 | 内部色 |
| Outline | 色 | "black" | 輪郭線の色 |
| Stipple | ビットマップ | 塗りつぶしのビットマップ | |
| Tags | 文字列 | そのアイテムにつけるタグ達 | |
| Width | 数値(ピクセル) | 1 | 輪郭線の幅 |
Ovalの属性
Polygon は閉じた他辺形を描きます。ただし、外形線はなく、全体が一体として扱われます。Create$Polygon} のパラメータは頂点の座標を
, ... と順に並べたものです。属性 Smooth が True のときは頂点はスプライン曲線で結ばれ、False のときは直線で結ばれます。
表に属性を掲げます。
| 属性 | 値 | デフォルト | 効果 |
| Fill | 色 | "black" | 全体色 |
| Smooth | True False | False | True: スプライン、False: 折線 |
| SplineSteps | 数値 | スプラインの線分数 | |
| Stipple | ビットマップ | 塗りつぶしのビットマップ | |
| Tags | 文字列 | そのアイテムにつけるタグ達 |
Polygonの属性
次の例は下図に成ります。
w = Window[];
c = Canvas[w, Width -> 600, Height -> 160];
param := {x, y, x + 40, y - 40,
x + 80, y, x + 120, y + 40,
x + 160, y, x + 120, y - 40,
x + 80, y, x + 40, y + 40};
{x, y} = {20, 60};
c[Create$Polygon] = {param, Smooth -> False};
c[Create$Text] = {x + 80, y + 60,
Text -> "Smooth -> False"};
{x, y} = {200, 60};
c[Create$Polygon] = {param, Smooth -> True};
c[Create$Text] = {x + 80, y + 60,
Text -> "Smooth -> True"};
{x, y} = {380, 60};
c[Create$Polygon] = {param, Smooth -> True,
SplineSteps -> 3};
c[Create$Text] = {x + 80, y + 60,
Text -> "Smooth -> True"};
c[Create$Text] = {x + 80, y + 76,
Text -> "SplineSteps -> 3"};
Polygonの例。Smooth -> True により、スプラインが用いられる。
Rectangle は傾きのない長方形です。 Create$Rectangleはその二つの対角頂点の座標をパラメータとします。
| 属性 | 値 | デフォルト | 効果 |
| Fill | 色 | 無指定 | 内部色 |
| Outline | 色 | "black" | 輪郭線の色 |
| Stipple | ビットマップ | 塗りつぶしのビットマップ | |
| Tags | 文字列 | そのアイテムにつけるタグ達 | |
| Width | 数値(ピクセル) | 1 | 輪郭線の幅 |
Rectangleの属性
Text は文字列を表示します。また Entry 部品のようにそれを編集することもできますが、その説明は省きます。Create$Textは位置を指定するひと組の座標をパラメータとします。また、その座標と Text との相対位置は属性 Anchor と Justify で指定します。Text の属性は表に掲げます。
| 属性 | 値 | デフォルト | 効果 |
| Anchor | "c" "n" "ne" "e" "se" "s" "sw" "w" "nw" | "c" | 座標との相対位置 |
| Fill | 色 | "black" | 文字の色 |
| Font | フォント | フォント | |
| Justify | "left" "right" "center" | "left" | 文字の揃え方 |
| Stipple | ビットマップ | 塗りつぶしのビットマップ | |
| Tags | 文字列 | そのアイテムにつけるタグ達 | |
| Text | 文字列 | "" | 表示文字列 |
Textの属性
Window はCanvasの上に他の任意のTkinterの部品を貼るのに用います。Create$Windowは貼り付ける部品の位置を指定するひと組の座標をパラメータとし、属性 Window で部品を指定します。例えば次のようにすると、図の様な結果が得られます。
w = Window[];
c = Canvas[w, Height -> 300, Width -> 400];
$DisplayFunction = CanvasDrawer;
Canvas$Widget = c;
Plot[Sin[x], {x, -Pi, Pi}];
b = Button[c, Text -> "Button on Canvas"];
c[Create$Window] = {150, 100, Window -> b};
Canvasの中のWindowの例
私がこれまで試した限りでは、上に貼る Frame などを透明にすることはできないようです。
Canvas 上に製作されたアイテムに対しては後から様々な操作を及ぼすことができます。 以下の説明でcはあるCanvas部品を表わすものとします。
,
} はアイテム番号で指定されるアイテム、またはタグで指定されるアイテム達を (
,
) だけ移動させます。Canvas の各アイテム、あるいはタグのつけられた各グループには Bindにより、それぞれ独立にイヴェントを結合することができます。 その方法は、例えば
c = Canvas[ ... ];
c[Create$Oval] = { ... , Tags -> "a"};
Bind[c, "Button-1", Print["OK"], Tags -> "a"];
の様に Bind にオプション Tags-> (タグまたはアイテム番号、あるいはそれらのリスト) を加えるだけで、あとは通常の部品に対する結合 (Bind参照) と全く同様です。 また、変数 $Eventにイヴェントを発生したアイテムの番号あるいはタグが返されます。
ListPlotや Plotなどのプロット関数も Canvas のアイテムの組み合わせでグラフを表現します。 したがって、それらのアイテム番号が知られれば、個々のアイテムに対して上記の各種の操作を加えることができます。ListPlot が製作したアイテムの番号は、オプション Tags-> True により、その都度シンボル Canvas$ID に記録されるようになっています。例えば、
w = Window[];
c = Canvas[w, Width -> 600, Height -> 400];
$DisplayFunction = CanvasDrawer;
Canvas$Widget = c;
data = {{1, 2, 0.5}, {2, 3, 2},
{3, 5, 0.5}, {4, 2, 0.5}, {5, -2, 0.5}};
ListPlot[data, Tags -> True,
Plot -> True, PlotJoined -> True,
PointSize -> 2];
Print[Canvas$ID];
と 5点のエラーバー付のデータを図のようにプロットしたとします。
ListPlot でプロットしたグラフのアイテム番号。Tags -> Trueにより、Canvas$IDにアイテム番号が記録されます。この場合、グラフの線には 番号 17、データ点のマーカには番号 18-22、エラーバーには番号 23-27 が割り当てられます。Canvas$IDの値は {{17, 27}}になります。(図上の番号は説明のためのもので、実際には表示されません。)
{{開始1, 終了1}, {開始2, 終了2}, ...}
という形式で表わされています。それぞれの要素リストは描かれるグラフィックス原子に対応します。この場合 16 以前のアイテム番号には座標軸や目盛などアイテムが割り当てられていますが、それらの数はグラフの条件に左右されるので、どれが何であるとは簡単には言えません。Canvas$ID の返すものは常にデータ、あるいは直接 Epilog などで書き込みを支持されたグラフィックス原子に対応するアイテムの番号だけです。また、アイテムは、グラフの線、マーカ、エラーバーの順に並び、アイテム番号はデータの順に並びます。エラーバーは両方向にあっても常にひとつのアイテムです。したがってアイテム番号とデータ点の対応は一意的です。PlotRange により表示されるデータ点が制限される場合でも、アイテムは必ず製作され、アイテム番号も付加されます。ただし、グラフの線は破線などの場合にはひとつのアイテムにはなりません。
Showにより複数のプロットを同時に表示するような場合にも Canvas$ID にはプロット毎、あるいはグラフィックス原子毎に アイテム番号が {開始, 終了}というリストで記録されます。
Canvas$ID の値は ListPlot などのオプション Initializeが True のとき (デフォルト) にリセットされます。そうでない時にはそれまでの Canvas$ID に次々に追加されていきます。
以上の方法で各アイテムのアイテム番号がわかりましたから、今度はそれを使って各アイテムにイヴェントを結び付けてみましょう。これは基本的にはアイテムへのイベントの結合で説明したことの応用です。まず、上の例に加えて、
ld = Length[data]; markers = Canvas$ID[[1, 1]] + Range[ld]; Bind[c, "<Button-1>", cmd, Tags -> markers];
とすると、markers にはマーカ達のアイテム番号がリストになって入ります。この場合は {18, 19, 20, 21, 22}になります。次に、Bind で Tags -> markers と指定することにより、各マーカはイヴェント "<Button-1>" (マウスボタン1 の押し下げ) が発生する度に式 cmd を評価実行することに割り当てられました。そこで、例えば
(switch[#] = True)& /@ markers; (ア) markcolor[True] = "green"; (イ) markcolor[False] = "red"; (ウ) errorbarcolor[True] = "black"; (エ) errorbarcolor[False] = "gray"; (オ)
cmd := Module[{id = ToExpression[Tag /. $Event]}, (カ)
switch[id] = switch[id]; (キ)
c[ItConfigure] = {id,
Fill -> markcolor[switch[id]]}; (ク)
c[ItConfigure] = {id + ld,
Fill -> errorbarcolor[switch[id]]}]; (ケ)
とすると、各マーカをクリックする度に図の様にそのマーカとエラーバーの色をトグルすることができます。
マーカをクリックするとそのマーカとエラーバーの色がトグルする。
ここでまず、(ア)はシンボル switch をマーカの状態を保持する関数として定義しています。(イ) から (オ) はそれぞれの状態に対応する色の定義です。(カ) から (ケ) がシンボル cmd の定義ですが、まず (カ) では局所シンボル id にシンボル Tag の $Eventを用いた置換により、クリックされたアイテムのアイテム番号を取り出しています。$Event はこの場合
{(Widget:>c),(Tag->"20"),(Type->"<Button>"),(X->291),(Y->24),(XRoot->693),
(YRoot->542),(Height->0),(Width->0),(Char->"??"),(KeySym->"??"),
(SendEvent->0),(KeyCode->),(State->0),(KeySymNum->),(Time->6784003)}
の様な規則のリストです。$Event は大域的なシンボルですが、イヴェントが発生し結合されたコマンドが呼ばれる度に値が局所的に設定されます(ローカルシンボルの節参照)。$Event に含まれるシンボルについてはEvent Symbolの表を参照してください。
(キ)は switch のトグルです。(ク)、(ケ) は番号 id のマーカ及び番号 id + ld のエラーバーの色を設定し直しています。こうして、アイテムとイヴェントを結合する基本的な動作は確認されました。