Reputation: 8033
I'm trying to apply a styler function to a df but getting this error and I don't know how to fix it.
ValueError: Function <function highlight at 0x0000029D89935F30> resulted in the apply method collapsing to a Series.
Usually, this is the result of the function returning a single value, instead of list-like.
I have a dataframe like below
Value Limit Actual
Issues < 33 0
Rating > 4 4.2
Complaints < 15 18
Time 30 - 45 41
Tip -- -
I want to color the column Actual
based on the Limit
column.
For example if the Limit
has "< 33", I want to color Actual
as Green if the value in Actual
column is less than 30, if not Red. Similarly for other rows as well.
If the Limit
has "30-45", I want to color Actual
as Green if the value in Actual
column is between 30 & 45 , if not Red.
If the Limit
has "-", I want to color Actual
as Yellow.
Based on this SO question Link, I created a function that evaluates the logic.
import re
def highlight(row):
numbers = re.findall('[0-9]+', row['Limit'])
if row['Value'] in ('Issues','Rating','Complaints'):
if '>' in row['Limit'] and row['Actual'] > numbers[0]:
color = 'green'
elif row['Actual'] < numbers[0]:
color = 'green'
else:
color = 'red'
else:
if len(numbers) == 0:
color = 'yellow'
elif row['Actual'] > numbers[0] and row['Actual'] < numbers[1]:
color = 'green'
else:
color = 'red'
return f"background-color: {color}"
However, when I try df.style.apply(highlight, axis=1)
, I get the error message at the beginning of the question.
How do I properly implement my logic to get the coloring I want? Below is what I want when I export this df to excel.
Upvotes: 1
Views: 2382
Reputation: 32921
The error message identifies the problem: "Usually, this is the result of the function returning a single value, instead of list-like." You have multiple columns, but you're only returning the style for one, and df.style.apply()
doesn't know which one. The docs explain:
func
should take a Series ifaxis
in [0,1] and return a list-like object of same length, or a Series, not necessarily of same length, with valid index labels consideringsubset
....
The elements of the output of
func
should be CSS styles as strings, in the format 'attribute: value; attribute2: value2; ...' or, if nothing is to be applied to that element, an empty string orNone
.
So in this case, you could simply return a list with no styles specified for the plain columns:
return [None, None, f"background-color: {color}"]
Or you could return a Series with just the "Actual" column style specified. This would still work even if you rearranged the columns or added more.
return pd.Series({'Actual': f"background-color: {color}"})
(Sidenote: I'm surprised it doesn't allow a dict, i.e. return {'Actual': f"background-color: {color}"}
.)
Upvotes: 1