16 Replies Latest reply on Feb 13, 2015 11:57 PM by asorokina

    Building a trend showing many variables for a single batch

    Claude Martineau

      There is request that I often have from my customers, which are working in plants that are batch based: they would like to have a trend showing many variables for a specific batch.

       

      This really seems simple at first.  However, the requirements are typically as follows:

      • the trend must start at the batch start time and end at the batch end time (or * if the batch is running). 
      • The trend must use a different pen color for each variable. 
      • The trend must show time as "Time into batch".

      If a regular Trend object is used, the trend start time and end time can be set (with VBA code) to the batch start and end time.  Each variable can easily be shown in a different color.  However, there is no way to have "time into batch" on the x-axis.  In such a trend, "relative time" puts time 0 on the right hand side, whereas a real "time into batch" puts time 0 on the left hand side.  That's a major difference.  People typically want to see What happened 50 or 100 hours after the batch start, not 50 or 100 hours before the batch end...

       

      If a Batch Trend is used, then having it start and end with the batch is standard.  Showing time as "Time into batch" is also a standard feature.  However, all the variables will be shown in the same color (the color is assigned to the whole batch, not to individual tags).  Therefore, such a trend is almost impossible to use if there is more than 2 or 3 tags.

       

      We have tried using an XY plot with a "time into batch" tag as the x-axis.  This approach gave correct results on a proof of concept, but the performance dropped to an acceptable level when the trend was showing a large number of values.  The low performance was due to the consant re-evaluation of the trend's statistics (such as correlation factor).

       

      Has anyone used an Activex trend object other than the standard OSIsoft ones?  Or developed a custom trend object?  All ideas are welcome!

       

      Claude Martineau

       

       www.gap5.com

        • Re: Building a trend showing many variables for a single batch

          Oooo I do like a challenge.

           

          After a few minutes playing with the standard OSISoft Trend object and some manipulation, you can come up with something to give you "Time into Batch".  Not using just a Trend object byt covering up part of it and making use of Trend Cursors.  Let me show you an example - please note I have only spent a couple of minutes on this but with some time you can build it into a powerful Trend for Batches.

          Here is an example of how it could look:

           

          So what I have done is created a normal Trend and placed a rectangle over the time portion of the Trend, we don't want to be confused by the time it displays.  I added 4 Text objects, 2 just act as labels whilst the other 2 will be assigned values from VBA.  I have named those in line with Trend, so if the Trend is "Trend1" then the Text objects are "Trend1_BatchTime" (top)  and "Trend1_TotalBatchTime" (bottom).

           

          Assuming you have written your VBA to set the starttime and endtime this is what you do next.
          A trend object that is Enabled for scripting has an event for when a cursor is "dropped", event = "_DropCursor".  So for "Trend1" the full event in VBA is "Trend1_DropCursor" from which you get the Cursor index number for the trend, which is key to this working.
          So we can capture when the user moves a cursor, get the cursor number and this is how we get the time into the batch.

          I created a quick routine to parse the cursor on the trend, the routine is fairly dynamic so you can throw multiple trends at it.  Here it is:  (assumes the 2 Text object are named accordingly)


          Sub ParseCursor(ByVal WhichTrend As String, ByVal WhichCursor As Integer)

          Dim MyTrend As Trend
          Set MyTrend = ThisDisplay.Symbols(WhichTrend)

          If MyTrend.CursorCount > 0 Then
              MyTrend.CurrentCursor = WhichCursor
              ThisDisplay.Symbols(WhichTrend & "_BatchTime").Contents = ElapsedTime(CDate(MyTrend.CursorTime) - CDate(MyTrend.StartTime))
          Else
              ThisDisplay.Symbols(WhichTrend & "_BatchTime").Contents = "No Cursor on Trend."
          End If

          ThisDisplay.Symbols(WhichTrend & "_TotalBatchTime").Contents = ElapsedTime(CDate(MyTrend.EndTime) - CDate(MyTrend.StartTime))

          Set MyTrend = Nothing

          End Sub

          Function ElapsedTime(ByVal Interval As Variant)
            Dim x As String
            x = Int(CSng(Interval * 24 * 3600)) & " Seconds"
            x = Int(CSng(Interval * 24 * 60)) & ":" & Format(Interval, "ss") _
               & " Minutes:Seconds"
            x = Int(CSng(Interval * 24)) & ":" & Format(Interval, "nn:ss") _
               & " Hours:Minutes:Seconds"
            x = Int(CSng(Interval)) & " days " & Format(Interval, "hh") _
               & " Hours " & Format(Interval, "nn") & " Minutes " & _
               Format(Interval, "ss") & " Seconds"
              ElapsedTime = x
          End Function

           

          And to use this, call the method from the DropCursor event:

          
          

          Private Sub Trend1_DropCursor(bCancel As Boolean, ByVal nCursor As Integer, ByVal NewTime As String)
              Call ParseCursor("Trend1", nCursor)
          End Sub

           

           

          All it does is set the Cursor index for the Trend (Trend.CurrentCursor property) and retrieves the time for the cursor (Trend.CursorTime property) and calculates the relative time into the batch for the cursor and formats it using an ElapsedTime function.  The total time for the trend is also displayed in case you have a routine that changes batches & batch times displayed on a trend.  Now each time the user adds a new cursor or moves an existing cursor that is the time into batch that is displayed.

           

          Not entirely what you were after but shows how powerful ProcessBook is on its own!

           

          If I had more time what I would do is calculate the total trend time (batch time), create myself an interval as the Standard trend object does for the major gridlines and dynamically add cursors (Trend.AddCursor method) and display the relative time into batch using a similar method as above for each cursor!

           

          Hope this helps.....

           

          RJK Solutions.

           

           

           

          (If ProcessBook developers are watching, maybe a toggle to reverse the relative time would be a good idea in the next release?)

            • Re: Building a trend showing many variables for a single batch
              Claude Martineau

              Thansk you very much for this reply,

               

              It is a very good workaround and definitely another tool to add to our toolbox. 

               

              I still see a few shortcomings to your solution, but they can probably be handled.  As an example, we sometimes build displays with a very large number of small trends and users maximixe them when they want to really look at them.  I do not believe that this approach would be usable as is on a maximized trend.  Another thing is that, with the cursor, the values of all tags are shown on screen.

               

              In the case of one customer, we came up with a somewhat similar solution: We have developed a PE tag, which was showing the "time into batch" in d hh:mm:ss format.  Then we added this tag to the trend (using a scale that made the trace always out of the trend).  With this, when a cursor is added to the trend, we see the time into batch in the cursor data).  As this tag is part of the trend, the time into batch is available even when the trend is maximized.

               

              What I like with your approach is that, as you pointed out, it could be expanded (with some development) to mimic the gridlines.  And the problem of maximizing the trend can probably be handled by intercepting the call to maximimize, cancel it and change manually the trend size to make it bigger (we have done something similar in another project).

               

              There is further development involved, but you really streered me in a promising direction.

               

              I totally agree with you last sentence: if developers could add a toggle to reverse the relative time, it would just be great.

               

              Thanks

                • Re: Building a trend showing many variables for a single batch

                  Claude Martineau

                  What I like with your approach is that, as you pointed out, it could be expanded (with some development) to mimic the gridlines.  And the problem of maximizing the trend can probably be handled by intercepting the call to maximimize, cancel it and change manually the trend size to make it bigger (we have done something similar in another project).

                   

                   


                  As I was reading your reply about maximising the trend I was thinking exactly what you mentioned later in your post

                   

                  This is a workaround and it would be nice to extend the Trend object and create it as an addin for ProcessBook.

                   

                  Let us know if you continue down this path and come up with a more solid solution.

                   

                  Cheers.

                    • Re: Building a trend showing many variables for a single batch

                      Thinking out loud again (might have something here), you can get a Trend to draw the time in relative format increasing from left to right but it gets a bit messy. 

                       

                      Basically get your Trend to draw a future trend and set the time stamp to relative, from the current time onwards you have the time increasing rather than decreasing.  If your batch time is 20 hours then set the start time to *  and the end time as *+20h.   Draw a second trend on top (*-20h to *) with an invisible background and no colour for the text but with the same data (for gridlines) as the first trend & same single scale (important) and overlay it on the first trend (ensure all trend formats are the same).  You have your data displayed with correct time format underneath.

                       

                      Thought it worthwhile mentioning.

                       

                      Heres an example:

                        • Re: Building a trend showing many variables for a single batch

                          Claude,

                           


                          Had spare 10 mintues so had another look at this and came up with a solution.  Uses 2 trends and a rectangle to achieve this:



                          You are not limited to single tag (like my example), you can use multiple tags.

                           

                          What it does, adds a "future" trend (* -> *+100h) then draws a rectangle same colour as default trend background colour over the trace portion of the trend.  Then draws a second trend on top of the rectangle with no colour set for the background & text.  This way you can still use cursors and so long as you use Multiple scales, you can still see the trace scale despite setting the text colour to no color.
                          The future trend relative time is calculated from the Batch Start & End time you supply.

                           

                          Hope this helps.

                           

                          VBA Code (obviously needs some refining as this is a 10 minute example and has some defaults/assumptions):

                          Private Sub test()
                              Dim srv As PISDK.Server: Set srv = PISDK.Servers("ServerName"): If Not srv.Connected Then srv.Open ("UID=user;PWD=pass")
                              Dim PL As New PISDK.PointList: Call PL.Add(srv.PIPoints("SINUSOID"))
                              Call AddPsuedoBatchTrend(DateAdd("d", -1, Now()), Now(), PL)
                          End Sub

                          Private Sub AddPsuedoBatchTrend(ByVal BatchStart As Date, ByVal BatchEnd As Date, ByVal PITags As PointList)

                          If BatchStart > BatchEnd Then
                              Call MsgBox("Batch start date must be before end date.", vbOKOnly)
                              Exit Sub
                          End If

                          If PITags.Count = 0 Then
                              Call MsgBox("You must supply at least 1 PI tag.", vbOKOnly)
                              Exit Sub
                          End If

                          Dim Rect As Rectangle
                          Dim DataTrend As Trend, Pnt As PIPoint
                          Dim BackTrend As Trend, TF As TrendFormat
                          Set BackTrend = ThisDisplay.Symbols.Add(pbSymbolTrend)
                              BackTrend.Top = 15000: BackTrend.Left = -15000
                              BackTrend.Height = 500: BackTrend.Width = 1000
                             
                              Set TF = BackTrend.GetFormat
                                  TF.ShowTitle = False: TF.ShowEngUnits = False: TF.ShowDescription = False
                                  TF.ShowTagName = False: TF.ShowServerName = False: TF.ShowValue = False
                                 
                                  Set Rect = ThisDisplay.Symbols.Add(pbSymbolRectangle)
                                  Rect.BackgroundColor = TF.Elements(pbBackGround).Color
                                  Rect.FillColor = TF.Elements(pbBackGround).Color
                                  Rect.LineColor = pbBlack
                                  Rect.Width = BackTrend.Width - 2
                                  Rect.Height = BackTrend.Height - 53
                                  Rect.Top = BackTrend.Top
                                  Rect.Left = BackTrend.Left
                                 
                                  Call BackTrend.SetFormat(TF)
                              Set TF = Nothing
                             
                              BackTrend.PlotTimeStyle = pbPTSRelative
                             
                              For Each Pnt In PITags
                                  Call BackTrend.AddTrace("\\" & Pnt.Server & "\" & Pnt.Name)
                              Next Pnt
                             
                              Call BackTrend.SetTimeRange("*", "*+" & DateDiff("n", BatchStart, BatchEnd) & "minutes")
                             
                          Set DataTrend = ThisDisplay.Symbols.Add(pbSymbolTrend)
                              Set TF = DataTrend.GetFormat
                                  TF.ShowTitle = False: TF.ShowEngUnits = False: TF.ShowDescription = False
                                  TF.ShowTagName = False: TF.ShowServerName = False: TF.ShowValue = False
                                  TF.Elements(pbBackGround).Color = -1: TF.Elements(pbText).Color = -1
                                  Call DataTrend.SetFormat(TF)
                              Set TF = Nothing
                             
                              DataTrend.Height = 500: DataTrend.Width = 1000
                             
                              Dim iTrace As Integer: iTrace = 1
                              For Each Pnt In PITags
                                  Call DataTrend.AddTrace("\\" & Pnt.Server & "\" & Pnt.Name)
                              Next Pnt
                             
                              Call DataTrend.SetTimeRange(BatchStart, BatchEnd)
                              DataTrend.MultipleScales = True
                              DataTrend.Top = BackTrend.Top
                              DataTrend.Left = BackTrend.Left
                             
                          Set Rect = Nothing
                          Set DataTrend = Nothing
                          Set BackTrend = Nothing

                          End Sub
                            • Re: Building a trend showing many variables for a single batch
                              Claude Martineau

                              Once again, thank you very much for your time and effort.

                               

                              I like your idea, but I still see some limitation: zooming would still be a challenge and and if a user changes the trend configuration (add the tag name on the right or adds/remove a tag) we would need to reajust the "future" trend as well

                               

                              What I have been working on is more in line with your first idea.  I have built on this to add a rectangle to cover the default x-axis, then I added text objects and lines to mimic the grid lines (with position that adjust themselves if the tagnames are displayed or not).  I have also added subs to intercept the double-click, so I can "manually" maximize the display.  When a cursor is dropped, a new text element is added to show the value at the time of the cursor.  When the trend is zoomed on, all the information follows.

                               

                              Here are a few screen shots

                               

                              1 - Normal view, with only the modified scale
                              Image1.bmp

                               

                              2 - After 2 cursors are added.  The time at the cursor is shown at the bottom

                               

                              Image2.bmp

                               

                              3 - With cursor and zoom.  The cursors and their values are kept.

                               

                              Image3.bmp

                               

                              Following are the main routines (the code still needs some cleaning, it is still a draft)

                               

                              Here is the core of the cursor sub:

                               

                                 

                              With ThisDisplay
                                      ' remove the text associated to this cursor
                                      For intLoop = .Symbols.Count To 1 Step -1
                                          If .Symbols(intLoop).Name = Trend.Name & "Cursor" & CurrentCursor Then
                                              .Symbols.Remove (intLoop)
                                          End If
                                      Next
                                     
                                      If Trend.CursorCount > 0 Then
                                          Trend.CurrentCursor = CurrentCursor
                                          ' Add a cursor text object
                                          strCursor = Trend.Name & "Cursor" & CurrentCursor
                                          Set txtText = .Symbols.Add(pbSymbolText)
                                          ' Set the value
                                          ' read the configuration start time
                                          datConfigStart.LocalDate = Trend.ConfigStartTime
                                          ' Read the display start time
                                          datStart.LocalDate = Trend.StartTime
                                          ' read the cursor time
                                          datCursor.LocalDate = Trend.CursorTime
                                           ' Read the end time
                                          If Len(Trend.EndTime) >= 19 Then
                                              datEnd.LocalDate = Left(Trend.EndTime, Len(Trend.EndTime) - 4)
                                          Else
                                              datEnd.LocalDate = Trend.EndTime
                                          End If
                                          txtText.Contents = Format((datCursor - datConfigStart) / 3600, "0.0")
                                          ' Set the position
                                          dblPosition = (datCursor - datStart) / (datEnd - datStart)
                                          ' Build the trends text objects name
                                          strTextStart = Trend.Name & "Left"
                                          strTextEnd = Trend.Name & "Right"
                                          txtText.Left = dblPosition * (.Symbols(strTextEnd).Left - .Symbols(strTextStart).Left) + .Symbols(strTextStart).Left
                                          txtText.Top = Trend.Top - Trend.Height + 45
                                          ' Set the color
                                          txtText.LineColor = Trend.LineColor
                                          txtText.BackgroundColor = Application.ActiveDisplay.BackgroundColor
                                          ' Set the name
                                          txtText.Name = Trend.Name & "Cursor" & CurrentCursor
                                      End If
                                  End With

                               

                              And the core of the main sub:

                               

                                 

                              With ThisDisplay
                                          
                                      ' Get the trend format
                                      Set objFormat = Trend.GetFormat
                                      ' If a value, an engineering unit or the tagname is shown, then change the font to Courier
                                      If objFormat.ShowEngUnits = True Or objFormat.ShowTagName = True Or objFormat.ShowValue = True Then
                                          Trend.Font.Size = 10
                                          Trend.Font.Name = "Courier"
                                          ' Set the boolean indicating data on the right hand side to true
                                          bolDataRight = True
                                      Else
                                          ' Set the boolean indicating data on the right hand side to false
                                          bolDataRight = False
                                      End If
                                     
                                     
                                      ' Calculate the width of the longest tagname
                                      intLongestTag = 0
                                      For intLoop = 1 To Trend.PtCount
                                          strTagName = Right(Trend.GetTagName(intLoop), Len(Trend.GetTagName(intLoop)) - InStr(3, Trend.GetTagName(intLoop), "\"))
                                          If Len(strTagName) > intLongestTag Then
                                              intLongestTag = Len(strTagName)
                                          End If
                                      Next
                                     
                                      ' Calculate the corrected trend width
                                      If bolDataRight = False Then
                                          intCorrectedWidth = Trend.Width
                                      Else
                                          intCorrectedWidth = Trend.Width - intLongestTag * 21 - 110
                                      End If
                                     
                                     
                                      ' remove all text, rectangle and line objects starting with the trend name
                                      For intLoop = .Symbols.Count To 1 Step -1
                                          If .Symbols(intLoop).Type = pbSymbolText Or .Symbols(intLoop).Type = pbSymbolRectangle Or .Symbols(intLoop).Type = pbSymbolLine Then
                                              If Left(.Symbols(intLoop).Name, Len(Trend.Name)) = Trend.Name Then
                                                  .Symbols.Remove (intLoop)
                                              End If
                                          End If
                                      Next
                                     
                                      ' Build a rectangle to hide the COTS timescale
                                      Set Rectangle = .Symbols.Add(pbSymbolRectangle)
                                      ' Set the rectangle position
                                      Rectangle.Height = 41
                                      Rectangle.Top = Trend.Top - Trend.Height + 43
                                      Rectangle.Width = intCorrectedWidth - 4
                                      Rectangle.Left = Trend.Left + 2
                                      ' Set the rectangle position
                                      Rectangle.LineColor = -1
                                      Rectangle.FillColor = objFormat.Elements(pbBackGround).Color
                                      ' Set the rectangle name
                                      Rectangle.Name = Trend.Name & "Rectangle"
                                     
                                      ' calculate the total trend time
                                      varTotalTime = (datEnd - datStart) / 3600
                                     
                                      ' create a text object for the right hand time
                                      Set txtNewText = .Symbols.Add(pbSymbolText)
                                      ' Set the text content
                                      txtNewText.Contents = Format(varTotalTime + Offset, "0.0")
                                      ' set the text position
                                      If bolDataRight = True Then
                                          txtNewText.Left = Trend.Left + intCorrectedWidth - 0.5 * txtNewText.Width
                                      Else
                                          txtNewText.Left = Trend.Left + intCorrectedWidth - txtNewText.Width
                                      End If
                                      txtNewText.Top = Trend.Top - Trend.Height + 45
                                      ' Set the text color
                                      txtNewText.LineColor = objFormat.Elements(pbText).Color
                                      txtNewText.BackgroundColor = -1
                                      ' Set the text name
                                      txtNewText.Name = Trend.Name & "Right"
                                     
                                      ' Add a Grid Line for the right hand side, ir required
                                      If bolDataRight = True Then
                                          Set LinNewLine = .Symbols.Add(pbSymbolLine)
                                          ' Set the Line Color
                                          LinNewLine.LineColor = objFormat.Elements(pbHAxis).Color
                                          ' Set the line position
                                          LinNewLine.Width = 0
                                          LinNewLine.Top = Trend.Top - 85
                                          LinNewLine.Height = Trend.Height - 130
                                          LinNewLine.Left = Trend.Left + intCorrectedWidth
                                          'Set the line name
                                          LinNewLine.Name = Trend.Name & "Line" & "Right"
                                      End If
                                     
                                      ' create a text object for the left hand time
                                      Set txtNewText = .Symbols.Add(pbSymbolText)
                                      ' Set the text content
                                      txtNewText.Contents = Format(Offset, "0.0")
                                      ' set the text position
                                      txtNewText.Left = Trend.Left
                                      txtNewText.Top = Trend.Top - Trend.Height + 45
                                      ' Set the text color
                                      txtNewText.LineColor = objFormat.Elements(pbText).Color
                                      txtNewText.BackgroundColor = -1
                                      ' Set the text name
                                      txtNewText.Name = Trend.Name & "Left"
                                     
                                      ' create a text object for the middle
                                      Set txtNewText = .Symbols.Add(pbSymbolText)
                                      ' Set the text content
                                      txtNewText.Contents = Format(Offset + varTotalTime / 2, "0.0")
                                      ' set the text position
                                      txtNewText.Left = Trend.Left + 0.5 * intCorrectedWidth - 0.5 * txtNewText.Width
                                      txtNewText.Top = Trend.Top - Trend.Height + 45
                                      ' Set the text color
                                      txtNewText.LineColor = objFormat.Elements(pbText).Color
                                      txtNewText.BackgroundColor = -1
                                      ' Set the text name
                                      txtNewText.Name = Trend.Name & "Middle"
                                     
                                      ' Add a Grid Line for the Middle
                                      Set LinNewLine = .Symbols.Add(pbSymbolLine)
                                      ' Set the Line Color
                                      LinNewLine.LineColor = objFormat.Elements(pbHAxis).Color
                                      ' Set the line position
                                      LinNewLine.Width = 0
                                      LinNewLine.Top = Trend.Top - 85
                                      LinNewLine.Height = Trend.Height - 130
                                      LinNewLine.Left = Trend.Left + 0.5 * intCorrectedWidth
                                      'Set the line name
                                      LinNewLine.Name = Trend.Name & "Line" & "Middle"
                                 End With

                               

                              Claude Martineau, Global Automation Partners, www.gap5.com

                                • Re: Building a trend showing many variables for a single batch
                                  ldieffenbach

                                  Hi, guys. I'm the Product Manager for PI ProcessBook at OSIsoft. The issue you are discussing here is highly relevant to ongoing discussions around Event Frames and the Next Generation user experience. There has already been discussion of the need to natively support either end-to-end or overlapping "batch" traces in a standard trend implementation. Naturally, this paradise of batch variable plotting will not be available in the near term, but this discussion points to the need to support concepts such as "time into" an event as a relative time expression along with the need to treat each variable as a separate visual presentation.

                                   

                                  If I'm understanding the situation correctly, the time scaling and alignment features of the existing Batch Trend are useful in this scenario, but the flexibility of formatting different variables (traces, not their time or batch ID context) is the limiting factor at this time. Do I have it right?

                                   

                                  Regards,

                                   

                                  Laurie Dieffenbach

                                    • Re: Building a trend showing many variables for a single batch

                                      Hi Laurie...is it not feasible to allow the standard Trend object to reverse the time scale on a relative time format?  I could imagine it is only a couple of lines of code

                                        • Re: Building a trend showing many variables for a single batch
                                          ldieffenbach

                                          We have a saying on the ProcessBook team: "If it was easy, anyone could do it."

                                           

                                          But seriously, just tweaking features in an application like ours isn't terribly interesting unless there is a larger problem to solve, like the one described here. There is always an enormous list of little requests like this and the only way to prioritize them for the team to work on is to provide the context of why they are important and how they will help customers. Even if you could have the scale drawn the way you like, you are still doing an awful lot of work to make the trend do what customers really want. Whilet that's to your advantage , it isn't in the best interests of the majority of our customers.

                                           

                                          A question I had for your workarounds above was this: if you were layering different trend symbols on a display to get the desired result, why couldn't you layer different batch trends? The Batch Group symbol in BatchView allows you to add as many plots as you want and each can be configured separately, I believe.

                                            • Re: Building a trend showing many variables for a single batch
                                              Claude Martineau

                                              Laurie,

                                               

                                              You asked above what was the limiting factor at this point.  The problem is that, with released OSIsoft tools, it is not possible to build a batch trend showing (properly) multiple variables for a single batch.  It is as simple as that.  A batchView trend does a good job at showing a single variable for multiple batches, but not multiple variables for a single batch.  The problems resides in the fact that all traces for a single batch are the same color, which makes it impossible to use if more than 2 or 3 variables are plotted (even if different line styles are used).  Using a regular trend does not work either, because it does not allow a time scale of type "time into trend". 

                                               

                                              We, at GAP, work as consultants in the regulated industry (mostly pharma/biotech) and almost all the customers ask for this feature.  I do not remember a project in the last 4 years where it was not requested at some point by the client.  We always have to create workarounds, but in most cases, even with a lot of VBA code, that does not fulfill 100% of the client requirements.

                                               

                                              You suggested to layer multiple batch trends.  It is simple and quick, but it has many problems:

                                               

                                              1) The scales of the multiple trends will overlap one another

                                               

                                              2) Zooming, adding a cursor, maximizing, changing the time scale would only be applied to the top layer.

                                               

                                              I have to agree with RJK Solutions: All we need to create a nice Batch Trend showing many variables for a single batch, while mainaining full native capability (zooming, maximizing, adding a cursor, ...) is to be able to have the relative time start on the left hand side.  You already have a "time into batch" option in BatchView.  All we need is to be able to use it in a standard trend (where it would be time into trend). 

                                               

                                              Thanks for your interest.

                                               

                                              Claude Martineau, Global Automation Partners, www.gap5.com

                                                • Re: Building a trend showing many variables for a single batch
                                                  ldieffenbach

                                                  Hi, Claude. I spoke with the development folks who work on the batch visualization tools and they acknowledge that this is a limitation in the batch trend (not allowing different colors to be assigned per variable rather than by batch ID). They intend to address it at some point, but the workarounds you all have figured out will be needed until that limitation has been remedied. I don't have any timeline on that right now, since most "batch" efforts are focused on the new event frames architecture at the moment.

                                                    • Re: Building a trend showing many variables for a single batch
                                                      ccoen

                                                      Hi Claude, I'm the Product Manager for Event Frames and Batch products.  We identified this particular request as being the most requested enhancement for BatchView and we have now made it a priority to deliver this feature.  That is, the Batch Trend will be able to support a single batch analysis mode, where the color of the traces are not based on which batch they are from, rather each tag or alias is assigned its own color.  This is our punchlist item 8269osi8, so you can track it on the support site.

                                                       

                                                      As of this time, we are targeting this feature to be delivered with ProcessBook 3.2.  (Yes this will not require a new version of BatchView, you'll just need to upgrade ProcessBook.)

                                                       

                                                      Regards, Chris

                                • Re: Building a trend showing many variables for a single batch
                                  nuser27

                                  Hi Claude,

                                   

                                  I'm trying to follow your code for inserting text name (description) for Trend Cursor. I followed all the steps but am still not be able to run this code succesfully.

                                   

                                  Could you please guide me for doing this or if you have any detailed code, do please send us across.

                                   

                                  Thanking you in advance.

                                   

                                  Regards / Nuser

                                    • Re: Building a trend showing many variables for a single batch
                                      bshang

                                      Hi Nuser,

                                       

                                      Could you post a code sample here with what you have tried? It may provide more details where the issue might be. Do any particular errors appear when you debug and step through the code?

                                        • Re: Building a trend showing many variables for a single batch
                                          nuser27

                                          Hi Barry,

                                           

                                          Thanks for the reply. I'm attaching my code below for your kind perusal.


                                          Sub AddCursors() 'This method adds two cursors to select data in the middle, after this you can move them (you can also add them without using vba)

                                              ' Dim utcStart As Double

                                              ' Dim utcEnd As Double

                                               Dim utcStart(5) As Double

                                               Dim utcEnd(5) As Double

                                               Dim pt As PIPoint

                                               Dim pvs As PIValues

                                               Dim file As Variant
                                              
                                               Dim strCursor As String

                                               Dim textline As String

                                               Dim textline1 As String
                                              
                                               Dim strTextStart As String
                                              
                                               Dim strTextEnd As String
                                              
                                               Dim dblPosition As Integer
                                              
                                               Dim datTest As Date
                                              
                                               Dim datConfigStart As String
                                                  
                                               Dim datStart As Date

                                               Dim datEnd As Date

                                               Dim I As Integer
                                              
                                               Dim iRate As Integer
                                              
                                               iRate = 1

                                               For I = 1 To iRate

                                               ThisDisplay.Trend1.AddCursor
                                              
                                               ThisDisplay.Trend1.CursorUTCTime = (ThisDisplay.Trend1.UTCStartTime + (ThisDisplay.Trend1.UTCEndTime - ThisDisplay.Trend1.UTCStartTime) / 6) + I

                                          '     ThisDisplay.Trend1.AddCursor
                                          '
                                          '     ThisDisplay.Trend1.CursorUTCTime = (ThisDisplay.Trend1.UTCStartTime + (ThisDisplay.Trend1.UTCEndTime - ThisDisplay.Trend1.UTCStartTime) / 6 * 1.5) + I
                                              
                                               If ThisDisplay.Trend1.CursorCount > 0 Then
                                                 ' ThisDisplay.Trend1.CurrentCursor = CurrentCursor                       ' Add a cursor text object

                                                      strCursor = ThisDisplay.Trend1.Name & "Cursor" & CurrentCursor
                                                      Set txtText = ThisDisplay.Symbols.Add(pbSymbolText)
                                                     
                                                      ' Set the value
                                                      ' read the configuration start time
                                                     
                                                      'datConfigStart.LocalDate = Trend1.ConfigStartTime
                                                      datConfigStart = ThisDisplay.Trend1.ConfigStartTime
                                                     
                                                      ' Read the display start time
                                                      'datStart.LocalDate = ThisDisplay.Trend1.StartTime
                                                      datStart = ThisDisplay.Trend1.StartTime
                                                     
                                                      ' read the cursor time
                                                     
                                                      'datCursor.LocalDate = ThisDisplay.Trend1.CursorTime
                                                      datCursor = ThisDisplay.Trend1.CursorTime
                                                     
                                                      ' Read the end time
                                                     
                                                      If Len(ThisDisplay.Trend1.EndTime) >= 19 Then
                                                      'datEnd.LocalDate = Left(ThisDisplay.Trend1.EndTime, Len(ThisDisplay.Trend1.EndTime) - 4)
                                                      datEnd = Left(ThisDisplay.Trend1.EndTime, Len(ThisDisplay.Trend1.EndTime) - 4)
                                                      Else
                                                      'datEnd.LocalDate = ThisDisplay.Trend1.EndTime
                                                      datEnd = ThisDisplay.Trend1.EndTime
                                                      End If
                                                     
                                                      'txtText.Contents = Format((datCursor - datConfigStart) / 3600, "0.0")
                                                      'txtText.Contents = Format((datCursor - 8) / 3600, "0.0")
                                                     
                                                      ' Set the position
                                                     
                                                      'dblPosition = (datCursor - datStart) / (datEnd - datStart)
                                                      dblPosition = 1
                                                     
                                                      ' Build the Trend1s text objects name
                                                     
                                                      strTextStart = ThisDisplay.Trend1.Name & "Left"
                                                     
                                                      strTextEnd = ThisDisplay.Trend1.Name & "Right"
                                                     
                                                      txtText.Left = dblPosition * (ThisDisplay.Symbols(strTextEnd).Left - ThisDisplay.Symbols(strTextStart).Left) + ThisDisplay.Symbols(strTextStart).Left
                                                      txtText.Top = ThisDisplay.Trend1.Top - ThisDisplay.Trend1.Height + 45
                                                     
                                                      ' Set the color
                                                     
                                                      txtText.LineColor = ThisDisplay.Trend1.LineColor
                                                      txtText.BackgroundColor = Application.ActiveDisplay.BackgroundColor
                                                     
                                                      ' Set the name
                                                     
                                                      txtText.Name = ThisDisplay.Trend1.Name & "Cursor" & CurrentCursor
                                                     
                                                      End If

                                                  If ThisDisplay.Trend1.CursorCount < 2 Then 'Checks there is at least 2 cursors (if there are more, it will use the first two)
                                                 
                                                       MsgBox "You need to have 2 cursors on Trend"

                                                       Exit Sub

                                                   End If

                                                   ThisDisplay.Trend1.CurrentCursor = I 'Selects the first cursor
                                                   utcStart(I) = ThisDisplay.Trend1.CursorUTCTime 'And gets its UTC time

                                                   ThisDisplay.Trend1.CurrentCursor = I + 1 'Selects the second cursor
                                                   utcEnd(I) = ThisDisplay.Trend1.CursorUTCTime 'And gets its UTC time

                                              Next I


                                          '     If Trend1.CursorUTCTime < utcStart Then 'Checks which one comes first and saves UTC times on utcStart and utcEnd
                                          '
                                          '         utcEnd = utcStart
                                          '
                                          '         utcStart = Trend1.CursorUTCTime
                                          '
                                          '     Else
                                          '
                                          '         utcEnd = Trend1.CursorUTCTime
                                          '
                                          '     End If
                                          End Sub

                                           

                                          Looking forward for your reply.

                                           

                                          Regards /  Nuser

                                            • Re: Building a trend showing many variables for a single batch
                                              asorokina

                                              Hi Nuser,

                                               

                                              While debugging your code I got an error on this line:

                                              txtText.Name = ThisDisplay.Trend1.Name & "Cursor" & CurrentCursor
                                              

                                               

                                              Since you don't have CurrentCursor variable defined, it has an empty value and causes the exception.

                                               

                                              If I replace the problem line with the line below, the code is executed successfully and Trend Cursor is added to the trend:

                                              txtText.Name = ThisDisplay.Trend1.Name & "Cursor" & ThisDisplay.Trend1.CurrentCursor