
スケールされたレスポンスオーバーレイグラフを備えた複数のY軸
やめてください!スクリプトだけが欲しい場合は、投稿の下部に添付されています。
編集: やめてください! - これは、v19 の Graph Builder に実装されました。: )
これは、すべての y 軸変数をスケールしてオーバーレイし、変数の単位と範囲で y 軸スケールを提供する特殊なグラフです。これは、範囲がすべて異なる 3 つまたは 4 つの変数をオーバーレイする場合に便利です。上の図では、流量は 0 ~ 40 の範囲ですが、電力は 200 ~ 1000 と 100 ~ 500 の範囲です。このタイプのグラフは、複数のセンサーが同時にデータを記録しているが、各センサーの範囲がかなり異なる科学およびエンジニアリング アプリケーションでよく使用されます。たとえば、発酵の例では、グルコースは 1 ~ 5 g/dl、pH は 6.8 ~ 7.8、乳酸は 10 ~ 50 mmol、細胞数または濁度は 1 桁大きくなります。すべての変数の関係を時間の経過とともにグラフ化する簡単な方法は、プロセスの速度論 (または異常なパターンの検出) を理解するのに非常に役立ちます。
このグラフは、長い間私の悩みの種でした。JMPかPowerPointで、ある程度の工夫を凝らしてコピー&ペーストをしないと、それなりに見栄えの良いグラフは作れません。では、なぜこのグラフはこんなにも難しいのでしょうか? 何らかの方法でデータをスケール調整して1つのグラフにまとめ、さらにスケール調整されていないY軸要素をすべてスケール調整されたデータグラフにまとめる必要があるからです。私が見てきた方法や試してきた方法はどれも、コピー&ペーストの手順があまりにも多く、PowerPointでグラフ要素のグループ解除や書式設定を行う方法は、スライド上ですべての要素を正しく配置しようとする手間がかかるため、結果が芳しくないことがありました。面倒で手作業が多く、退屈で反復的なプロセスは、JSLによる自動化を強く求めています。
ソリューションをスクリプト化する戦略を考える際には、考慮すべきいくつかのステップがあります。
1. 変数/列ごとに y 軸ボックスを作成します。
2. 各列の値を同じ範囲にスケールする
3. オーバーレイ プロットで機能するようにデータの形状を変更します。
4. yロールとxロールの列を選択するための起動ダイアログがあれば良いでしょう(あるいは行番号だけを使用することもできます)。
5. 最後に、グラフには元のスケールの各変数を含む軸ボックスを含める必要があります。
JSLの鉛筆を削って、この図の作成を自動化しようと試みました。ここでは私が行ったことを説明したいと思います。より機能的にするための方法について、さらに議論していただければ幸いです。現状では、1種類の固定図を生成し、中間テーブルが残ってしまう後の処理を省いたスクリプトです。(完成したスクリプトを投稿に添付します)
最初のステップ: 起動ダイアログ
cd = Column Dialog(
ylist = ColList( "Y", Min Col( 2 ), Max Col( 8 ), Data Type( "Numeric" ), Modeling Type( {"Continuous"} ) ),
xlist = ColList( "X", Max Col( 1 ), Modeling Type( {"Continuous", "Multiple Response"} ) )
);
Eval( Eval Expr( cd[1] ) ); //eval expr, returns what is in cd[1], and the eval makes it execute
Eval( Eval Expr( cd[2] ) ); //separately run just cd[1], then run evalexpr)cd[1], this is how I get the ylist and xlist variables
起動ダイアログを書き始めるときは、スクリプトインデックスから恥ずかしげもなくコピーし、不要なものを削除したり、必要に応じて追加したりしています。目標はYとXをきちんと記録することです。いくつかルールがあり、列は連続した数値でなければならないこと、Yは少なくとも2つなければならないことなどです(理由は後ほど詳しく説明しますが、Yが1つしかないのに、なぜこれを使うのでしょうか?)。また、Yの応答は8つまでという制限がありますが、これは自由に編集してください。8つを超えると見栄えが悪くなるからです。
eval(eval expr()) を含む最後の 2 行は、列ダイアログの "cd" で返される内容から ylist および xlist 変数を生成する方法です。
データ表1:標準化されたデータ表
dt1 = New Table( "multiple y-axis table" ); //this is the table where the standardized values go
If( N Items( xlist ) == 1, //note that if there is a column selected for xlist, then it doesn't get scaled
Insert Into( ylist, xlist, 1 ), //call me crazy, but the first value in ylist is the "X", if it exists
dt1 << New Column( "Row", formula( Row() ) )
);
DT1は、標準化後のデータを格納するテーブルです。ダイアログでXが選択されていない場合、最初の列は「行」となり、グラフのX軸として使用する行番号が設定されます。Xが選択されている場合は、ylistの先頭に追加されます。はい、その通りです。ylist変数にはXとYの両方が格納されます。
dt1を埋めて「軸ボックス」を作成する
For(
<FONT color="#FF6600"> If( N Items( xlist ) == 1, //yep, that's an "if" argument inside a "for" loop
i = 2; //if an "x" is specified, then start with the second thing in the list
ycol = As Column( dt, ylist[1] ) << get values;
dt1 << New Column( Munger( ylist[1], 1, ":", "" ), set values( ycol ) );//this is soooo ugly
,i = 1), i <= N Items( ylist ), i++, //end of setup for the For loop</FONT>
<FONT color="#008000"> ycol = As Column( dt, ylist[i] ) << get values;
yycol = ((ycol - Min( ycol )) / (Max( ycol ) - Min( ycol )));
dt1 << New Column( Munger( ylist[i], 1, ":", "" ), set values( yycol ) ); //this is soooo ugly, very sorry</FONT>
<FONT color="#0000FF"> amin = Min( ycol ); //this second part of this script is getting values to make the y-axis boxes
amax = Max( ycol ); //I need the min and max values from each of the unscaled columns, along with their names
ymin = amin - ((amax - amin) * .1); //The y-axis box axis range is 10% higher and lower than the min and max.
ymax = amax + ((amax - amin) * .1); //It looks better and is more closely aligned with the scaled data in gb
obj1 = Graph Box( Framesize( 0, 230 ), yName( Char( ylist[i] ) ), Y Scale( ymin, ymax ) ); </FONT><BR /><FONT color="#0000FF"> //its not a true axis box, just a squished graph box. the axis box was free
Insert Into( objhlb1, Name Expr( obj1 ) ); </FONT><BR /><FONT color="#0000FF"> //there is a lot of inserting of name expr() here. its part of building expressions from the inside out.</FONT>
);
次の部分は、Yに選択された列のリストをループします。Xが指定されている場合は、リストの2番目の項目から開始します。
最初の部分では、ループの設定と結果のテーブル作成にロジックを使用しています。テーブルの種類は、X軸変数が指定されているかどうかによって異なります。
スクリプトの真ん中の部分は、短いながらも非常に重要です。元のテーブル (dt) の各列から値を取得し、スケールされた値を dt1 に格納します。この行は正直言ってあまり良いとは言えません。 dt1 << 新しいコラム ( マンガー ( ylist[i], 1 , 「:」 , 「」 ), set values( yycol ) ); しかし、ここで問題なのは、New column には "colname" または colname が必要なのに、:colname はこのステップを無効にしてしまうため、コロンを削除したことです。(より良い方法があればコメント欄で教えてください。)
最後の部分では、列の値の各セットを調べ、それらを使用してグラフ ボックスのスケールを設定します。グラフ ボックスは適切な軸ボックスを作成し、グラフ ボックスの幅が 0 に設定されている場合、y 軸ボックスのみが表示されます。この手順はグラフの書式設定に重要です。最後の行では、グラフ ボックスの式を表示ボックスに挿入し、最後に評価します。obj1 (グラフ ボックス) を参照するために name expr を使用することで、スクリプトによって式が作成され、スクリプト内のすべての変数が評価されますが、スクリプト自体は評価されません。各グラフ ボックスは、水平リスト ボックス (objhlb1) に挿入されます。その後、このボックスは別のボックスに挿入されます。
グラフを作成するためのテーブルの構築:
For(
If( N Items( xlist ) == 1,
i = 2,
i = 1
), i <= N Items( ylist ), i++,
Insert Into( dt2stackcols, ylist[i] )
);
Insert Into( dt2stack, Name Expr( dt2stackcols ), 1 );
Eval(
Substitute( Expr( dt2 = dt1 << ping ),
Expr( ping ), Eval Expr( dt2stack )
)
); //This is tricky!
dt2 << set name( "multiple y-axis stack" );
上で、少なくとも2つのy変数を選択する必要があるという制約について言及しました。しかし、変数を1つだけスタックすることはできず(既にスタックされているため)、変数が1つしかない場合はスクリプトがクラッシュすることが判明しました。ここで興味深いのは、X変数が指定されているかどうかを扱うロジックです。X変数が指定されている場合は既にスケーリングしたくありませんが、今回はXラベルとして使用したいため、スタックに含めたくありません。X変数が指定されていない場合は、ylist内のすべての変数を使用します。
最後の赤字部分は説明が難しいです。スタックを実行するスクリプトが1行でビルドされ、実行/評価されています。「Ping」は置換されるパターンで、これらの式をいろいろ試してみた時に最初に思い浮かんだ言葉です。
dt2stackcols の式はどこにありますか?作業の明確さと、正気を保つために、定義されているすべての式をスクリプトの先頭に移動しました。これは役に立ちました。スクリプトの順序を変更しても、式は必要なときにすべて存在していたからです。式をスクリプト内に散在させたままにしておくと、スクリプトの後半で定義されている式に挿入しようとすることが頻繁にありました。添付の完全なスクリプトを見て、レイアウトを確認してください。ベストプラクティスではないかもしれませんが、私はネミシスグラフのために全力を尽くしています。
すべての部品を組み立てる
Insert Into( objout, Name Expr( objhlb1 ) );
Insert Into( objvlb, Name Expr( objout ) );
Insert Into( objhlb2, Name Expr( objvlb ) );
Insert Into( objhlb2, Name Expr( obj ) );
Insert Into( objwin, Name Expr( objhlb2 ) );
Eval( Eval Expr( objwin ) ); //Evaluating all the assembled parts after all the expressions are evaluated
gb << size( 600, 285 ); //if you want to format the graph, send messages to gb
JSL の最も優れた点の 1 つは、関数ベースの言語であることです。これにより、2 つの重要なことが実現されます。1 つ目は、車輪の再発明をすることなく特定の処理を簡単に実行できること、2 つ目は、複雑な構造の構築方法を簡単に考えることができることです (ただし、それらを内側から外側へと構築するタマネギとして考える必要があります)。たとえば、一般的な考え方は次のようになります。最初に土地を購入し、その土地に建物を建て、建物に部屋を配置し、部屋にオフィスチェアなどのものを置き、椅子に座って、最後に作業を始めます。関数による考え方は次のようになります。最初に椅子があり、そこに Byron を配置します。次に、椅子 (まだ Byron が付いています) をオフィスに置き、それを建物に配置し、それを土地に配置し、土地を購入して、最後に Byron が動作します。
最初のステップでは、グラフ ボックスを objhlb1 に入れ、次に垂直リスト ボックス (objvlb) があり、そこにアウトライン ボックス (objout) と objhlb1 が挿入されます。これはグラフの左側です。左側であるため、ovjvlb は最初に 2 番目の水平リスト ボックス (objhlb2) に挿入され、次にグラフ ビルダー チャート (obj) が挿入されます。最後に、objhlb2 (これですべてが含まれます) は、表示できるように新しいウィンドウ ボックスに挿入されます。その後、すべてが機能するように、評価されます。単に Eval を使用した場合、何が起こるかわかりませんが、機能しないため、最初に Eval Expr を実行して、すべての評価されたスクリプト全体が表示されるようにし (スクリプトで Eval Expr( objwin ) だけを実行して、意味するところを確認してください)、次に Eval を使用してその部分を実行しました。
グラフビルダープロットのobjに少し書式設定があります。タイトルがオフになり、フレームサイズが調整され、y軸がオフになっています。これはすべて、y軸ボックスのスケールと形状に合わせるためです。グラフビルダープロットを使用すると、x軸の編集、凡例の移動、そしてGBオプションによる詳細な書式設定が可能なため便利です。
現在のエンドポイント
スクリプトは7回目のメジャーリビジョン時点では、あまり整然としておらず、多くのテーブルが未完成のままになっています。この点とその他いくつかの点を修正する必要があります。追加機能のアイデアがあれば、ぜひお送りください。ただし、グラフ内のデータが元のデータテーブルに動的にリンクされなかったり、Y軸ボックスがスケールレスポンスグラフのアウトラインボックスにリンクされなかったりするなど、いくつかの問題が発生します。これらのボックスは個別にサイズ調整する必要があります。もしそれがうまくいけば素晴らしいのですが。最後に、スクリプトを動作させない、または望ましくない結果を返す方法が存在する可能性はほぼ100%あると確信しています。そのため、特殊な列名や極端な外れ値、大量の欠損データには注意してください。
このスクリプトをより良く動作させる方法についてコメントをいただければ幸いです。(動作と言えば、私はこれを PC と Mac の v13 と v14 でテストしましたが、問題なく動作して投稿できました。)
著者からの末尾の注記:
これは、まるで私たちがこれについて話しているかのように、最もくだけた口調で書かれています。
これは意図的なものです。コーディングにおける堅苦しい専門用語は、私の意見ではコミュニケーションの妨げになるからです。その代わりに、難解な表現は避けています。