Autoscale by script


Recommended Posts

Hi Guru!

In an effort to provide my user with a way to scale a graph in runtime, I am using sliders for both the X and Y axis. This works well, however nothing I do is as good as the "Autoscale both axis" command, which of course is not available in runtime.

While I have successfully used the strScaleTo and the TimeWidth commands, and I've scoured the forum and the UserGuide for clues, I still cannot find the explicit script or combination of commands that accomplishes "Autoscale Both Axis".

Could you please shed some light on how it works?


Link to comment
Share on other sites

Well, first, you can do Auto-scale both Axes from runtime. The graph popup menu is still available from runtime, though a few options are eliminated. Simply right click on the graph at runtime.

As for how its done, it basically takes the min / max values for the trace for the particular axis, then adds/subtracts 2% of the difference so that the min/max don't lie right at the edge of the graph. Its pretty easy if you have one trace:

private myMin = min(myExpression)

private myMax = max(myExpression)

private dif = myMax - myMin

component.myGraph.leftAxis1.strScaleFrom = myMin - dif * 0.02

component.myGraph.leftAxis1.strScaleTo = myMax + dif * 0.02

If you have multiple traces, you'll need to figure out the max / min of all the traces.

Link to comment
Share on other sites

You can get the history length by access the channel's member variables:


However, that won't really get what you want for a number of reasons, first you'd have to also use the Interval, second, you'd be assuming the data actually came in at that interval, and most importantly, it won't take into account what happens before the history is filled. The best way then is to access the first and last points and get their time:

timeMin = myChannel.time[myChannel.numRows()-1]

timeMax = myChannel.time[0]

Then just apply the dif stuff I did before.

Link to comment
Share on other sites

Hi Guru!

I was able to solve this problem and I wanted to share it for those who may need it. I must qualify that my data set is a static, non-changing set of numbers (a control chart), although this may work in realtime as well. Attached is a screengrab of the page containing the graph. The channel data is loaded to the graph by selecting the channel number on the on-screen keypad.

The code is as follows:

// Constants:
Component.MyChart.MyTrace.Color = rgb(255,0,0)   // I chose Red
Component.MyChart.MyTrace.LineType = 10  // I chose Medium Solid Line
Component.MyChart.MyTrace.PointType = 5  // I chose Diamond
Component.MyChart.XAxisFrozen = 0  // Be sure to thaw the axis first
Component.MyChart.YAxisFrozen = 0  // Be sure to thaw the axis first
Component.MyChart.BottomAxis.UseTimeWidth = 0
Component.MyChart.LeftAxis1.strAutoScaleFrom = ""
Component.MyChart.BottomAxis.strAutoScaleFrom = ""
// Function:
	  case(MyVariable_1 == 1)
		 Component.MyChart.MyTrace.StrYExpression = "MyChannel[]"
		 Component.MyChart.MyTrace.StrXExpression = "MyChannel.Time"		
		 private timeMin = MyChannel.time[numRows(MyChannel)-1]
		 private timeMax = MyChannel.Time[0]
		 Component.MyChart.BottomAxis.strScaleFrom = timeMin
		 Component.MyChart.BottomAxis.strScaleTo = timeMax				
		 Component.MyChart.LeftAxis1.strScaleFrom = (Min(MyChannel[]) - 50)
		 Component.MyChart.LeftAxis1.strScaleTo = (Max(MyChannel[]) + 50)
		 Component.MyChart.LowerBoundValue = (Mean(MyChannel[]) * 0.8)
		 Component.MyChart.UpperBoundValue = (Mean(MyChannel[]) * 1.2)
	  case(MyVariable_2 == 1)
		 // Do the same for your other channels
// End Sequence

I execute my sequence when I switch to the page containing the graph, and it automatically autoscales for me.

Link to comment
Share on other sites

Thanks. Three comments, in increasing order of complexity:

1) you don't need [] after your channels. Just putting MyChannel is the same as MyChannel[]

2) in general, always put at least:

? strLastError

inside a catch(). Otherwise, if you have a typo inside the try block, you'll never know what it is. DAQFactory will just quietly jump out of your script and you won't know why things didn't work like they should.

3) Whenever you are cutting / pasting code and just changing one item, you should think about how to make simplify. Since DAQFactory doesn't support pointers really, you often have to use a combination of execute() and evaluate() to do this. In your case, you could do this a couple ways. I personally would probably create an array with the channel names:

private chans = {"", "MyChannel","MyOtherChannel"}

Then, instead of the switch, index into chans based on MyVariable_1:

private theChan = chans[myVariable_1]

then use theChan and evaluate()/execute(). For example:

Component.MyChart.MyTrace.StrYExpression = theChan

Component.MyChart.MyTrace.StrYExpression = theChan + ".Time"

private timeMin = evaluate(theChan + ".time[numrows(" + theChan + ") + 1]")


Actually, you don't need execute(), just evaluate().

Then you don't have to have these repetitive blocks of code that are essentially the same. You could also create a function that does the block of code for setting the graph trace based on a string parameter passed to it.

Link to comment
Share on other sites

Hi Guru!

Learning to code is one of the most challenging and satifying endeavors I've ever faced. Doing it well is something I really look forward to.

This is what makes DF so great. I don't think I could have ever gotten this far with any other program. I will bone up on execute() and evaluate()...!

Thanks for your support!!


Link to comment
Share on other sites

  • 1 month later...


This topic is now archived and is closed to further replies.