Change table columns color depending on cell value

Hi all,

I need to change the color of each cell from each column depending on their value.

image

in this image I'm changing the "Coarse" and "Fine" column>style>color to red, but I need to add a conditional to be red or black depending on the cell value....

I have the conditions but don't know how to apply it on the color binding expression because I don't know how to refer the cell value or the column value

In this case on "Coarse" the "A" should be Black and the "A5" red..... and for Fine "L16" should be Black and the others red....

You need to run a script transform on the document returned by your query.

Start with this from the documentation and then ask further questions when you get stuck.

https://docs.inductiveautomation.com/display/DOC81/Perspective+-+Table#PerspectiveTable-Example1:StylingRowsBasedonValue-JSONData

yeah, but I dont want to change the row, I want to change each cell of a column.

I have a table with 15 columns, and I'm not sure if it's a good idea to add 15 new columns (1 color for each column) ... and even if I do it, in which prop do I need to add this color?

the table have columns prop in which you can configure each column, and when rendered it as a view you can pass the "value" of each cell for that column to the rendered view, but what about using this value in the columns>[0]>style>color, is it possible? because I tried to point to the same column and add a transform for my color, but it colored all the column depending on the first row value, not for each one.

if the first one should be black... all column is black
image

and if the first one should be red, all column is red
image

I mean each column has condition... for Coarse column it is red when the cell is different from "A" or "B", and for Fine column, it is red when it is different from "R16" or "L16".

I could render every column and just have a view that show the value and change the color, but I'm not sure if it's going to work fine because almost every cell will be rendered as view....

No you don't. You want to change each row and then you want to change one or more columns within that row. The linked article is applying the style to the whole row. You need to examine each cell and apply formatting to that cell. It will be something this code which you can test in the Script Console. When you have it working to your satisfaction use it in a transform applied to the data binding - not the column or row.

value = [
  {
    "Date": "22/24/2022",
    "Time": "12 PM",
    "Coarse": "A"
  },
  {
    "Date": "22/24/2022",
    "Time": "11 AM",
    "Coarse": "A5"
  },
  {
    "Date": "22/24/2022",
    "Time": "10 AM",
    "Coarse": "A5"
  }
]

print("value input:")	# The unmodified data.
print(value)
print("--------------------------------------------------------------------")

def styleApply(val, pattern):
	import re

	if val != "":
		x = re.findall(pattern, str(val))
		if not x:
			return {"color": "--error"}
		else:
			return {"color": "--neutral-90"}
	else:
		return ""
		
def main(value):    # Main routine
	output_json = []
	for row in value:
		row_object = row           # Start with the existing row dictionary.
		print(row)

		val = row['Coarse']
		row_object['Coarse'] = {"value": val, "style": styleApply("&([A-D]|[1-5])$", val)}

#	    # Add in other columns to be modified here.

		output_json.append(row_object)
	return output_json
	
print(main(value))

Table cell formatting
The result.

Watch the indents when you paste into the Script Console. Tabs get converted sometimes.

Note also my use of Perspective Theme Colors which I highly recommend.
https://docs.inductiveautomation.com/display/DOC81/Perspective+Built-In+Themes#PerspectiveBuiltInThemes-Built-inThemeColors

1 Like

hi @Transistor I didnt see the reply until now, and after a lot of trying I Finnaly did it! :laughing:

What I didint understand was that adding

"style": {"color": color}

to every column value on each row, it will automatically modify the color of each cell for each column.

so, your explanation really helped me, thanks!!

image

PD: I use almost everytime datasets on the props.data of a table instead of list of dict, so I have some problems because I tried to do all this working with datasets. At the end I transform my dataset to a List of Dict like your example and worked fine to me.

If you set the binding to return a DOCUMENT rather than a DATASET it might simplify things.

It looks like you're in business.

Tangent, but regex is a big (and relatively slow) hammer for a nail this simple. Keep in mind this check is being run a lot, depending on how large your dataset is, and it may be worth 'hand writing' this check out long form for better performance.

Fair enough. I copied it from the original post screen grab.

1 Like

the thing is that I use scripts to exec SP more than sql binding, so in these cases I use expressions like

runScript("app.mymodule.my_function", 0, myParams)

so in these cases, I cannot change it to document, but I have another script to transform it in json :laughing:

About the Regex, I used it because I'm migrating and old .net app to perspective so in this case they used this regex to validate the values so, I just copy it :laughing: I dont know what its good or not, only have those expressions so I used them :stuck_out_tongue_closed_eyes:

But what could be better than regex in cases like this in which only values like "A", "B", "C", D", "1", "2", "3", "4", "5" are good??

1 Like
allowedChars = {"A", "B", "C", "D", "1", "2", "3", "4", "5"}

if all(char in allowedChars for char in string):
	#do something

A set will be O(1) lookup for purposes of contains, and the all builtin will be 'lazy' and short-circuit as soon as a match is not found.

2 Likes

I will consider this approach in this case because they are just few cases.

but what do you think about this other example?

"^([RL][1-9]|[RL]1[0-6]|[N])$"

I mean, in this case they are 33 cases... Its my first time working with regular expressions, I didnt know it until the last week, and as I said I didnt write the expressions, I just copied them and find how to use them on python... the question is in which cases do you recommend use regex?

Regex is absolutely the right choice in lots of cases; I'm certainly not saying to never use regex. But it is almost always good to use it deliberately. In particular, if you are using regex, do your best to "pre-compile" your patterns as much as possible. Using re.compile will give you a "compiled" regex object that can be re-used more efficiently; especially if you're doing things in a loop it's much more efficient to do that compilation as few times as possible.

In your example here, you're using it in a transform; it would also be worth pushing the re.compile out to a project library script (or, for more refactoring safety, just have a general filtering function in the project library that calls into the regex).

Personally, my line for "when to use a regex" is usually when the condition is unable to be cleanly expressed in a single line expression. So your second example there should absolutely stay a regex.

1 Like

As they say...

You have a problem. You use regex to solve it.
Now you have 2 problems.

Or something similar.

2 Likes

LOL!

http://regex.info/blog/2006-09-15/247

Ah, interesting. Jamie Zawinski would be my hero, for his distaste for Perl, except he likes Lisp. Lisp?!!? The language that is named for and personifies a speech defect?!?
:man_shrugging:

2 Likes