Customizing Perspective Table and json scripting help

https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.18/index.html

	def getStyle(row, col):
		if row%2==0:
			subStyle= {"backgroundColor": "white"}
		else:
			subStyle= {"backgroundColor": "blue"}
	
		if col=='Line':
					  subStyle= {"backgroundColor": "green"}
		return subStyle
	
		#"value": value.getValueAt(row, col),"style": getStyle(row, col)    
		#col: value.getValueAt(row, col),
	return [{col: value.getValueAt(row, col)	for col in value.getColumnNames()}	for row in range(value.rowCount)]

This shows my data, but it does not set the colors.

Why would it? You’re never calling getStyle

Sorry, I mean that no variation of trying to put the style into that comprehension is working for me, not that this specific script is not working.

I can iterate through the col and rows correctly, but I don’t understand how the JSON is supposed to look so that I can construct it.

the table expects this format:
{'value': 'your value here', 'style': 'your style here'}

So just return something matching that format from your function and call the function in your list comprehension

1 Like

Imgur

I did something wrong.

value =[{'value': '20', 'style': {"fontSize": 36,"fontWeight": 500,"backgroundColor": "#a0bed8"}}]
return value

I also tried:


	value =[{'value': '20', 'style': 'fontSize": 36,"fontWeight": 500,"backgroundColor": "#a0bed8'}]
	return value

Still style became a column name, and string to the right became the value.
Value became a column name, and 20 became the value in cell. They were in the reverse order though.

I appreciate the help, this is really confusing for me.

you need the column name added to your return

should be like:
value =[{'columnNameHere': {'value': '20', 'style': {'fontSize': 36,'fontWeight': 500,'backgroundColor': '#a0bed8'}}}]

1 Like
value =[{value.getColumnName(0):{'value': '20', 'style': 'fontSize": 36,"fontWeight": 500,"backgroundColor": "#a0bed8'}}]
return value

Table is empty. No error though, and data has a 0, which is named the column name, which has a value and a style.

Getting a component error though.

My idea is if I can get this simple format to work, then I can write code to write the other.
I think that until I understand the json format, I won’t understand how the rest works.

I didn’t realize on my last reply, but your style property is still incorrect. It needs to be wrapped in a dictionary:
{'value': '20', 'style: {'fontSize': 36}}

You also have a mix of single quotes and double quotes

1 Like

value =[{value.getColumnName(0):{'value': '20', 'style': {'fontSize": 36,"fontWeight": 500,"backgroundColor": "#a0bed8'}}}]

This is correct formatting?
I have a component error I think because I have created only one column.

hint hint hint

3 Likes
styleBluish 	= {'fontSize': 36,'fontWeight': 500,'backgroundColor': '#a0bed8'}
value = [{value.getColumnName(col):{'value': value.getValueAt(row,col), 'style': styleBluish} for col in  range(value.getColumnCount())} for row in range(value.getRowCount())]
		
return value

I got them to all show up.

:clap:
Nice!

1 Like
def getStyle(row, col):
			if row%2==0:
				subStyle= {'fontSize': 36,'fontWeight': 500,'backgroundColor': '#ffffff', 'borderStyle':'ridge'}
			else:
				subStyle= {'fontSize': 36,'fontWeight': 500,'backgroundColor': '#a0bed8', 'borderStyle':'ridge'}
		
			if value.getColumnName(col)=='Line':
						  subStyle= {'fontSize': 36,'fontWeight': 500,'backgroundColor': 'green', 'borderStyle':'ridge'}
			return subStyle

	
	value = [{value.getColumnName(col):{'value': value.getValueAt(row,col), 'style': getStyle(row, col) } for col in  range(value.getColumnCount())} for row in range(value.getRowCount())]
		
	return value

I got the function to call as well for the style now.

Whitespace is your friend for readability :slight_smile:

	def getStyle(row, col):
		baseStyle = {
			'fontSize': 36,
			'fontWeight': 500,
			'borderStyle': 'ridge' 
		}
		if value.getColumnName(col)=='Line':
			return dict(backgroundColor="green", **baseStyle)

		return dict(
			backgroundColor="#a0bed8" if row % 2 else "#ffffff", 
			**baseStyle
		)

	return [
		{
			value.getColumnName(col): {
				'value': value.getValueAt(row,col),
				'style': getStyle(row, col)
			}
			for col in range(value.getColumnCount())
		}
		for row in range(value.getRowCount())
	]
4 Likes

I struggle to comprehend list comprehensions when they are not in a single line.
The other ways is easier for me to read.
I don’t understand some of the changes too.

I was so happy 6 minutes ago. Also, I like to learn the things new to me too though.

Regarding how to see .getColumnNames() as a possiblity, just run a dir or @pturmel 's inspect function on a dataset object and you would see all functions/attributes associated with the object type.

1 Like

Also mentioned in the manual:
https://docs.inductiveautomation.com/display/DOC81/Datasets#Datasets-AccessingDatainaDataset

2 Likes

Its a matter of writing DRY code.

In your original function you define three dictionaries that are basically the same. So @PGriffith factored out the common things to a single dictionary baseStyle

Then he is using the dictionary constructor to return a new dictionary combining the background color key into the base style dictionary.

The ** unpacks the baseStyle dictionary to be used as keyword arguments in the constructor.

So dict(backgroundColor="green", **baseStyle) essentially becomes

dict(backgroundColor="green",fontSize = 36, fontWeight=500, borderStyle = "ridge")

He also rearranged the if statements to short circuit (return early) if needed. For instance if the column name is Line it doesn’t matter if it’s an even or odd row, just return the “green” style.

4 Likes

That's fair - obviously it's your code, so write it however you can read it now (and in six months :slight_smile:).

Other than the whitespace, I really only did three things to your getStyle function.
First, I extracted the common style settings; that prevents the duplication, which, again, generally makes things easier to read and maintain down the road. Now you don't have to carefully read each condition to see if any of the other style properties are changing.
That's this part:

		baseStyle = {
			'fontSize': 36,
			'fontWeight': 500,
			'borderStyle': 'ridge' 
		}

Then, I put the Line branch first, and made it an early return. That's the same functionality as your existing code, just expressed in a different way.
return dict(backgroundColor="green", **baseStyle)
This line uses the Python builtin dict to create a new dictionary. dict allows you to provide keyword arguments to construct a dictionary; so I'm passing in backgroundColor as a keyword argument, and then unpacking the baseStyle dictionary using **.

And finally, I changed the final return to use a ternary expression rather than a full if statement, because there's no difference between the two branches other than the color chosen:

		return dict(
			backgroundColor="#a0bed8" if row % 2 else "#ffffff", 
			**baseStyle
		)

This is also known as a conditional expression.

5 Likes