
具有縮放響應疊加圖的多個 Y 軸
停止! 如果你只想要腳本,它附在帖子的底部。
這是一個專門的圖表,它縮放所有 y 軸變量並覆蓋它們,然後以變量的單位和範圍提供 y 軸比例。 當您想要覆蓋 3 或 4 個都在不同範圍內的變量時,這很有用。 在上圖中,流量在 0-40 範圍內,而功率在 200-1000 和 100 到 500 範圍內。 這種類型的圖表通常用於科學和工程應用中,其中多個傳感器同時記錄數據,但每個傳感器的範圍有很大不同。 例如,在發酵示例中,葡萄糖為 1-5 g/dl,pH 為 6.8 - 7.8,乳酸為 10-50 mmol,細胞計數或濁度高出一個數量級。 一種簡單的方法來繪製所有變量之間隨時間變化的關係對於理解過程的動力學(或檢測異常模式)非常有幫助。
很長一段時間以來,這個特定的圖表一直是我的剋星。 通常需要在 JMP 或 PowerPoint 中進行一些創造性的複制和粘貼,以獲得看起來相當不錯的任何內容。 那麼為什麼這張圖這麼難呢? 您必須以某種方式將數據縮放並組合成一個圖形,然後您必須將所有未縮放的 y 軸組件與縮放的數據圖形組合。 我見過和嘗試過的所有方法都涉及太多的複制和粘貼步驟,而在 Powerpoint 中涉及取消分組和重新格式化圖形元素的方法有時會產生糟糕的結果,因為嘗試讓所有元素對齊很乏味在我的幻燈片上。 JSL 自動化需要雜亂、手動、乏味和重複的流程。
在考慮編寫解決方案腳本的策略時,需要考慮幾個步驟
1. 為每個變量/列製作一個 y 軸框。
2.將每列的值縮放到相同的範圍
3. 重塑數據,使其在疊加圖中起作用。
4. 如果有一個啟動對話框來選擇 y 角色和 x 角色的列,那也很好,(或者可能只使用行號)
5. 最後但並非最不重要的一點是,圖表需要包含軸框,其中每個變量在原始比例中。
我削尖了我的 JSL 鉛筆,嘗試自動製作這個數字。 我將嘗試解釋我在這裡所做的事情,並希望進一步討論如何使其更具功能性。 當前狀態是一個腳本,它可以生成一種類型的固定圖形,並且不需要清理它留下的中間表的尾跡。 (我會將完整的腳本附加到帖子中)
第一步:啟動對話框
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。 這裡有一些規則,比如列必須是數字連續的,而且必須至少有 2 個 Y(原因後面會更清楚,而且,如果你只有一個 Y,那你為什麼用這個?) Y 回復也有 8 個限制,請隨意編輯,超過 8 個似乎太亂了。
eval(eval expr()) 的最後兩行是我如何從列對話框的“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,則從列表中的第二項開始
第一部分使用一些邏輯來設置循環並為結果製作表格,因此請進入。 表格變體取決於是否指定了 x 軸變量。
腳本的中間部分非常重要,儘管它很短。 它從原始表 (dt) 中的每一列中獲取值,並將縮放後的值放入 dt1。我真的不為這條線感到驕傲:dt1 <<新列(芒格( ylist[i], 1 , “:” , “” ), 設置值(yycol));但事情是這樣的,新列需要“colname”或colname,而:colname 會終止這一步,所以我只是把冒號刪掉了。 (在評論中發送更好的方法來做到這一點。)
最後一部分查看每組列值並使用它們來縮放圖形框。 圖錶框製作漂亮的軸框,如果圖錶框的寬度設置為 0,則僅顯示 y 軸框。 發生的事情是這一步對於格式化圖表很重要。 最後一行將圖形框的表達式插入到最後計算的顯示框中。 通過使用名稱 expr 來引用 obj1(圖形框),我得到了創建它的腳本,並且腳本中的所有變量都被評估,但腳本沒有被評估。 每個圖形框都插入到水平列錶框 (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" );
上面我提到了一個約束:必須選擇至少兩個 y 變量。 事實證明,你不能只堆疊一個變量(因為它已經堆疊了),如果只有一個變量,它會使腳本崩潰。 這裡有趣的是處理是否指定 X 的邏輯。 如果有 X,我已經不想縮放它,現在我不想將它包含在堆棧中,因為我希望它作為 X 標籤。 如果沒有指定 X,那麼我想使用 ylist 中的所有變量。
紅色的最後一部分很難解釋。 在一行中,構建並運行/評估了執行堆棧的腳本。 “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 最好的一點是它是一種基於函數的語言。 這完成了兩件重要的事情,首先,它可以輕鬆地完成特定的事情,而無需重新發明輪子,其次,它可以輕鬆地思考如何構建複雜的結構。 (只要您將它們視為您從內到外構建的洋蔥。 例如,典型的思維方式是這樣的。 首先我買了很多土地,然後我在土地上蓋了一棟樓,然後我在樓裡放了房間,然後我把我的辦公椅之類的東西放在房間裡,然後我坐在椅子上,最後,我開始工作。 功能思維是這樣工作的;首先有一把椅子,我把拜倫放在裡面。 然後我把椅子(還有一把拜倫)放到辦公室,然後我把它放到大樓裡,我把它放到地段裡,然後我買了它,最後,拜倫工作了。
第一步是將圖形框放入objhlb1,然後有一個垂直列錶框(objvlb),其中插入了一個輪廓框(objout)和objhlb1。 這是圖表的左側。 由於位於左側,ovjvlb 被插入到第二個水平列錶框 (objhlb2) 中,首先是圖形構建器圖表 (obj)。 最後 objhlb2 (現在包含所有內容)被插入到一個新的窗口框中,以便可以顯示它。 然後為了使這一切正常工作,它會被評估。 如果我只是使用 Eval,那麼.. 我不確定會發生什麼,但它不起作用,所以我先執行了 Eval Expr,以便顯示所有內容的整個評估腳本(嘗試在腳本中僅運行 Eval Expr( objwin ) 以了解我的意思)然後我使用 Eval 運行該部分。
obj 有一點格式,即圖形生成器圖。 關閉標題,重新調整幀大小,關閉 y 軸。 這一切都是為了使其與 y 軸框的比例和形狀相匹配。 使用 Graph Builder 繪圖很方便,因為仍然可以編輯 x 軸,可以移動圖例,並且所有 GB 選項都可用於進一步格式化。
當前終點
就腳本而言,在第 7 次重大修訂時,它不是很整齊,而且它留下了一堆桌子。 這和其他幾件事應該得到解決。 因此,如果您有添加的想法,請發送它們。 有些事情不會發生,例如圖表中的數據不會動態鏈接到原始數據表,並且 Y 軸框不會鏈接到 Scaled Response Graph 大綱框,您必須調整大小每一個獨立。 如果那行得通,那就太好了。 最後,我幾乎 100% 確信有辦法使腳本中斷或返回不幸的結果,因此請注意特殊的列名和極端異常值,或大量缺失數據。
我很想就使這個腳本工作的更好方法發表評論。 (說到工作,我在 PC 和 Mac 上的 v13 和 v14 中對此進行了測試,並且運行良好。)
作者的結束語:
這是用最非正式的語氣寫的,就像我們在談論這個一樣。
這是故意的,因為編碼中的正式術語,恕我直言,阻礙了溝通。 相反,我避免混淆。