Perspective Ad Hoc Charting and table display of historic tag collection

I want to select multiple tags from a list of tags and display their tag history at runtime. On one screen I want to display the results to a Perspective Table control. On the other screen I want to display it to an XY Chart.

I have been able to get static versions of this functionality working but I’m not sure how to dynamically bind to tags at runtime.

I understand that I can export my bindings as json but I don’t know what mechanism I can use to send a json binding to a control. I suspect the answer is to use messaging or maybe json to send the bindings to the Perspective control at runtime but I don’t understand how to do that.

Can someone point me in the right direction?

I just had a discussion regarding dynamic binding with some devs recently, and… you can’t. And… you shouldn’t. Bindings are meant to be static/unchanging/final. The underlying data the bindings would represent can and should be malleable, but the definition of a binding should never change.

Best way to go about what you’re doing: build a data structure which allows for defining or toggling data values.

For example, try:

  1. Placing a “refresh” button into your View, along with some Toggle Switches.
  2. Allow the Toggle Switches to define which Tags are displayed in the graph.
  3. When your refresh button is clicked, refer to the Toggle Switches to determine which tags are included in a tag read request.
  4. Build a dataset from the data.
  5. Use system.perspective.sendMessage() to broadcast this dataset.
  6. Place a listener on the Chart/Table which determines how the dataset is digested.

In this way your bindings do not change, but the underlying data built from their information can be changed.

1 Like

Thank you. That should get me going in the right direction. I at least know which things I need to understand before I can execute this.

Do you have an example of how to set this up? I was going over the message documentation because I suspected that was part of the answer but it looked like it was still a work in progress (the documentation).

I can throw something together. Give me a little bit and I’ll post an example View in here.

Excellent. Thank you

Okay, a few caveats:

  1. you’ll need to have today’s build deployed.
  2. My datasets are pretty simplistic.
  3. There’s got to be a better way to do this, but I was just trying to get you something usable…
  4. There might be a bug when attempting to create a new Series in the XY Chart - we’re investigating.

demotags.json (2.4 KB)
TabulaRasa.zip (10.8 KB)

Steps:
Import the tags from demotags.json
Extract the View from the .zip folder and place it in your Project.
You’ll want to configure a Page Configuration for the new View.
Navigate to the new Page.
Toggling the Toggle Switches and then pressing the button will result in one or the other or both (BUT NOT NONE - I was in a hurry) being rendered in the Chart.

Notes:

  • Instead of Toggle Switches, a multi-select Dropdown would probably be better for determining which tags are displayed.
  • To examine the bulk of the logic, right-click the Refresh button and select “Configure Events”.
  • tag.split('/')[-1] is getting the last token of the split.
  • system.tag.readBlocking was used instead of readAsync because I didn’t want to get into using a callback function.
  • messageType must match exactly the name of the listener configured on the XYChart.
  • To examine the listener, right-click the Chart and select “Configure Scripts”, then select “XYDATACHANNEL”.
  • The self.props.series[i] properties must all be configured in order for a series to render.

Thank you for your help.

I installed the latest daily on my testing station and tried to import this project file. It’s locking up and the objects don’t appear to be getting imported. There are other projects on this gateway but none of them are important. It’s just a testing station but I wanted to give details of my environment in case they matter (probably not).

I thought maybe the problem was how I created the project so I referenced my global project from the project I’m importing into and tried again. It locked up again.

I created the project from the designer launcher and tried importing the .zip file into it from within the designer. Before that I tried to import the .zip file from the configuration webpage as a new project and that threw an error saying the gateway was unable to import the file.

I’m also interested in anything you can tell me about using the expression definitions on the historic section of the XYChart. I was trying to use the expressions but wasn’t having a lot of success yesterday. I did see that the documentation is actively being updated as of yesterday so I’m sure this will become easier to figure out soon. You guys are really on top of things. It’s a big job.

Let me know if you need any details from my station that is crashing when I try to import this project.

It’s a windows station.

It looks like I'm actually dealing with this problem

Probably not a problem with the project files or import process.

@cmallonee
Hi
I wonder if the import of the project has been fixed?
I am looking for easiest way to display tabulated data in the perspective table
Regards

The only reported bug I see in this thread is from 8.0.0, so... I am pretty sure it's been fixed.

1 Like

@cmallone well impressed by your reply on Sunday :slight_smile:

Thanks. I try to watch for activity on here as I'm available.

1 Like

#refresh button
def runAction(self, event):
tag_paths =
if self.getSibling('ToggleSwitch').props.selected:
tag_paths.append('[default]Experimentation/Arrays/MockOne')
if self.getSibling('ToggleSwitch_0').props.selected:
tag_paths.append('[default]Experimentation/Arrays/MockTwo')
data_dict = dict()
data_dict['tags'] =
for tag in tag_paths:
data_dict['tags'].append(tag.split('/')[-1])
returned_data = system.tag.readBlocking(tagPaths=tag_paths)
outgoing =
for i in range(len(returned_data)):
tag_value = returned_data[i].value
for point in tag_value:
outgoing.append(point)
data_dict['data'] = outgoing
system.perspective.sendMessage(messageType='XYDATACHANNEL',payload=data_dict,scope='view')

XY chart message handler

def onMessageReceived(self, payload):
tags = payload['tags']
data = payload['data']
self.props.dataSources.tagData = data
for i in range(len(tags)):
self.props.series[i].data.source = 'tagData'
self.props.series[i].label.text = tags[i]
self.props.series[i].name = tags[i]
self.props.series[i].data.x = 't_stamp'
self.props.series[i].data.y = tags[i]+'_output_temp'
self.props.series[i].xAxis = 'time'
self.props.series[i].yAxis = 'output temp'

Code above is from your quick demo project (it shows refresh button and XY chart message handler) which i believe is relevant for my task to display tabulated data of the historic values of the selected tag in the tag browse tree.

From the high point of view the solution is really simple :slight_smile: - after selecting the tags, reading their historic values i need to use send a message using message handler "system.perspective.sendMessage". This message is then consumed by the table and displayed.
But as always the devil is in the details - any chance you comment on any of the following please:

  1. is there a message or function to read historic tag of the tag for the specified period? You demo was using memory tag with 11 values
  2. any known limits on the size of the payload passed to the message handler ?

If anybody else would like to comment you are very welcome.

I can't speak to the specifics of the Demo project because I didn't build it.

Yes. By default, the websocket is capped at something like 2mb. You can adjust this by editing the Gateway configuration file.

1 Like

thank you for reply. I like perspective a lot but sometimes i am surprised how different it is to Vision module which is expected as its different technology.

From the high point of view the solution is really simple :slight_smile: - after selecting the tags, reading their historic values i need to use send a message using message handler

I am trying the simplest possible solution so i wonder if message handler gives any benefits at all if the button is on the same screen where display table is?

I am just about to use the example from docs and bind the datasets to the data property of the table.
# The following example will return a dataset with one row detailing maximum value of a Tag named 'Sine' for the past 30 minutes.

endTime = system.date.now()

startTime = system.date.addMinutes(endTime, - 30 )

dataSet = system.tag.queryTagHistory(paths = [ 'Sine' ], startDate = startTime, endDate = endTime, returnSize = 1 , aggregationMode = "Maximum" , returnFormat = 'Wide' )

The main benefit to message handlers is their resilience during the life-cycle of a project. Bindings are hard-coded against some path (even if relative vs absolute), and so structural changes to a View can result in broken bindings over time. Message Handlers are structure-agnostic, though you do have a hard-coded message type (which is basically a key) that must remain unchanged; if you do change it, you have to search for anything which might have used the original message type and update the usages to use the new message type.

Unfortunately, there's no bi-directional aspect to Message Handlers for this very same reason; the ephemeral one-way "broadcast" which doesn't rely on any sort of path also means there's no way to feed data back to the broadcaster.

An additional benefit is it's very easy to configure multiple listeners to hear a singular broadcast event.

1 Like

fantastic answer which i will keep in mind.
Sadly i cannot grant you solution as i re-heated old topic :slight_smile:

1 Like

Bindings are meant to be static/unchanging/final. The underlying data the bindings would represent can and should be malleable, but the definition of a binding should never change.

i hope you don't mind the question but i need to be really clear on the basics.
Objects like power charts can be populated with the data via scripting and can be pulling data from various places but if binding is used it has to be created manually and if its selected to Direct it cannot change to Expression via scripting ?
Please correct me if you can.

Yes, but when you do it via scripting, you are only updating the data every time the script is invoked. Bindings update realtime.

Correct, you may not use scripting to manipulate a binding after-the-fact. If you ever think you might want to swap to an Expression configuration in the future, just do it now. The Expression structure allows you to build the Tag Path dynamically, which is very likely what you're looking for anyway.

1 Like

thanks for reply
can you please confirm if the binding update cycle is configurable in the project settings or there is no user control as bindings update when the values change?