The Multiple Y-Axis Graph
This is a specialized graph that scales all of the y-axis variables and overlays them and then provides the y-axis scale in the units and range of the variable. This is useful when you want to overlay 3 or 4 variables that are all in different ranges. In the figure above the flow rates are in 0-40 range while power is in the range of 200-1000 and 100 to 500. This type of graph is often used in scientific and engineering applications where multiple sensors are recording data at the same time, but the range of each sensor is quite different. For example, in a fermentation example, glucose is 1-5 g/dl, pH is 6.8 - 7.8, lactic Acid is 10-50 mmol, and cell count or turrbidity is an order of magnitude greater. A simple way to graph the relationship between all the variables over time is very helpful for understanding the kinetics (or detecting unusual patterns) of the process.
Names Default To Here( 1 ); dt = Current Data Table(); //This could be a dialog too, but its set up to make an add-in this way. //////////////////////////////////////////////////////////////Expressions - I moved these all up here rather than having them scattered through the script obj = Expr( //the graph builder plot which is gb gb = dt2 << Graph Builder( Size( 640, 230 ), Show Title( 0 ), ////opt Show Control Panel( 0 ), Legend Position( "Inside Left" ), Variables( X( Column( dt2, 1 ) ), Y( :Data ), Overlay( :Column Names ) ), //:Row needs to be dynamic based on x or no x in dialog. Elements( Line( X, Y, Legend( 7 ) ) ), SendToReport(Dispatch( {}, "400", LegendBox, {Set Title( "" )} ) ), SendToReport(Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( "Scaled Response Graph" )} ) ), SendToReport(Dispatch( {}, "Data", ScaleBox, {Label Row( Show Major Labels( 0 ) )} )), SendToReport(Dispatch( {}, "Y title", TextEditBox, {Set Text( "" )} )) ) ); objwin = Expr( //window that everything ends up in New Window( "Scaled Response Graph with Multiple Y's" ) ); objout = Expr( //outline box Outline Box( "Y-axis Labels" ) ); objhlb1 = Expr( H List Box( "1" ) ); //this one has the axis plots objhlb2 = Expr( H List Box( "1" ) ); //this one has the obj graph objvlb = Expr( V List Box( "1" ) ); //this one has out and dt2stackcols = Expr( columns() ); //column names to stack dt2stack = Expr( //the stack expression with arguments. Note: the column argument MUST be first. stack( Source Label Column( "Column Names" ), Stacked Data Column( "Data" ) ) ); //////////////////////////////////////////////////////////////////// Dialog to get column names 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 /////////////////////////////////////////////////////////////////// Standardized Data Table, and "Axis Boxes"" 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() ) ) ); For( 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 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 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 ) ); //its not a true axis box, just a squished graph box. the axis box was free Insert Into( objhlb1, Name Expr( obj1 ) ); //there is a lot of inserting of name expr() here. its part of building expressions from the inside out. ); ///////////////////////////////////////////////////////////////stack standardized data for graphing 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); dt2 = dt1 << Eval Expr( dt2stack ); eval(substitute(expr(dt2=dt1< Find a more detailed set of notes on how the script works here:
https://community.jmp.com/t5/Byron-Wingerd-s-Blog/Multiple-Y-Axis-Graphs/ba-p/52000
Life Sciences