How to check for NoneType in a Change Script


I was wondering how to avoid the error above when the props.series[0].data Dataset is empty. Any help would be appreciated!

<
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
if self.props.series[0].data != None:
if previousValue < currentValue:
self.props.plots[0].axes[0].min = CustomTrends.getMinimum(self.props.series[0].data)
self.props.plots[0].axes[0].max = CustomTrends.getMaximum(self.props.series[0].data)*1.06

Try
if self.props.series[0].data is not None:


Tip: please post code rather than pictures of code and format it using the </> button. It means people can copy the code to test it and paste it into their answers to edit it rather than typing the whole lot out again. Post a screengrab as well if it adds some important details.

Thank you, I edited my post to include the code

You should be able to check it simply by using

if self.props.series[0].data:
    ...
2 Likes

Even with either 'if self.props.series[0].data: ' or 'if self.props.series[0].data is not None: ' I am getting the same error on line 5 when the DataSet is empty.

Capture

A dataset with no rows is not the same thing as None.
Do this instead

if self.props.series[0].data.getRowCount():

It produces this error on line 2 now.
Error running property change script on TimeSeriesChart.props.series[0].data: Traceback (most recent call last): File "function:valueChanged", line 2, in valueChanged AttributeError: 'com.inductiveautomation.perspective.gateway.script' object has no attribute 'getRowCount'
Code:

def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if self.props.series[0].data.getRowCount():
		if previousValue < currentValue:
			self.props.plots[0].axes[0].min = CustomTrends.getMinimum(self.props.series[0].data)
			self.props.plots[0].axes[0].max = CustomTrends.getMaximum(self.props.series[0].data) * 1.06

... using the </> button to format the code. Select the code and press the button.

what is the result of doing

system.perspective.print(type(self.props.series[0].data))

Better might be to check for both None Type and an Empty Data set.

if self.props.seris[0].data is not None and self.props.series[0].data.rowCount:

previousValue and currentValue are QualifiedValue objects, so you need to get the value out of them.

previousVaue < currentValue will probably always evaluate as false.

I would probably do something like:

def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if all([previousValue, currentValue,self.props.series[0].data,self.props.series[0].data.rowCount, previousValue.value < currentValue.value]):
		self.props.plots[0].axes[0].min = CustomTrends.getMinimum(self.props.series[0].data)
		self.props.plots[0].axes[0].max = CustomTrends.getMaximum(self.props.series[0].data) * 1.06

EDIT: Code does not work when tested. Mainly because you can't compare datasets with <.

This is the result:
16:13:53.939 [Browser Thread: 54158] INFO Perspective.Designer.Workspace - class com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper$ArrayWrapper

Okay, lets back up a few steps and make sure that we understand everything.

  1. The error that you were originally encountering on Line 5 was saying that * operator is not supported on NoneType, in the context of your code, this means that CustomTrends.getMaximum() returned a NoneType object. Can you provide the code for this method?

  2. If I run system.perspective.print(type(self.props.series[0].data)) on a this, while it contains a dataset object, the output I see in the console is

class com.inductiveautomation.ignition.common.JsonDataset

So, either you're object isn't what you thought it is, or your code doesn't match what @dkhayes117 provided.

Assuming that the functions CustomTrends.getMinimum() and CustomTrends.getMaximum() do something like:

def getMinimum(ds):
    #ds is expected to be a Dataset type object
    return min(ds.getColumnAsList(ds.getColumnIndex('column')))

def getMaximum(ds):
    #ds is expected to be a Dataset type object
    return max(ds.getColumnAsList(ds.getColumnIndex('column')))

Then the following code properly checks that this is a true valueChange and that the dataset is not empty.

def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if all([previousValue, currentValue,currentValue.value,currentValue.value.rowCount]):
		self.props.plots[0].axes[0].min = CustomTrends.getMinimum(currentValue.value)
		self.props.plots[0].axes[0].max = CustomTrends.getMaximum(currentValue.value) * 1.06

However, why not just use expression bindings here:

coalesce(min({this.props.series[0].data},'ColumnName'),100)
coalesce(max({this.props.series[0].data},'ColumnName'),100) * 1.06

These expressions will return the min/max if there is data, and the provided default value otherwise.

My .getMinimum and getMaximum functions were returning null for empty datasets. Also the code you added for checking was helpful.

1 Like