Pandas is the most commonly used data analysis tool in python for tabular data. It's built on the top of numpy and hence is quite fast in performing various data manipulation as well. Pandas data frames are commonly displayed in jupyter notebooks for presentation purposes as well. Pandas data frames are internally converted into HTML <table>
and then displayed in Jupyter notebook. The default display is very simple and does not provide any special functionalities which can be used for presentation purposes like a different color of cells, rows, columns, etc. There can be instances when we want to use jupyter notebooks for presentation purposes and we want to highlight few things in our data frames to attract the attention of the audience towards them and we can do such things with pandas.
Pandas provide us with Styler object which has a bunch of methods that we can utilize to modify the default look of the data frames in Jupyter Notebook. It even lets us include CSS in our code to make attractive tables. The modifications will require a little bit of HTML and CSS knowledge to properly decorate tables. We can also take the HTML code of the modified dataframe and deploy it to our website. The Styler object is accessible through style attribute of a data frame.
We have created this tutorial to explain how we can style pandas data frame. We'll try to explain different methods with very simple examples so that it is easy to grasp. We'll start by importing the necessary libraries.
import pandas as pd
import numpy as np
We have started by creating a dataframe of 10 rows and 5 columns for explanation purposes. The data in the dataframe is random floats in the range 0-1. We'll be using this dataframe for all our examples to make things easier to understand.
data = np.random.random(size=(10,5))
df = pd.DataFrame(data=data, columns=list("ABCDE"),
index=["A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "I9", "J10"])
df
Below we have retrieved Styler instance of the data frame. When we execute the styler instance in the jupyter notebook, it creates tabular representation from it as well because it has _repr_html_
method which creates an HTML representation of it.
print("Styler : {}".format(type(df.style)))
df.style
The Styler instStyle DataFrame Headerance has a method named render() which returns a string containing the HTML code of the data frame table and it includes CSS as well. Below we have printed only the first 1500 characters for explanation purposes.
print(df.style.render()[:1500])
The Styler instance provides us with 4 useful methods which let us decorate HTML tables in three different ways. These 4 methods will do the working majority of the time. It does provide additional methods which we'll discuss as well but these four methods should do the working majority of the time.
Below is sample CSS data that we'll transform for the purpose of explanation. We have transformed it in two different ways.
CSS
thead {
background-color:dodgerblue;
color:white;
border:3px solid red;
}
Style for Method 1
[
{
"selector":"thead",
"props":"background-color:dodgerblue; color:white; border:3px solid red;"
},
]
Style for Method 2
[
{
"selector":"thead",
"props": [("background-color", "dodgerblue"), ("color", "white"),("border", "3px solid red"),]
},
]
2. set_td_classes(classes_dataframe) - This method works in combination with set_table_styles(). This method accepts a data frame that has the same size as that of the original data frame with values that are strings representing an HTML class that we want to assign to an individual cell. It'll assign that class to an individual cell of the HTML table and then we can apply style for those classes using set_table_styles(). This can be used to decorate individual cells of the data frame.
3. apply(func,axis=0,subset=None) - This function is well suited for row-wise or column-wise decoration.
4. applymap(func,subset=None) - This function is well suited for the decoration of individual cells based on some conditions.
If you don't understand the methods from the theoretical explanation above then it's okay, don't worry. Things will become very easy when you actually see the results of applying them with few simple examples.
We'll now try to explain with simple examples how we can decorate different parts of the data frame table when displaying it in the jupyter notebook. We'll cover the below-mentioned TOPICS.
As a part of this section, we'll explain how we can style the header of the pandas data frame using set_table_styles() method. We have provided list with one dictionary to set_table_styles() method. We have set the value of selector key as thead which is HTML tag (header of HTML table) and the value of props with styling details like the background color of dodger blue, white font color, and border of 3 pixels.
We have also printed the type of returned object after calling method set_table_styles() which gets easily rendered by jupyter notebook.
s = df.style.set_table_styles([
{
"selector":"thead",
"props":"background-color:dodgerblue; color:white; border:3px solid red;"
},
])
type(s)
s
Below we have explained another way of decorating the header of the data frame where we give style details to props key as a list of tuples. We can notice that it produces the same results as the above one.
s = df.style.set_table_styles([
{
"selector":"thead",
"props": [("background-color", "dodgerblue"), ("color", "white"),
("border", "3px solid red"),
]
},
])
s
We can call render() method anytime to see the CSS and HTML of the table. We can export this to an HTML file and display it on some other website as well.
print(s.render()[:800])
As a part of this section, we have explained how we can style the header and index of the data frame using set_table_styles() method. We have provided a method with a list of two dictionaries. The first dictionary like previous examples decorates the header whereas the second dictionary has decoration details for the index. We have used string th.row_heading as selector to decorate index. We can notice that th tags have details about an index of the data frame.
This time we have also increased the font size of both header and index. We have printed CSS and HTML of the table as well below to see styling details.
s = df.style.set_table_styles([
{
"selector":"thead",
"props": [("background-color", "dodgerblue"), ("color", "white"),
("border", "3px solid red"),
("font-size", "2rem"), ("font-style", "italic")]
},
{
"selector":"th.row_heading",
"props": [("background-color", "orange"), ("color", "green"),
("border", "3px solid black"),
("font-size", "2rem"), ("font-style", "italic")]
},
])
s
print(s.render()[:800])
As a part of this section, we have explained how to target an individual column of the data frame. We have passed dictionary to set_table_styles() this time with key as C and value as list of one dictionary. The dictionary holds decoration details. It has selector set as td (HTML cell tag) and props set as a string of styling like a border of 2 pixels, green font color, and yellow background color.
s = df.style.set_table_styles({"C" : [
{
"selector" :"td",
"props": "border: 2px solid red; color:green; background-color:yellow;"
}
]
})
s
Below we have explained the same example as above but this time we have passed decoration details as a list of tuples to props key. We have as usual printed CSS and HTML table details using render() method.
s = df.style.set_table_styles({"C" : [
{
"selector" :"td",
"props": [("border","2px solid red"),
("color", "green"),
("background-color", "yellow")]
}
]
})
s
print(s.render()[:500])
As a part of this section, we have explained how we can style individual rows of the data frames. We have passed a list of one dictionary to style the second row of a data frame. We can notice from the code of the HTML table above that row1 is the class for the second row of a table. We'll be giving that to selector to style it. The styling details are given to props key which has almost the same details as the previous example.
s = df.style.set_table_styles([
{
"selector" :".row1",
"props": [("border","2px solid red"),
("color", "green"),
("background-color", "yellow")]
}
]
)
s
print(s.render()[:500])
Below we have explained another way of highlighting a particular row. This time we have passed dictionary to set_table_styles() with key as value B2 and value as a list of a single dictionary that holds decoration details. We have set axis parameter to 1 which indicated that we'll be targeting each row and key B2 will limit targeting to only that row. The dictionary passed for decoration has selector set as td which will target all cells.
Please make a note that styling in this example does not style index value whereas in the previous example it did style index value as well.
s = df.style.set_table_styles({"B2" : [
{
"selector" :"td",
"props": [("border","2px solid red"),
("color", "green"),
("background-color", "yellow")]
}
]
},
axis=1
)
s
print(s.render()[:500])
As a part of this section, we have demonstrated how to style individual cells of the table. Though styling individual cell using set_table_styles() is possible but not recommended.
We have passed selector value of .row1.col1 which refers to a cell in the second row and second column. The value of props is like previous examples. We can notice here that we will need to pass different class names if we want to style individual cells which can increase the number of styling entries a lot and can make code cumbersome. Hence this way of styling individual cells is not recommended. We have explained the efficient way of styling individual cells in upcoming examples.
This method is okay if you want to style only a few cells of the data frame though.
s = df.style.set_table_styles([
{
"selector" :".row1.col1",
"props": [("border","2px solid red"),
("color", "green"),
("background-color", "yellow")]
}
]
)
s
print(s.render()[:500])
As a part of this example, we have explained how to style individual cells of the data frame using set_td_classes() method.
As we had explained earlier, set_td_styles() works in combination with set_table_styles(). We'll be setting class for individual cells of data frame HTML table using set_td_styles() method and then decorate cells based on classes assigned using set_table_styles().
Below we have created a dataframe that has exactly the same shape as our original data frame. We have kept string green where the value in a cell is greater than 0.5 and red where the value is less than 0.5
data = np.array(["red" if cell < 0.5 else "green" for row in df.values for cell in row])
cell_color = pd.DataFrame(data.reshape(df.shape),
index=df.index,
columns=df.columns)
cell_color
Below we have set the style for red classes to be of red background and for green classes to be of the green background. We have done that using set_table_styles() method. Then we have set classes using set_td_styles() method by giving it the data frame created in the previous step.
s = df.style.set_table_styles([
{"selector": ".green", "props": "background-color:lime; font-size:1.5rem;"},
{"selector": ".red", "props": "background-color:tomato; font-size:0.9rem;"}
])
s.set_td_classes(cell_color)
Below we have explained another way of styling individual cells of the data frame using applymap() method. As we had explained earlier, the applymap() method takes as input function which takes a single value as input and returns a single value as output. The output value is decoration detail and the single input value is cell data. It takes decisions based on the value of cell data. Like earlier, if a value is greater than 0.5 then it returns styling details with background color green and if a value is less than 0.5 then it returns styling details with background color red.
s = df.style.applymap(lambda x: "background-color:lime; font-size:1.5rem;" if x > 0.5 else "background-color:tomato; font-size:0.9rem;")
s
As a part of this section, we have explained how we can style individual cells of selected columns of the data frames. We have used applymap() method for this purpose. We have given a function that is the same as previous examples as the first parameter. We have set subset parameter to list of two columns names to target only those columns.
s = df.style.applymap(lambda x: "background-color:lime; font-size:1.5rem;" if x > 0.5 else "background-color:tomato; font-size:0.9rem;",
subset=["B", "D"])
s
Below we have explained how we can decorate individual cells of selected columns using apply() method. It also takes as input function like applymap() method but input to that function is series and output is also series unlike applymap(). We have a set function that takes series as input and returns a list with styling details for each cell of that series. We have set subset parameter to two-column names to target cells of only those columns.
s = df.style.apply(lambda x: ["background-color:lime; font-size:1.5rem;" if i>0.5 \
else "background-color:tomato; font-size:0.9rem;" for i in x],
subset=["B", "D"],
)
s
As a part of this section, we have explained how we can style individual cells selected rows of the data frame. We have used apply() method for this purpose. We have set the function to the same function which we had used in our previous example. We have set subset parameter to a tuple of two values. The first value is a list of index names and the second value is a list of column names. We have given B2 and D4 as index names to decorate only those rows and for columns, we have given an empty list.
s = df.style.apply(lambda x: ["background-color:lime; font-size:1.5rem;" if i>0.5 \
else "background-color:tomato; font-size:0.9rem;" for i in x],
subset=(["B2", "D4"], slice(None)),
) ## Axis=1 : Row and Axis=0: Column
s
As a part of this section, we have explained how we can decorate cells that come at the intersection of selected rows and columns. We have used apply() function for this purpose.
We have given the same function to apply() method that we have used in the previous example. The subset parameter is set to a tuple with two lists where the first list has index names and the second list has column names.
s = df.style.apply(lambda x: ["background-color:lime; font-size:1.5rem;" if i>0.5 \
else "background-color:tomato; font-size:0.9rem;" for i in x],
subset=(["B2", "D4"], ["A","C"]),
) ## Axis=1 : Row and Axis=0: Column
s
As a part of this section, we'll explain how we can decorate the values of cells by going row at a time or column at a time. We have used apply() function for this purpose.
We have given function to apply() method which takes series as input and returns a list of the same length with details about styling for an individual element of series. The function sets background color as dodger blue if the value is a maximum value of series else sets the background color to orange.
We have set axis parameter to 1 to go row-wise. It'll pass a single row as a series to function.
s = df.style.apply(lambda x: ["background-color:dodgerblue;" if i == x.max() \
else "background-color:orange;" for i in x],
axis=1) ## Axis=1 : Row and Axis=0: Column
s
Below we have explained how we can work on columns of the data frame using apply() function. We have passed the same function as our previous cell but this time we have set axis parameter to 0 which will send one by one column data as a series to function.
We can notice differences from the previous example. The previous example highlighted the maximum value per row and this one highlighted the maximum value per column.
s = df.style.apply(lambda x: ["background-color:dodgerblue;" if i == x.max() \
else "background-color:orange;" for i in x],
axis=0) ## Axis=1 : Row and Axis=0: Column
s
As a part of this section, we'll explain how we can highlight null values in the data frame. We have first set few cells of the data frame as null. The Styler instance has a method named highlight_null() which can be used for special treatment of nulls.
Below we have highlighted null values as red color.
df.iloc[0, 1] = np.nan
df.iloc[1, 3] = np.nan
df.iloc[3, 4] = np.nan
df.iloc[4, 4] = np.nan
df.iloc[6, 2] = np.nan
df.iloc[8, 3] = np.nan
df.iloc[9, 4] = np.nan
df.style.highlight_null(null_color="tomato")
Below we have explained another example where we highlight null values by using props parameter.
df.style.highlight_null(props="border: 2px solid dodgerblue; background-color: yellow; color:red;")
Below we have highlighted null values for only columns A,C, and E using subset parameter.
df.style.highlight_null(props="border: 2px solid dodgerblue; background-color: yellow; color:red;",
subset=list("ACE"))
As a part of this section, we'll explain how we can highlight min/max values for each rows and columns of data frame. The Styler object provides highlight_min() and highlight_max() methods for this purpose.
Below we have highlighted min values per column with red color.
df.style.highlight_min(axis=0, color="tomato")
Below we have highlighted max values per column with red color.
df.style.highlight_max(axis=0, color="tomato")
Below we have highlighted min value per row using red color.
df.style.highlight_min(axis=1, color="tomato")
Below we have highlighted max value per row with red color.
df.style.highlight_max(axis=1, color="tomato")
Below we have highlighted min value per row with different styling details.
df.style.highlight_min(axis=1, props="border: 2px solid dodgerblue; background-color: yellow; color:red;")
As a part of this section, we have explained how we can highlight values in a particular range using highlight_between() method of Styler instance.
Below we have highlighted values in the range (0.3,0.6) with yellow color.
df.style.highlight_between(left=0.3, right=0.6, color="yellow", axis=0)
Below we have highlighted values in the range (0.3, 0.6) with different styling details.
df.style.highlight_between(left=0.3, right=0.6,
axis=1,
props="background-color:tomato; border:3px dotted dodgerblue;")
As a part of this section, we have explained how we can highlight values in a particular quartile range using highlight_quartile() method of Styler object.
below we have highlighted values in the quartile range of (0.0-0.5).
df.style.highlight_quantile(q_left=0.0, q_right=0.5,
axis=0, props="border: 2px solid grey; background-color: black; color:white;")
Below we have highlighted values in quartile range of (0.0-0.5) but does not include bounds.
df.style.highlight_quantile(q_left=0.0, q_right=0.5, inclusive="neither",
axis=0, props="border: 2px solid grey; background-color: black; color:white;")
As a part of this section, we have explained how we can create a heatmap in a data frame based on their values. The Styler instance provides 2 methods for this purpose.
Below we have explained the usage of both methods on our data frame.
import matplotlib.pyplot as plt
df.style.background_gradient(cmap="Purples")
df.style.text_gradient(cmap="Purples")
As a part of this section, we have explained how we can style all the cells of a data frame in one go. We can use this kind of styling when we don't have to do conditional styling. Styling this way does not style the header and index, it only styles all cells. The Styler instance provides a method named set_properties() for this purpose.
Below we have explained the usage of the method with simple examples.
df.style.set_properties(color="red", border="2px solid dodgerblue")
df.style.set_properties(**{
"color":"red",
"border":"2px solid dodgerblue",
"background-color": "yellow",
})
As a part of this section, we have explained how we can bar inside of pandas data frame which has only float or integer values inside of it. The Styler instance provides us with a method named bar() which lets us create a bar chart inside of the data frame.
Please make a note that when method is going column-wise, it'll only consider values of that columns to create bar chart and not the values of whole data frame. The same will happen when it goes row-wise. Pay attention to axis parameter for this.
Below we have simply created a bar chart with lime color on our existing data frame.
df.style.bar(color='lime')
Below we have given two colors as input and aligned bar in the center.
df.style.bar(color=['tomato','lime'],align='mid')
Below we have explained another example that has the same code as the previous one but this time we have set axis parameter to 1 so that it goes row by row instead of column by column.
df.style.bar(color=['tomato','lime'],align='mid', axis=1)
Below we have set few values in the data frame as negative and then created a bar chart on it by setting align parameter to zero. This will make sure that 0 is in the center.
df.iloc[5, 0] = -0.5
df.iloc[7, 0] = -0.7
df.iloc[1, 0] = -0.1
df.iloc[3, 2] = -0.2
df.iloc[1, 2] = -0.1
df.iloc[8, 2] = -0.9
df.style.bar(color=["tomato", "lime"], align="zero")
Our last example explains how we can apply this to only a few columns/rows based on our needs.
df.style.bar(color=["tomato", "lime"], subset=["A", "C"], align="mid")
df.style.bar(color=["tomato", "lime"], subset=(["B2", "F6"],slice(None)), axis=0, align="zero")
This ends our small tutorial explaining how we can style pandas data frames with CSS styles. Please feel free to let us know your views in the comments section.
If you are more comfortable learning through video tutorials then we would recommend that you subscribe to our YouTube channel.
When going through coding examples, it's quite common to have doubts and errors.
If you have doubts about some code examples or are stuck somewhere when trying our code, send us an email at coderzcolumn07@gmail.com. We'll help you or point you in the direction where you can find a solution to your problem.
You can even send us a mail if you are trying something new and need guidance regarding coding. We'll try to respond as soon as possible.
If you want to