Indirect Pen Tag Path

I have an easy chart with pens configured to use a MySQL database. However, this project will also be deployed on an Edge panel and use the Edge Historian for trending at the local panel.

What I've run into is that I cannot rename the Edge Historian history provider, so I need to be able to dynamically change the tag path based on where the project is deployed.

My first thought is a cell update binding on the [tag] pens dataset, but performance with that is yet to be seen. My next thought was an indirect tag path in the data section of the pen configuration. Wondering if that's possible at all (guessing not) and what sort of performance I can expect with the cell update bindings as the pen sets get larger.

You cannot use the pens dataset with EasyChart at all on Edge, as DB pens require a DB. You need to configure the tagPens dataset for charting from the historian.

You may be able to script the population of the two datasets based on the environment.

Yes, I am using the tag pens dataset

Then just script the content of .tagPens based on the environment.

It's a pretty large dataset to script... not sure if I want to start down that route (yet).

Wondering if you have any opinions on the cell update bindings.

Not a fan of cell update bindings.

Consider making custom dataset properties for the two environments and storing the correct content in each. Then bind to .tagPens an expression of the form:

if({some.edge.boolean}, {path.to.edge.pens}, {path.to.nonEdge.pens})

I see. Just "big" datasets that exist on the page and the only expression is figuring out which to use. Seems like alot of work when the only thing that changes is the data source (i.e. [MySQL/ignition-desktop-av4v6h5:area_01] > [Edge Historian/area_01]) for each tag pen. I guess the second dataset could be scripted and use a loop/replace. Now I wish easy charts could have custom properties...

Just put the custom props on the container in which the EasyChart sits.

Ya, I just like to put component-specific custom props on the component themselves if possible.

So I've got the two custom dataset properties made. One I populated just using a temporary binding to the existing tag pens dataset on the easy chart. Now, I'm trying to use an update script on that dataset to modify the TAG_PATH column for each row and just not sure how to do that second part.

I know datasets are immutable so I have to somehow use the existing dataset to create a new one and then write that to the prop, just unfamiliar with that process.

Don't script it. Copy the dataset to the clipboard in the dataset editor popup. Fix up in your favorite text editor. Paste into the other dataset.

I'm going to be doing this quite a bit and would like it to update automatically if pens area added in the future.

You can't, using the if() expression binding (nor a cell update binding, fwiw). That would make a circular reference and crash/freeze your client.

You may need to script the entire thing.

Where's the circular reference? That binding I was talking about was just to get the rows and columns from the existing easy chart without doing it manually. The binding no longer exists. This custom dataset would end up being the driving data source for the tag pens.

The if() just decides which dataset to use; the primary dataset or the 'derived' dataset. I just want to script the creation of the derived dataset so it updates if the primary dataset is changed.

Ah, ok. Then your update script would loop through the source dataset, using a string replace operation to produce a new list of rows, then assemble with system.dataset.toDataSet().

Getting a toDataSet(): 1st arg can't be coerced to org.python.core.PySequence error when I try and convert the lists to a dataset. I used data.getColumnNames()

[NAME, TAG_PATH, AGGREGATION_MODE, AXIS, SUBPLOT, ENABLED, COLOR, DASH_PATTERN, RENDER_STYLE, LINE_WEIGHT, SHAPE, FILL_SHAPE, LABELS, GROUP_NAME, DIGITAL, OVERRIDE_AUTOCOLOR, HIDDEN, USER_SELECTABLE, SORT_ORDER, USER_REMOVABLE]


Fixed by adding [] around the headers, but now it says row 0 has a different number of columns, which it doesn't... it's literally made from the same dataset...

penData_master = system.dataset.toPyDataSet(event.source.master)


headers = event.source.master.getColumnNames()
penData_edge = []

TAG_PATH_index = event.source.master.getColumnIndex('TAG_PATH')

#print headers
#print len(headers)
for row in penData_master:
	new_row = list(row)
	
	new_row[TAG_PATH_index] = row['TAG_PATH'].replace('[MySQL/ignition-desktop-av4v6h5:area_01]',event.source.parent.hist_root_path)
	
	penData_edge.append(new_row)
	
	#print new_row
	#print len(new_row)

newData = system.dataset.toDataSet([headers], penData_edge)

len() prints show header and rows are all 20 elements in length. Probably because of the [headers]. But without the wrapping [] I'm back where I started.

Things just keep getting weirder... so I transposed the headers to a list of lists and no longer get any errors, but now each header is a list...

newData = system.dataset.toDataSet([[str(col)] for col in headers], penData_edge)

Original dataset headers:
image
New dataset headers:
image

very confused

Finally got it.

So, event.source.master.getColumnNames() returns strings in that u'STRING' format, which system.dataset.toDataSet(headers, data) does not like in the headers list.

penData_master = system.dataset.toPyDataSet(event.source.master)


headers = event.source.master.getColumnNames()
headers = [str(col) for col in headers]
penData_edge = []

TAG_PATH_index = event.source.master.getColumnIndex('TAG_PATH')

#print headers
#print len(headers)
for row in penData_master:
	new_row = list(row)
	
	new_row[TAG_PATH_index] = row['TAG_PATH'].replace('[MySQL/ignition-desktop-av4v6h5:area_01]',event.source.parent.hist_root_path)
	
	penData_edge.append(new_row)
	
	#print new_row
	#print len(new_row)

event.source.edge = system.dataset.toDataSet(headers, penData_edge)

It is not the unicode, but that it is a java list, not a python list. You can just use:

headers = list(event.source.master.getColumnNames())
1 Like

Thanks

So my motivation for this was because I couldn't find a way to rename the Edge Historian. This is working just fine, but I've now found that I can rename the Edge Historian.

Now the question is... do I undo it all or just leave it because it works... :expressionless:

I'm thinking I'll probably just leave it because the path would still have to change either way.