Search code examples
pythonpandasdataframedata-visualizationpandas-styles

How to add a border to column headers and caption to pandas dataframe using .style?


I am trying to adding borders to the column headers and also the caption to the dataframe below. I can successfully add a border to the caption, but when I attempt to add a border around the column headers I believe it overrides the caption border and format. Is there a way to add borders to both? I tried adding two .set_table_styles() statements and I also tried incorporating them into the same chunk of code, but I must be misunderstanding how to code is being interpreted when ran.

final = unique_shows_imdb_final.style.bar(subset=["Netflix IMDb Score"], color='')\
                     .bar(subset=["Hulu IMDb Score"], color='')\
                     .bar(subset=["Prime IMDb Score"], color='')\
                     .bar(subset=["Disney+ IMDb Score"],color='').background_gradient(cmap=sns.cm.rocket_r,axis=None).hide_index().format(precision=1)

final.set_properties(subset=['Rank'], **{'font-weight': 'bold'})



final.set_properties(
    **{'border': '1px black solid !important'}
).set_table_styles([{
    'selector': '',
    'props': [('border', '2px black solid !important')]}]
).set_caption("Top 20 TV Shows per Streaming Platform").set_table_styles([{
    'selector': 'caption',
    'props': [
        ('color', 'black'),
        ('font-size', '25px'),
        ('text-align','center'),
        ('border', '3px black solid !important')
    ]
}])

Successful border around caption

final = unique_shows_imdb_final.style.bar(subset=["Netflix IMDb Score"], color='')
.bar(subset=["Hulu IMDb Score"], color='')
.bar(subset=["Prime IMDb Score"], color='')
.bar(subset=["Disney+ IMDb Score"],color='').background_gradient(cmap=sns.cm.rocket_r,axis=None).hide_index().format(precision=1)

final.set_properties(subset=['Rank'], **{'font-weight': 'bold'})



final.set_properties(
    **{'border': '1px black solid !important'}
).set_table_styles([{
    'selector': '',
    'props': [('border', '2px black solid !important')]}]
).set_caption("Top 20 TV Shows per Streaming Platform").set_table_styles([{
    'selector': 'caption',
    'props': [
        ('color', 'black'),
        ('font-size', '25px'),
        ('text-align','center'),
        ('border', '3px black solid !important')
    ]
}])

final.set_table_styles([{'selector': 'th', 'props': [('font-size', '10pt'),('border-style','solid'),('border-width','1px')]}])

Successful add of border around column header, lose formatting/border of caption


Solution

  • set_table_styles by default has overwrite=True.

    From the Docs:

    overwrite bool, default True

    Styles are replaced if True, or extended if False. CSS rules are preserved so most recent styles set will dominate if selectors intersect. New in version 1.2.0.

    This means that (by default) each call will overwrite the previous styles, we can set overwrite=False and also add in the missing "border-color" from the table styles:

    final.set_properties(
        **{'border': '1px black solid !important'}
    ).set_table_styles([{
        'selector': '',
        'props': [('border', '2px black solid !important')]}]
    ).set_caption("Top 20 TV Shows per Streaming Platform").set_table_styles([{
        'selector': 'caption',
        'props': [
            ('color', 'black'),
            ('font-size', '25px'),
            ('text-align', 'center'),
            ('border', '3px black solid !important')
        ]
    }], overwrite=False)  # Don't overwrite previous styles
    
    final.set_table_styles([{
        'selector': 'th', 'props': [
            ('font-size', '10pt'),
            ('border-style', 'solid'),
            ('border-width', '1px'),
            ('border-color', 'black') # Missing Border Color here
        ]
    }], overwrite=False)  # Don't overwrite previous styles
    

    Sample Data:

    import numpy as np
    import pandas as pd
    
    np.random.seed(5)
    df = pd.DataFrame(np.random.randint(1, 100, (4, 6)))
    final = df.style
    

    Sample Output:

    styled table


    However, generally it is better practice to style the table last and pass a single list of selector dictionaries:

    final.set_properties(
        **{'border': '1px black solid !important'}
    ).set_caption("Top 20 TV Shows per Streaming Platform").set_table_styles([
        # Selector 1
        {'selector': '',
         'props': [('border', '2px black solid !important')]},
        # Selector 2
        {'selector': 'caption',
         'props': [
             ('color', 'black'),
             ('font-size', '25px'),
             ('text-align', 'center'),
             ('border', '3px black solid !important')]},
        # Selector 3
        {'selector': 'th', 'props': [
            ('font-size', '10pt'),
            ('border-style', 'solid'),
            ('border-width', '1px'),
            ('border-color', 'black')  # Missing Border Color here
        ]}
    ])
    

    This produces the exact same styled frame as above.