How to get Python data set into a Dataset Memory Tag?

How do you get a system.tag.browse results to a python dataset then get that into a Dataset Memory Tag? I get stuck with the data.append() when trying to build a dataset from the tag.browse(). I looked at the append.toDataset(), can’t get my head around this…

One way you could do it is by building a list out of the returned data by appending the values from each result returned from your browse to an empty list (in this case I used listHolder). Specify the headers of the result data in another list, and using system.dataset.toDataSet you can convert all of that into a dataset. Once you have that, you can write the dataset to a tag! Here, I only went to one level of browse, but you could always do something very similar for a multi-level browse.

I recommend taking a look at the Ignition documentation for dictionaries and lists, as it goes into more detail on this style of manipulating data.

https://docs.inductiveautomation.com/display/DOC80/Dictionaries

https://docs.inductiveautomation.com/display/DOC80/Lists+and+Tuples

results = system.tag.browse(path = '[default]')
listHolder=[]
for result in results.getResults():
	listHolder.append(result.values())


headers=["fullPath","hasChildren","name","tagType"]

dataSet=system.dataset.toDataSet(headers,listHolder)
system.tag.write("[default]Test Tag",dataSet)

Thank you @nathanielbrown for the prompt reply! That is great, simple… I get crossed up with the .toDataSet, .appendDataset, .getComponent, .write and .writeBlock…

doesn’t ‘result’ contain the correct formatted data without using .value()? Because, this dataset will be only two columns where I have figured out I can get a string using result[‘fullPath’] and result[‘name’]…

@hwbrill each “result” is a dictionary containing key-value pairs, where the keys are those I specified in the headers code. If you only want those two columns, you could just get the string values using:

listHolder.append([str(result['fullPath']),str(result['name'])])

Then, just make the headers those two columns.

1 Like

If you don’t want to change the content, just use the first form of system.util.toDataSet().

Thank you… so, when I click the function, it takes me to the system.dataset.toDataSet doc in the manual. When I look for the Scripting Function Index, I don’t see it… Am I reading into it too much? This is where I am having a problem with following what functions are the best solution…

Yes!
system.util.jsonDecode(str(system.tag.browse(path,filter)))

That function has multiple formats. The first one in the manual shows it taking a single, solitary argument: a PyDataset to be converted into a plain Dataset.

now I am having trouble figuring out how to iterate through a passed PyDataset… The following keeps printing out the row as one col in def getFPlist():, no matter what I do…

# Dataset memory tag configuration properties
dataType='DataSet'
tagType='AtomicTag'
valueSource='memory'
# Dataset memory tag configuration list
config={'valueSource':valueSource,'dataType':dataType,'name':'FP List','tagType':tagType}

data=[]

def getFPlist(fpList):
    for r in fpList:
        for c in fpList:
            print fpList[r][c]
    return

def browseTags(path,filter):

    results=system.tag.browse(path,filter)
    
    for result in results.getResults():
        if result['hasChildren']==True and str(result['tagType'])!='Folder':
            fullPath=str(result['fullPath'])
            splitPath=fullPath.split('/')
            c_name=splitPath[1]
            desk_name=splitPath[2]
            fp_name=splitPath[3]
            data.append([c_name,desk_name,fp_name])
            print c_name,desk_name,fp_name
        elif str(result['tagType'])=='Folder':
            browseTags(str(result['fullPath']),filter)
    system.tag.configure('Schafer',[config],'o')
    
    header=['c_name','desk_name','fp_name']
    
    table=system.dataset.toDataSet(header,data)
#    system.tag.write('Schafer/FP List',table)
    fpList=system.dataset.toPyDataSet(table)

browseTags('Schafer',{})
getFPlist(fpList)

the markdown didn’t indent the code in the getFPlist() function but it runs in the python console…

Don't use plain markdown. This forum is built on discourse. Use ``` markers above and below your code.

1 Like

You probably want

def getFPlist(fpList):
    for r in fpList:
        for c in r:
            print(c)
    return

Your code wouldn’t compile as posted, but I assume you simply chopped it down incorrectly.

I am attempting to create a "Save Configuration" feature for my HMI and this topic seems similar to what I am attempting to accomplish so I thought I would try posing here first.

The purpose of my feature is to save the known good values of a few tags that are being used to configure my application to a .csv file so that if the configuration ever becomes corrupted by the user, they can restore the original working values.

The tag data needs to be stored in a .csv file (not a database) so that it can be easily copied to another system. The filename for this config file is "DAS Config.csv".

I have a test script project that is 90% complete that saves the data is able to successfully read it back into a dataSet. However, I cannot figure out how to put the dataSet back into the tags. I need help figuring out what I am doing wrong.

I attached a copy of my test script along with the export of the tags I am backing up. I also included an example of the DAS Config.csv file it creates.

DAS_Config.csv (2.2 KB)
tags.json (10.3 KB)
Test Code.txt (2.7 KB)

Post your code as formatted text, see Wiki - how to post code on this forum. It lets people quickly browse your code and configurations without having to download a file. This also helps with getting more people to answer questions.

Moving on to your actual attempt:

When importing, don't convert the csv into a dataset, just pull the raw values and pass them to system.tag.writeBlocking as the list of values for the list of tags. Trim down the list of values to match the number of tags you have or you'll get an error.

And for personal recommendations:

First off, don't trim the CSV that system.dataset.toCSV gives you, if you keep it in the default 'Dataset as a CSV' style it gives you, you can then call system.dataset.fromCSV() on the file contents to have it converted into a dataset for you when importing it. Much simpler.

I would also include the source tag path in the dataset that you are exporting to a CSV. How else are you supposed to be able to know what value to stick where? If you do that, you can loop through the dataset to create the list of tags to write to and their value.

One minor thing, don't import time or datetime, use Ignition's built in system.date functions.

Also imports should always go at the top of the project library above any other definitions or calls. If these methods are not in a project library they should be.

Cleaned Example
logger = system.util.getLogger("DAS.Config")

CONFIG_TAG_PATHS = [
	"[Beckhoff CTU]Devices/BOP Pressure",
	"[Beckhoff CTU]Devices/Chain Front Stretch",
	"[Beckhoff CTU]Devices/Casing Pressure"
]
CONFIG_HEADERS = [
	'tagPath',
	'value'
]

def exportDASConfigCSV(filePath=None):
	""" Exports a CSV dataset of the DAS configuration tags to the given filepath """
	
	if not filePath:
		filePath = "C:/CSV Files/%s/DAS_Config.csv" % system.date.format(system.date.now(), "yyyy-MM-ddTHHmmss")

	tagValues = [qv.value for qv in system.tag.readBlocking(CONFIG_TAG_PATHS)]

	configValueDataset = system.dataset.toDataSet(
		CONFIG_HEADERS,
		[[value] for value in tagValues]
	)

	system.file.writeFile(filePath, system.dataset.toCSV(configValueDataset), append=0)

	return


def importConfigCSV(filePath):
	""" Import DAS config CSV file and write values to tags """
	
	if not system.file.fileExists(filePath):
		logger.warnf("File '%s' does not exist or the system does not have permission to access it", filePath)
		return 0

	configFileData = system.file.readFileAsString(filePath)
	
	configData = system.dataset.toPyDataSet(
		system.dataset.fromCSV(configFileData))
	tagPaths, values = [], []
	
	for row in configData:
		tagPaths.append(row['tagPath'])
		values.append([row['value']])

	system.tag.writeBlocking(tagPaths, values)

	return 1
1 Like

Thanks Ryan! I will test your suggestions on my tags and modify as needed.
BTW, I really appreciate the example code!
I typically put all my imports at the top, but my example was just temporary test code I was experimenting with in the script tool so things are not where they should be.