Custom CSS#

You can control the appearance of your table passing custom CSS. There are a few ways to achieve this.

Styles for values#

You can set css styles for values using the argument value_styles. This can be either a string (in which case the style is going to be applied to all values), a list of strings (or a numpy array or strings), in which case each style will be applied to one row, or a list of lists (or 2D numpy array of strings) in which case each style is going to be applied individually.

As an example let’s change the background of the values to achieve a zebra effect.

We will first create the dataframe we used in the basic usage last example. You can unfold to see the code.

Hide code cell source
import pandas as pd
from IPython.core.display import display, HTML

from pysummaries import pandas_to_report_html, get_styles
# a couple of symbols with html codes or html tags
dagger = "†"
sup = "<sup>1</sup>"
sub = "<sub>2</sub>"

nums = [["91 (67.9%) " + sup, "28 (49.1%)", "7 (50.0%)", "126 (61.5%)"],
["43 (32.1%)", "29 (50.9%)",	"7 (50.0%)", "79 (38.5%)"],
["50.0 (15.9)", "55.1 (17.9)", "65.3 (10.9)", "52.5 (16.7)"],
["52.0 [4.00, 84.0] " + sub, "56.0 [14.0, 95.0]", "65.0 [49.0, 86.0]", "54.0 [4.00, 95.0]"],
["91 (67.9%)", "28 (49.1%)", "7 (50.0%)", "126 (61.5%)"],
["43 (32.1%)", "29 (50.9%)",	"7 (50.0%)", "79 (38.5%)"],
["50.0 (15.9)", "55.1 (17.9)", "65.3 (10.9)", "52.5 (16.7)"],
["52.0 [4.00, 84.0]", "56.0 [14.0, 95.0]", "65.0 [49.0, 86.0]", "54.0 [4.00, 95.0]"]]

cols = [("Specific","Alive " + dagger, ""),
("Specific","Death", "Melanoma death"),
("Specific","Death", "Non-melanoma death"),	
("","Overall", "")]


rows = [("Section 1", "Gender", "Male"), ("Section 1", "Gender", "Female"),
    ("Section 1", "Age", "Mean (SD)"), ("Section 1", "Age", "Median [min max]"),
    ("Section 2", "Gender", "Male"), ("Section 2", "Gender", "Female"),
    ("Section 2", "Age", "Mean (SD)"), ("Section 2", "Age", "Median [min max]")]

df = pd.DataFrame(nums, columns=pd.MultiIndex.from_tuples(cols), index=pd.MultiIndex.from_tuples(rows))

# notice that now strat numbers must make reference to all the hierarchy of multi-indices
strat_numbers = {("Specific","Alive " + dagger, ""):"134",
    ("Specific", "Death", "Melanoma death"):"57",
    ("Specific", "Death", "Non-melanoma death"):"14",	
    ("", "Overall", ""):"205"}

# beautify and show
caption = "Table 1: a nice report table with multiple indices and symbols"
footer = [dagger + " This is a foot note",  "1.  Another foot note", "2. Yet another footnote"]
# And now, let's do the zebra effect
value_styles = ["background-color: lightgrey;", ""] * 4

caption = "Table 1: a nice report table with multiple indices and symbols"
footer = [dagger + " This is a foot note",  "1.  Another foot note", "2. Yet another footnote"]
table = pandas_to_report_html(df, strat_numbers=strat_numbers, 
                                                 caption=caption, footer=footer, 
                                                 value_styles=value_styles)
table
Table 1: a nice report table with multiple indices and symbols
Specific
Alive † Death Overall

(N=134)
Melanoma death
(N=57)
Non-melanoma death
(N=14)

(N=205)
Section 1
Gender
Male 91 (67.9%) 1 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 2 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
Section 2
Gender
Male 91 (67.9%) 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
† This is a foot note
1. Another foot note
2. Yet another footnote

Now, let’s say we would like to highlight only a couple of values. In this case we need a 2D data structure to represent all values in our table, and we change the styles only for those that we are interested in.

highlight = "background-color: yellow;"
value_styles = [[""] * 4 for x in range(8)]
# let's highlight the element in the first row fourth column, 
value_styles[0][3] = highlight
# and in the third row, second 
value_styles[2][1] = highlight

caption = "Table 1: a nice report table with multiple indices and symbols"
footer = [dagger + " This is a foot note",  "1.  Another foot note", "2. Yet another footnote"]
table = pandas_to_report_html(df, strat_numbers=strat_numbers, 
                                                 caption=caption, footer=footer, 
                                                 value_styles=value_styles)
table
Table 1: a nice report table with multiple indices and symbols
Specific
Alive † Death Overall

(N=134)
Melanoma death
(N=57)
Non-melanoma death
(N=14)

(N=205)
Section 1
Gender
Male 91 (67.9%) 1 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 2 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
Section 2
Gender
Male 91 (67.9%) 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
† This is a foot note
1. Another foot note
2. Yet another footnote

Styles for other elements with customstyles#

You can change the styles of other elements on the table as a block using the argument customstyles. This must be a dictionary where they keys are the elements and the values are the styles.

You can check what are the keys and the default styles with the function get_styles, using ‘default’ as argument.

default_styles = get_styles('default')

for k, v in default_styles.items():
    print(k, ":", v)
table : font-family: Arial, sans-serif; border-collapse: collapse; padding: 0px; margin: 0px;
caption : padding: 0px; margin: 0px; text-align: left !important; margin-bottom: 5px;
superheader : padding: 0.5ex 1.5ex; margin-left: 1.5ex; margin-right: 1.5ex; text-align: center !important; margin: 0px; background-color: white;
header : border-bottom: 1pt solid black; text-align: center !important; padding: 0.5ex 1.5ex; margin: 0px; background-color: white;
rowgrouplabel : padding-top: 0.5ex; padding-right:1.5ex; padding-bottom:0.5ex;font-weight: bold; text-align: left !important;  white-space: nowrap; background-color: white;
rowlabel : padding-top: 0.5ex; padding-right:1.5ex; padding-bottom:0.5ex; text-align: left !important; white-space: nowrap; background-color: white;
footnote : font-size: smaller; padding: 0px; margin: 0px; text-align: left !important; 
value : text-align: center !important; padding: 0.5ex 1.5ex; margin: 0px; background-color: white; white-space: nowrap;

As an example, let’s change the font color and size of the caption, you can achieve this by passing your own customstyles dictionary

customstyles = {'caption': 'color: blue; font-size: larger;'}

table = pandas_to_report_html(df, strat_numbers=strat_numbers, 
                                                 caption=caption, footer=footer, 
                                                 customstyles=customstyles)
table
Table 1: a nice report table with multiple indices and symbols
Specific
Alive † Death Overall

(N=134)
Melanoma death
(N=57)
Non-melanoma death
(N=14)

(N=205)
Section 1
Gender
Male 91 (67.9%) 1 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 2 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
Section 2
Gender
Male 91 (67.9%) 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
† This is a foot note
1. Another foot note
2. Yet another footnote

Your customstyles will be appended to the existing default styles. Since the last css property is the one that takes precedence, you can effectively override any style. However, if needed, you can pass the argument styles=’empty’ to completely get rid of any default styles (except a few that have to do with borders and indentation). Here we see some strange formatting because JupyterBook has a default formatting that now is showing_up once we get rid of our own formatting.

table = pandas_to_report_html(df, strat_numbers=strat_numbers, 
                                                 caption=caption, footer=footer, 
                                                 styles='empty')
table
Table 1: a nice report table with multiple indices and symbols
Specific
Alive † Death Overall

(N=134)
Melanoma death
(N=57)
Non-melanoma death
(N=14)

(N=205)
Section 1
Gender
Male 91 (67.9%) 1 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 2 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
Section 2
Gender
Male 91 (67.9%) 28 (49.1%) 7 (50.0%) 126 (61.5%)
Female 43 (32.1%) 29 (50.9%) 7 (50.0%) 79 (38.5%)
Age
Mean (SD) 50.0 (15.9) 55.1 (17.9) 65.3 (10.9) 52.5 (16.7)
Median [min max] 52.0 [4.00, 84.0] 56.0 [14.0, 95.0] 65.0 [49.0, 86.0] 54.0 [4.00, 95.0]
† This is a foot note
1. Another foot note
2. Yet another footnote

Map of custom classes#

Here we show a map of the custom classes you have on the precedent table. The class of the table itself is “table”

caption
superheader superheader superheader
superheader superheader superheader superheader
header header
header
header
header
rowgrouplabel
rowgrouplabel
rowlabel rowvalue rowvalue rowvalue rowvalue
rowlabel rowvalue rowvalue rowvalue rowvalue
rowgrouplabel
rowlabel rowvalue rowvalue rowvalue rowvalue
rowlabel rowvalue rowvalue rowvalue rowvalue
rowgrouplabel
rowgrouplabel
rowlabel rowvalue rowvalue rowvalue rowvalue
rowlabel rowvalue rowvalue rowvalue rowvalue
rowgrouplabel
rowlabel rowvalue rowvalue rowvalue rowvalue
rowlabel rowvalue rowvalue rowvalue rowvalue
footnote