'Applying style to a pandas DataFrame row-wise
I'm experimenting/learning Python with a data set containing customers information.
The DataFrame structure is the following (these are made up records):
import pandas as pd
df1 = pd.DataFrame({'left_name' : ['James', 'Mary', 'John', 'Patricia'],
'left_age' : [30, 37, 30, 35],
'right_name' : ['Robert', 'Jennifer', 'Michael', 'Linda'],
'right_age' : [30, 31, 38, 35]})
print(df1)
left_name left_age right_name right_age
0 James 30 Robert 30
1 Mary 37 Jennifer 31
2 John 30 Michael 38
3 Patricia 35 Linda 35
Applying the transpose method to df1, we get the following view:
df2 = df1.T
print(df2)
0 1 2 3
left_name James Mary John Patricia
left_age 30 37 30 35
right_name Robert Jennifer Michael Linda
right_age 30 31 38 35
My goal is to apply some styling to df2. Specifically,
- The
left_nameandright_namerows should be highlighted in yellow; - The
left_ageandright_agerows should be highlighted in blue.
I did some research before posting here and I managed to highlight one subset the following way:
df2.style.set_properties(subset = pd.IndexSlice[['left_name', 'right_name'], :], **{'background-color' : 'yellow'})
The problem is that I'm unable to combine multiple styles together. If I add an additional blue color for left_age and right_age using the same method as above, I "lose" the previous style.
Ideally, I would like to have a function that takes df2 as input and returns the styled DataFrame.
Solution 1:[1]
You can create DataFrame of styles with Styler.apply and set rows by index value with loc:
def highlight(x):
c1 = 'background-color: yellow'
c2 = 'background-color: blue'
df1 = pd.DataFrame('', index=x.index, columns=x.columns)
df1.loc[['left_name','right_name'], :] = c1
df1.loc[['left_age','right_age'], :] = c2
return df1
df1.T.style.apply(highlight, axis=None)
Solution 2:[2]
You were so close! You can actually "chain" set_properties on the same dataframe:
df2.style.set_properties(subset = pd.IndexSlice[['left_name','right_name'], :], **{'background-color' : 'yellow'})\
.set_properties(subset = pd.IndexSlice[['left_age','right_age'], :], **{'background-color' : 'blue'})
I'm sure there is a more elegant solution - but this works!
Solution 3:[3]
Following up on MattR's answer: instead of chaining, you can also assign the result to a styler for the first call to set_properties, and call set_properties again - plus slightly different way of selecting the rows:
s1 = df1.T.style.set_properties(**{'background-color': 'yellow'}, subset=(['left_name', 'right_name'], slice(None)))
s1 = s1.set_properties(**{'background-color': 'blue'}, subset=(['left_age', 'right_age'], slice(None)))
s1
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | MattR |
| Solution 3 | Alex Waygood |


