How can a make or set the Y-axis of a processanalyst pen dynamically, based on an argument when I call the cicode function to be implemented

I made a normal trend using this code displaying the average measurement value and scaling the Y-axis automatically to predefined values (arguments).

I call the function from a button and in the input property of the button - up action - up-command like: loadZoomTrend_loc_for("TR_201_FluxHoogte", S201_fh_Min, S201_fh_Max);

FUNCTION
loadZoomTrend_loc_for (STRING strTrenTagF, REAL intSchaal0F, REAL intSchaal100F)

// Avg waarde
	TrnSetPen(31, 1, strTrenTagF);
	SleepMS(20);

//Y-axis scale automatic	
	REAL Range = intSchaal100F - intSchaal0F;
	REAL Avg = (intSchaal100F + intSchaal0F)/2;
	REAL ScaleMax = Avg + Range*2;
	REAL ScaleMin = Avg - Range*2;
	SleepMS(20);
	
	TrnSetScale(31, -1, 0, ScaleMin);
	SleepMS(20);
	TrnSetScale(31, -1, 100, ScaleMax);
	SleepMS(20);

//X-as span
	TrnSetSpan(31,3600); //28800 = 8 uur / 21600 = 6 uur / 14400 = 4 uur / 7200 = 2 uur / 3600 = 1 uur
	SleepMS(20);
END

This works great but I have some limitations regarding this trending output.

Now I want to do the same in process analyst using also cicode function.
How do I do that?

Thanks for your support.

Parents
  • I believe you want the PutVerticalAxisSpan method in the Process Analyst. See this help page for more info and brief examples.

    See also TN6374: https://softwaresupportsp.aveva.com/#/knowledgebase/details/000028548?lang=en_us

    It has an example of how to add pens to process analyst and set a bunch of properties. It enables auto scale mode, but your could use PutVerticalAxisSpan in place of that.

    Basically, you just need to get Process Analyst object handle, get the pane handle, get the pens group handle, create a pen within that group, then set the pen's properties:

    hPA = ObjectByName(sPaObjectName);
    hPane = GetPane(hPA, sPane);
    hPens = _ObjectGetProperty(hPane, "Pens");
    hPen = _ObjectCallMethod(hPens, "Create", nPenType, nNameMode);
    _ObjectSetProperty(hPen, "DataPoint", sPen);
    _ObjectSetProperty(hPen, "VerticalAxisAutoscale", TRUE);

  • Hello Eric,

    I took a look at the code and was a little bit overwhelmed.
    I'm quit a noob in coding with aveva scada ci-code.

    Maybe you can help me getting started.

    This is what I am trying to chart:


    6 pens, all in one pane, stacked.

    In this example I added the pens manually but I want this to be set in the up-command line like I did in the normal trending code (see above)
    I call the function from a button and in the input property of the button - up action - up-command like:

    loadTrend_PA("TR_201_FluxHeight", S201_fh_Min, S201_fh_Max, "TR_201_LineSpeed", S201_ls_Min, S201_ls_Max,"TR_201_BeltSpeed", S201_bs_Min, S201_bs_Max, etc etc );

    The max and min values for the Y-axis are the ' S201_* ' arguments where as the ' "TR_201_ *" ' arguments are the pens to trend.

    What would be best?
    Save this layout as a .pav file, load it, add the pens to the pane and adjust the Y-axis or start from scratch in, not loading a view ( *.pav file ), adding the pane, change to the correct background color, add pen, change the pencolor, adjust Y-axis etc etc.?

    Much obliged for your assistance.

  • If you're not familiar with writing Cicode functions and working with ActiveX objects in Cicode, then it is a lot to learn at once. However, it is much easier to manually create the layout you want in the runtime and save it to a PAV file. You can then use the built-in command ProcessAnalystLoadFile() to re-open it from a button.

    I think the question is: do you need to have variable scales for each of the trend pens? PlantSCADA is designed so that you set the variable min and max values in the variable tag properties. Or, if needed, you can set a different range in the trend tag properties. Also, in Process Analyst you can set pens to be auto-scaled according to the min/max values currently displayed.

    If you really need variable setpoints, you would need to write a Cicode function to add the pens and set the scales and other properties. Or you could just load a PAV file with the pens preconfigured, then use a Cicode function to loop through all the currently-displayed pens and edit their scales.

  • Hello Eric, 

    I would like to have less pages, that's why I want to make the PA charting as flexible, and dynamically as possible so I can call one page or function to do it all. That's why I want to use the arguments in the input property of the button.

    Therefor I would like to have the y-axis dependant on the arguments for it. 

  • Maybe I am asking to much. 

    It's the perfectionist in me.

    The issue is that every product we make has a different setpoint and I would like to have this setpoint in the middle of the chart. 

    If I do not do it like this I must make 50 pages for 50 recipes and that's not the way I think do do this. 

  • been a while since we wrote this, but check out the below, it auto-scales every 30 seconds while the graphic is active by setting the span to be PV + / - 5.  The intent is to show the PV with an upper and lower tolerable band, and then have an upper and lower (wider) alarm band

    FUNCTION PAPageAutoScale(INT nSleepTime = 30) !Called while page active

    PAAutoScaleEnable=1;

    WHILE 1 DO

    PAAutoScale("AN39", 1);
    PAAutoScale("AN39", 2);
    PAAutoScale("AN39", 3);
    PAAutoScale("AN39", 4);
    PAAutoScale("AN40", 1);
    PAAutoScale("AN40", 2);
    PAAutoScale("AN40", 3);

    Sleep(nSleepTime);

    END

    END

    FUNCTION PAAutoScale( STRING sPAName = "", INT nPane = 1)

    OBJECT hPen1;
    OBJECT hPen2;
    OBJECT hPen3;
    OBJECT hPen4;
    OBJECT hPen5;
    OBJECT hAnalyst;
    OBJECT hPanes;
    OBJECT hPane;
    OBJECT hPens;
    STRING sHiAlmMax;
    STRING sLoAlmMin;
    STRING sPVMax;
    STRING sPVMin;
    REAL rHiAlmMax;
    REAL rLoAlmMin;
    REAL rPVMax;
    REAL rPVMin;
    REAL rSpanHi;
    REAL rSpanLo;

    hAnalyst = ObjectByName(sPAName);
    hPanes = _ObjectGetProperty(hAnalyst,"Panes");
    hPane = _ObjectCallMethod(hPanes,"get_Item",nPane);
    hPens = _ObjectGetProperty(hPane,"Pens");

    hPen1 = _OBJECTCallMethod(hPens, "get_item", 1);
    hPen2 = _OBJECTCallMethod(hPens, "get_item", 2);
    hPen3 = _OBJECTCallMethod(hPens, "get_item", 3);
    hPen4 = _OBJECTCallMethod(hPens, "get_item", 4);
    hPen5 = _OBJECTCallMethod(hPens, "get_item", 5);

    sHiAlmMax = _ObjectCallMethod(hPen1, "GetStatistic", "Maximum");
    sPVMax = _ObjectCallMethod(hPen3, "GetStatistic", "Maximum");
    sPVMin = _ObjectCallMethod(hPen3, "GetStatistic", "Minimum");
    sLoAlmMin = _ObjectCallMethod(hPen5, "GetStatistic", "Minimum");

    rHiAlmMax = StrToReal(sHiAlmMax);
    rLoAlmMin = StrToReal(sLoAlmMin);
    rPVMax = StrToReal(sPVMax);
    rPVMin = StrToReal(sPVMin);

    IF rHiAlmMax > rPVMax THEN
    rSpanHi = rHiAlmMax + 5.0;
    ELSE
    rSpanHi = rPVMax + 5.0;
    END

    IF rLoAlmMin < rPVMin THEN
    IF rLoAlmMin = 0 THEN //when LowDevAlm is deactivated by user
    rSpanLo = 0;
    ELSE
    rSpanLo = rLoAlmMin - 5.0;
    END
    ELSE
    rSpanLo = rPVMin - 5.0; //be sure that PV is visible
    END

    _OBJECTCallMethod(hPen1, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    _OBJECTCallMethod(hPen2, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    _OBJECTCallMethod(hPen3, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    _OBJECTCallMethod(hPen4, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    _OBJECTCallMethod(hPen5, "PutVerticalAxisSpan", rSpanLo, rSpanHi);

    END

  • Hello Greg,

    I tried to incorporate your code into my code and ended up with this:

    FUNCTION
    loadProcessAnalyst_advAS (STRING strFileTag)
    
    	PageDisplay("1_Recorder_PA_print");
    	SleepMS(20);
    	ProcessAnalystLoadFile(strFileTag, 0, 483, "AN139");
    	OBJECT hProcessAnalyst = ObjectByName("AN139");
    	_ObjectCallMethod(hProcessAnalyst, "SynchroniseToNow");
    	SleepMS(20);
    // END
    
    // FUNCTION PAPageAutoScale(INT nSleepTime = 10) !Called while page active
    
    PAAutoScaleEnable=1;
    
    WHILE 1 DO
    
    PAAutoScale("AN139", 1);
    Sleep(5);
    
    END
    
    END
    
    FUNCTION PAAutoScale( STRING sPAName = "", INT nPane = 1)
    
    OBJECT hPen1;
    OBJECT hAnalyst;
    OBJECT hPanes;
    OBJECT hPane;
    OBJECT hPens;
    STRING sPVMax;
    STRING sPVMin;
    REAL rPVMax;
    REAL rPVMin;
    REAL rSpanHi;
    REAL rSpanLo;
    
    hAnalyst = ObjectByName(sPAName);
    hPanes = _ObjectGetProperty(hAnalyst,"Panes");
    hPane = _ObjectCallMethod(hPanes,"get_Item",nPane);
    hPens = _ObjectGetProperty(hPane,"Pens");
    
    hPen1 = _OBJECTCallMethod(hPens, "get_item", 1);
    
    sPVMax = _ObjectCallMethod(hPen1, "GetStatistic", "Maximum");
    sPVMin = _ObjectCallMethod(hPen1, "GetStatistic", "Minimum");
    
    rPVMax = StrToReal(sPVMax);
    rPVMin = StrToReal(sPVMin);
    
    rSpanHi = rPVMax + 5.0;
    rSpanLo = rPVMin - 5.0; 
    
    _OBJECTCallMethod(hPen1, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    
    END
    

    But during compilation I get:

    referring to:

    Any idea what I am doing wrong?

  • PAAutoScaleEnable is likely to be either a local or global variable (or tag) designed to turn autoscaling on or off for their project (e.g. attached to a button or something on the page).

    The function Greg gave you doesn't actually use it, so you can delete it.

  • Hello Bradley,

    After removing PAAutoScaleEnable=1; it compiled correctly but the trend will not autoscale.
    I am missing some command to execute the 2nd function every 5 seconds, I think.

    The intension should be that when this page is visible (loaded/displayed) every 5 seconds the trend Y axis is updated based on the max and min values

  • Hi Jan,

    There could be a number of reasons why it is not working, but I suspect it is probably hitting an error and aborting. I would put breakpoints in your functions and attach the Cicode Debugger. If all your code is executing in foreground that won't work, so you can use trace statements to see where it is getting up to.


    When is the function loadProcessAnalyst_advAS called?


    I noted in that function it ends with a WHILE 1 DO which then calls the PAAutoscale function which also does a WHILE 1 DO. So that needs to be corrected.

    Because you want to execute this code every so many seconds you need to consider when it needs to be called, and what happens when someone interacts with the PA (e.g. deletes a pen), or changes pages.

    Probably the easiest method, is to just execute the PAAutoscale function on the Process Analyst's pages' OnPageShown event. (Open the page in Graphics Builder, go to File >Properties, then the Event tab, and paste the function into the On Page Shown event).

    This will mean, everytime that Process Analsyt page is shown it will begin executing this function - regardless of whether the PA actually has any pens on display.

    For this to work, you would need to improve the PAAutoScale function by adding in Error handling. What I mean by that, is that is calling ObjectIsValid before executing commands like ObjectCallMethod/GetProperty etc. I have feeling you would probably need to put ErrSet(1) at the beginning of the PAAutoScale function and ErrSet(0) at the end as well to prevent the function terminating if the user did something in the PA just after you validated the object.

    I would also "Pause the function" whenever you call loadProcessAnalyst_advAS as well. You can use a global variable for that. There is no point trying to autoscale while a PAV file is loading. You can undo the pause by handling the Process Analyst's ViewLoadedSaved event: ViewLoadedSaved[Event]. This will tell you when the file is finished loading and ready.

  • I have added a tag in Studio like:

    but then I get errors because I do not have an address

    So I put in an 'fake' address like 'i999' and it compiles OK.

    The I have set this into the page property:

    So in theory on page entry the PAAutoScaleEnable tag should be set to 1

    But doing it like this still does not trigger the while do when coded like:

    FUNCTION
    loadProcessAnalyst_advAS (STRING strFileTag)
    
    	PageDisplay("1_Recorder_PA_print");
    	SleepMS(20);
    	ProcessAnalystLoadFile(strFileTag, 0, 483, "AN139");
    	OBJECT hProcessAnalyst = ObjectByName("AN139");
    	_ObjectCallMethod(hProcessAnalyst, "SynchroniseToNow");
    	SleepMS(20);
    
    WHILE PAAutoScaleEnable=1 DO
    
    PAAutoScale("AN139", 1);
    Sleep(5);
    
    END
    
    END
    
    FUNCTION PAAutoScale( STRING sPAName = "", INT nPane = 1)
    
    OBJECT hPen1;
    OBJECT hAnalyst;
    OBJECT hPanes;
    OBJECT hPane;
    OBJECT hPens;
    STRING sPVMax;
    STRING sPVMin;
    REAL rPVMax;
    REAL rPVMin;
    REAL rSpanHi;
    REAL rSpanLo;
    
    hAnalyst = ObjectByName(sPAName);
    hPanes = _ObjectGetProperty(hAnalyst,"Panes");
    hPane = _ObjectCallMethod(hPanes,"get_Item",nPane);
    hPens = _ObjectGetProperty(hPane,"Pens");
    
    hPen1 = _OBJECTCallMethod(hPens, "get_item", 1);
    
    sPVMax = _ObjectCallMethod(hPen1, "GetStatistic", "Maximum");
    sPVMin = _ObjectCallMethod(hPen1, "GetStatistic", "Minimum");
    
    rPVMax = StrToReal(sPVMax);
    rPVMin = StrToReal(sPVMin);
    
    rSpanHi = rPVMax + 5.0;
    rSpanLo = rPVMin - 5.0; 
    
    _OBJECTCallMethod(hPen1, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    
    END
    
    

    Any help is appriciated

Reply
  • I have added a tag in Studio like:

    but then I get errors because I do not have an address

    So I put in an 'fake' address like 'i999' and it compiles OK.

    The I have set this into the page property:

    So in theory on page entry the PAAutoScaleEnable tag should be set to 1

    But doing it like this still does not trigger the while do when coded like:

    FUNCTION
    loadProcessAnalyst_advAS (STRING strFileTag)
    
    	PageDisplay("1_Recorder_PA_print");
    	SleepMS(20);
    	ProcessAnalystLoadFile(strFileTag, 0, 483, "AN139");
    	OBJECT hProcessAnalyst = ObjectByName("AN139");
    	_ObjectCallMethod(hProcessAnalyst, "SynchroniseToNow");
    	SleepMS(20);
    
    WHILE PAAutoScaleEnable=1 DO
    
    PAAutoScale("AN139", 1);
    Sleep(5);
    
    END
    
    END
    
    FUNCTION PAAutoScale( STRING sPAName = "", INT nPane = 1)
    
    OBJECT hPen1;
    OBJECT hAnalyst;
    OBJECT hPanes;
    OBJECT hPane;
    OBJECT hPens;
    STRING sPVMax;
    STRING sPVMin;
    REAL rPVMax;
    REAL rPVMin;
    REAL rSpanHi;
    REAL rSpanLo;
    
    hAnalyst = ObjectByName(sPAName);
    hPanes = _ObjectGetProperty(hAnalyst,"Panes");
    hPane = _ObjectCallMethod(hPanes,"get_Item",nPane);
    hPens = _ObjectGetProperty(hPane,"Pens");
    
    hPen1 = _OBJECTCallMethod(hPens, "get_item", 1);
    
    sPVMax = _ObjectCallMethod(hPen1, "GetStatistic", "Maximum");
    sPVMin = _ObjectCallMethod(hPen1, "GetStatistic", "Minimum");
    
    rPVMax = StrToReal(sPVMax);
    rPVMin = StrToReal(sPVMin);
    
    rSpanHi = rPVMax + 5.0;
    rSpanLo = rPVMin - 5.0; 
    
    _OBJECTCallMethod(hPen1, "PutVerticalAxisSpan", rSpanLo, rSpanHi);
    
    END
    
    

    Any help is appriciated

Children
No Data