Sos
Sos

Reputation: 1949

Styling upper triangular, lower triangular, and diagonal of a pandas dataframe

I have generated a pandas dataframe and I want to use pd.DataFrame().style to highlight some cells.

    v1  v2  v3  v4  v5
v1  0   1   1   1   0
v2  0   0   1   1   1
v3  0   0   0   0   0
v4  0   0   0   0   0
v5  0   0   0   0   0

I want to color its upper and lower triangular, as well as its diagonal. To do so I'm doing the following:

  1. Compute lower and upper triangular, and diagonal.

    def triang(df):
        temp=df.copy()
        ut=np.triu(np.ones(df.shape),1).astype(np.bool)
        lt=np.tril(np.ones(df.shape),-1).astype(np.bool)
    
        temp=temp.where(ut==False, 'up')
        temp=temp.where(lt==False, 'lt')
        np.fill_diagonal(temp.values,'dg')
        return(temp)
    
    triang(mymat)
    

returns

    v1  v2  v3  v4  v5
v1  dg  up  up  up  up
v2  lt  dg  up  up  up
v3  lt  lt  dg  up  up
v4  lt  lt  lt  dg  up
v5  lt  lt  lt  lt  dg
  1. Define the color function

    def color_vals(value):
         if value == 'up':
             color='orange'
         elif value=='lt':
             color='blue'
         else:
             color='black'
         return(color)
    color_vals('up')
    #'orange'
    
  2. Style the dataframe

    triang(mymat).style.applymap(color_vals)
    #returns the same as triang(mymat)
    

I am stuck in the style part (step 3). I'd like to see the very first matrix (mymat, the one with 0 and 1) stylized according to the colors per section (upper, lower triangular and diagonal).

How can I do the last step?

Thanks a lot in advance.

Upvotes: 1

Views: 1435

Answers (2)

Scott Boston
Scott Boston

Reputation: 153500

IIUC, try this:

where df_vals:

    v1  v2  v3  v4  v5
v1   0   1   1   1   0
v2   0   0   1   1   1
v3   0   0   0   0   0
v4   0   0   0   0   0
v5   0   0   0   0   0

def triang(df):
    temp=df.copy()
    ut=np.triu(np.ones(df.shape),1).astype(np.bool)
    lt=np.tril(np.ones(df.shape),-1).astype(np.bool)

    temp=temp.where(ut==False, 'up')
    temp=temp.where(lt==False, 'lt')
    np.fill_diagonal(temp.values,'dg')
    return(temp)

def color_vals(val):
    """
    Color dataframe using values
    """
    d = {'up' : 'orange',
         'dg' : 'black',
         'lt' : 'blue'}
    return [f'color : {i}' for i in triang(df_vals).loc[val.name, val.index].map(d).tolist()] 

df_vals.style.apply(color_vals)

Output:

enter image description here

Upvotes: 3

anky
anky

Reputation: 75100

I'd like to see the very first matrix (mymat, the one with 0 and 1) stylized according to the colors per section (upper, lower triangular and diagonal)

Okay so you can modify the function like below:

def myfunc(x):
    c1=np.triu(np.ones(df.shape),1).astype(np.bool)
    c2=np.tril(np.ones(df.shape),-1).astype(np.bool)
    col1='color:orange'
    col2='color:blue'
    col3='color:black'
    df1 = pd.DataFrame(np.select([c1,c2],[col1,col2],col3),columns=x.columns,index=x.index)
    return df1

df.style.apply(myfunc,axis=None) # mymat.style.apply(myfunc,axis=None)

enter image description here

Upvotes: 3

Related Questions