Hi,
For a project I´m working on I have created a graph with time on the x-axis which shows a period of approx 24 hours. To visually illustrate when it is night time and day time I have added reference lines as shown in the below script and attached image.
Properties for x-axis column:
SableData << New Column(
"Time since first dose-[hours]",
Numeric, "Continuous",
Format("Best", 12),
Formula((:Date Time - :StartTime) / (60 * 60)),
Set Property("Spec Limits", {LSL(8), USL(20), Show Limits(0)}), Set Selected);
Creating graph, adding and configuring ref lines:
Oxygen consumption = SableData << Graph Builder(
Size( 1007, 689 ),
Variables(
X( :Name( "Time since first dose-[hours]" ) ),
Y( :Name("VO2-[ml/min]" )),
Overlay( :Treatment )
),
Elements( Line( X, Y, Legend( 21 ), Error Bars( "Standard Error" ) ) ),
SendToReport(
Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( "Oxygen consumption" )} ),
Dispatch(
{},
"Time since first dose-[hours]",
ScaleBox,
{Min( 168 ), Max( 288), Inc( 2 ), Minor Ticks( 12 )}
),
Dispatch(
{},
"400",
ScaleBox,
{Legend Model(
21,
Properties( 0, {Line Color( 0 )}, Item ID( "A", 1 ) ),
Properties(
1,
{Line Color( 53 )},
Item ID( "B", 1 )
),
Properties(
2,
{Line Color( 37 )},
Item ID( "C", 1 )
),
Properties( 3, {Line Color( 0 )}, Item ID( "A", 2 ) ),
Properties(
4,
{Line Color( 53 )},
Item ID( "B", 2 )
),
Properties(
5,
{Line Color( 37 )},
Item ID( "C", 2 )
)
)}
),
Dispatch( {}, "Graph Builder", FrameBox, {Marker Size( 0 )} ),
Dispatch( {}, "400", LegendBox, {Set Title( "" )} )
)
);
Eval(
Substitute(
Expr(
Report( Oxygen consumption )[AxisBox( 1 )] << Add Ref Line( {__LSL__, __USL__}, "Solid", "Black", "", 1, 0.25 ) //try show limits(1) in spec limits
),
Expr( __LSL__ ), (SableData:Name( "Time since first dose-[hours]" ) << get property( "spec limits" ))["LSL"],
Expr( __USL__ ), (SableData:Name( "Time since first dose-[hours]" ) << get property( "spec limits" ))["USL"]
));
But now I have data covering two weeks and I would still like to illustrate visually when it is night and day. I can of course add these manually but and copy the script but I would like to do this in a robust manner.
Can I in any way add these extra properties to the "Time since first dose-[hours]"
column or is it possible to create a separate data table including all limits and pull them into the data table in one go?
Thanks in advance.
Br Julie
The second problem with the light and dark phase lines not showing up where expected is due to a mismatch between the axis variable and the variable used to define where the lines should go.
In the graph the x axis is a duration and in the custom script the lines are based on the row number, so graph builder uses the row number and plots it on the time duration, which kind of just doesn't work.
I added a couple of columns to the data table, they are similar to some of the original columns, but with some small tweaks and formatting differences.
//if you have the data table open, make it the active table and run this
dt=current data table();
dt<<New Column( "Time 2",
Numeric,
"Continuous",
Format( ":day:hr:m", 14 ),
Input Format( ":day:hr:m" ),
Formula( :DateTime - :StartTime ),
Set Selected
);
dt<<New Column( "step2",
Numeric,
"Continuous",
Format( "Best", 12 ),
Formula( If( :Phase == "Dark phase", 0, 1 ) ),
Set Selected
);
dt<<New Column( "phase2",
Character,
"Nominal",
Formula( If( :Phase == "Dark phase", "D", "L" ) )
);
The next step is to edit the custom script in the graph.
//This script goes into the Custom Script in the graph builder plot
For Each Row( If( Is Missing( :NewPhase ) == 0, V Line( :Time2 ) ) );
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text( {:Time2, 5 + :step2}, " "||:Phase2 )
)
);
//The, " "||:phase2, inserts a space before the label so that it isn't touching the phase line.
The result is the fixed graph, like this.
With all the changes, the x-axis is now in Days:Hours:minutes format, and all the light and dark phase lines show up in the right place. The phase label is abbreviated so that it doesn't overlap and just make a jumble off messy text.
Graph script
Graph Builder(
Size( 1455, 290 ),
Show Control Panel( 0 ),
Variables( X( :Time2 ), Y( :Name( "EE-[kcal/h]" ) ), Overlay( :Treatment ) ),
Elements( Line( X, Y, Legend( 5 ) ) ),
SendToReport(
Dispatch(
{},
"Time2",
ScaleBox,
{Min( -586333.5 ), Max( 2531060.48337292 ), Interval( "Day" ), Inc( 1 ),
Minor Ticks( 6 ), Label Row( Label Orientation( "Perpendicular" ) )}
),
Dispatch(
{},
"EE-[kcal/h]",
ScaleBox,
{Format( "Best", 12 ), Min( 1.7751677852349 ), Max( 5.7751677852349 ),
Inc( 1 ), Minor Ticks( 0 )}
),
Dispatch(
{},
"Graph Builder",
FrameBox,
{Add Graphics Script(
2,
Description( "Script" ),
For Each Row( If( Is Missing( :NewPhase ) == 0, V Line( :Time2 ) ) );
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text( {:Time2, 5 + :step2}, " " || :Phase2 )
)
);
), Grid Line Order( 1 ), Reference Line Order( 3 ),
DispatchSeg(
TopSeg( 1 ),
{Set Script(
For Each Row(
If( Is Missing( :NewPhase ) == 0,
V Line( :Time2 )
)
);
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text( {:Time2, 5 + :step2}, " " || :Phase2 )
)
);
)}
)}
)
)
)
I've used columns to define when to add reference lines. I suppose it would be just as easy to add ranges too.
Here are some notes that might be useful: Event Lines and Comments on Control Charts
Hi @Byron_JMP
Thanks for the suggestion.
I tried using the setup you describe and it worked to some extend. In order to follow the same process I created a new column in my data table (NewPhase) where the rows that are not missing should result in a event line.
I based the NewPhase column output solely on the animal number with the highest number of rows so that I will only get one set of event lines instead one for each animal:
DataPointsAnimal = SableData << Summary(
Group( :Animal No. ),
N( :Phase ),
Freq( "None" ),
Weight( "None" ));
DataPointsAnimalSorted = DataPointsAnimal << Sort( By( :N Rows ), Order( Descending ) );
Close( DataPointsAnimal, No Save );
AnimalVar = DataPointsAnimalSorted:Animal No.[1];
SableData << New column("NewPhase", Formula(If( :Animal No. == AnimalVar,
If( :Phase == Lag( :Phase, 1 ),
.,
"new"
),
.
)));
I then created the graph with your input
Graph Builder(
Size( 924, 695 ),
Variables(
X( :Name( "Time since first dose-[hours]" ) ),
Y( :Name( "EE-[kcal/h]" ) ),
Overlay( :Treatment )
),
Elements( Line( X, Y, Legend( 5 ) ) ),
SendToReport(
Dispatch(
{},
"Graph Builder",
FrameBox,
{Add Graphics Script(
2,
Description( "Script" ),
For Each Row( If( Is Missing( :NewPhase ) == 0, V Line( Row() ) ) );
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text(
Right Justified,
{Row(), Col Maximum( :Name( "EE-[kcal/h]" ) ) * 1.2},
:Phase
)
)
);
), Grid Line Order( 1 ), Reference Line Order( 3 )}
)
)
);
But for some reason it only includes a limited amount of lines and it doesn´t include any text at all.
What am I doing wrong?
it looks like it works fine, just not as expected, due possibly to an outlier...
the column max() of the Y axis variable is over 23. So the text shows up off scale with the rest of the figure.
The second problem with the light and dark phase lines not showing up where expected is due to a mismatch between the axis variable and the variable used to define where the lines should go.
In the graph the x axis is a duration and in the custom script the lines are based on the row number, so graph builder uses the row number and plots it on the time duration, which kind of just doesn't work.
I added a couple of columns to the data table, they are similar to some of the original columns, but with some small tweaks and formatting differences.
//if you have the data table open, make it the active table and run this
dt=current data table();
dt<<New Column( "Time 2",
Numeric,
"Continuous",
Format( ":day:hr:m", 14 ),
Input Format( ":day:hr:m" ),
Formula( :DateTime - :StartTime ),
Set Selected
);
dt<<New Column( "step2",
Numeric,
"Continuous",
Format( "Best", 12 ),
Formula( If( :Phase == "Dark phase", 0, 1 ) ),
Set Selected
);
dt<<New Column( "phase2",
Character,
"Nominal",
Formula( If( :Phase == "Dark phase", "D", "L" ) )
);
The next step is to edit the custom script in the graph.
//This script goes into the Custom Script in the graph builder plot
For Each Row( If( Is Missing( :NewPhase ) == 0, V Line( :Time2 ) ) );
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text( {:Time2, 5 + :step2}, " "||:Phase2 )
)
);
//The, " "||:phase2, inserts a space before the label so that it isn't touching the phase line.
The result is the fixed graph, like this.
With all the changes, the x-axis is now in Days:Hours:minutes format, and all the light and dark phase lines show up in the right place. The phase label is abbreviated so that it doesn't overlap and just make a jumble off messy text.
Graph script
Graph Builder(
Size( 1455, 290 ),
Show Control Panel( 0 ),
Variables( X( :Time2 ), Y( :Name( "EE-[kcal/h]" ) ), Overlay( :Treatment ) ),
Elements( Line( X, Y, Legend( 5 ) ) ),
SendToReport(
Dispatch(
{},
"Time2",
ScaleBox,
{Min( -586333.5 ), Max( 2531060.48337292 ), Interval( "Day" ), Inc( 1 ),
Minor Ticks( 6 ), Label Row( Label Orientation( "Perpendicular" ) )}
),
Dispatch(
{},
"EE-[kcal/h]",
ScaleBox,
{Format( "Best", 12 ), Min( 1.7751677852349 ), Max( 5.7751677852349 ),
Inc( 1 ), Minor Ticks( 0 )}
),
Dispatch(
{},
"Graph Builder",
FrameBox,
{Add Graphics Script(
2,
Description( "Script" ),
For Each Row( If( Is Missing( :NewPhase ) == 0, V Line( :Time2 ) ) );
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text( {:Time2, 5 + :step2}, " " || :Phase2 )
)
);
), Grid Line Order( 1 ), Reference Line Order( 3 ),
DispatchSeg(
TopSeg( 1 ),
{Set Script(
For Each Row(
If( Is Missing( :NewPhase ) == 0,
V Line( :Time2 )
)
);
For Each Row(
If( Is Missing( :NewPhase ) == 0,
Text( {:Time2, 5 + :step2}, " " || :Phase2 )
)
);
)}
)}
)
)
)
Wow thanks a lot for the explanation. That made good sense and it works beautifully too.
That is a very fun data set, thanks for posting it and your questions.
If I had infinite time, it would look even better if the dark phases were an interval line that was shaded just a little bit grey. Maybe someone else can pick that up and run with it?
I actually had help with that and it it turned out something like this:
DarkLight = SableData << select where(:NewPhase == "new" ) << subset(
Output Table("DarkLight"),
columns(
:Date,
:Phase,
:Name("Time since first dose-[hours]"),
:NewPhase)
);
DarkLight:Date << data type( Character ) << Set Modeling Type( Nominal );
DarkLight << new column("Phase per day", Character, "Nominal", Formula( :Date || "-" || :Phase ) );
DarkLight << new column("High", Numeric, "Continuous", Formula(
Lag( :Name( "Time since first dose-[hours]" ), -1 ))
);
DarkLight:High << delete formula;
DarkLight << new column("Color", Character, "Nominal", set each value("Grey"));
column(DarkLight, "Time since first dose-[hours]") << Set Name("Low");
DarkLight << select where(:Phase == "Light phase") << delete rows;
RQ = SableData << Graph Builder(
Size( 938, 712 ),
Variables(
X( :Name( "Time since first dose-[hours]" ) ),
Y( :RQ ),
Overlay( :Treatment )
),
Elements( Points( X, Y, Legend( 4 ) ) )
);
x axis = Report( RQ )[AxisBox(1)];
For Each Row( DarkLight,
// draw colored regon
Eval( Eval Expr( x axis << Add Ref Line( { Expr( :Low ), Expr( :High ) }, "Solid", Expr( :Color ), , , 0.25 ) ) );
// draw border lines
Eval( Eval Expr( x axis << Add Ref Line( Expr( :Low ), "Solid", "Black" ) ) );
Eval( Eval Expr( x axis << Add Ref Line( Expr( :High ), "Solid", "Black" ) ) );
);