
Styled Pandas (Image by author)
At the end of your data analysis, you need to decide how to communicate your findings. Tables can be more suitable than graphs for communicating data when you need your audience to look up individual precise values and compare them to other values. However, tables contain a lot of information that your audience processes by reading, which makes it difficult for your audience to understand your message right away. Random design of the table, such as too many colors, bold borders, or too much information, can additionally distract your audience. However, purposeful usage of formatting and styling can guide your audience’s attention to the most important number in a table.
Purposeful usage of formatting and styling can guide your audience’s attention to the most important number in a table.
DataFrames from the pandas library are great to visualize data as tables in Python. Additionally, the pandas library provides methods to format and style the DataFrame via the style attribute. Therefore, this article discusses essential techniques to format and style pandas DataFrames to effectively communicate data.
If you want to play around with the techniques describes in this article, you can download or fork this article’s code including the example dataset from my related Kaggle Notebook.
For this tutorial, we will be using the following small fictional dataset:
)](images/essential-techniques-to-style-pandas-dataframes-unstyled-pandas-dataframe-of-fictional-sample.webp)
Global Display Options
Before you get started with customizing the visualizations for individual DataFrames, you can adjust the global display behavior of pandas with the .set_option() method [1]. Two common tasks you can handle are:
- displaying all columns of a DataFrame and
- adjusting the width of a DataFrame column.
When your DataFrame has too many columns, pandas does not render all columns but instead hides columns in the middle. To force pandas to display all columns, you can set:
pd.set_option("display.max_columns", None)When you are working with long texts, pandas truncates the text in the column. To force pandas to display the full column contents by increasing the column width, you can set:
pd.set_option("display.max_colwidth", None)General Tips
The DataFrame’s style attribute, returns an object of the class Styler. This class contains various formatting and styling methods. The following tips apply to all methods of the Styler object.
Multiple Stylings
You can combine multiple stylings by chaining multiple methods together.
E.g. df.style.set_caption(...).format(...).bar(...).set_properties(...)
Column-wise vs. Row-wise Styling
By default, the styling is applied column-wise (axis = 0).
df.style.highlight_max() # default is axis = 0)](images/essential-techniques-to-style-pandas-dataframes-highlight-column-wise-maximum-with-axis-0-image.webp)
If you want to apply the styling row-wise, use axis = 1 in the properties instead.
df.style.highlight_max(axis = 1)))](images/essential-techniques-to-style-pandas-dataframes-highlight-row-wise-maximum-with-axis-1-image-by.webp)
Styling Only a Subset
By default, the styling methods are applied to all columns.
df.style.background_gradient())](images/essential-techniques-to-style-pandas-dataframes-background-gradient-applied-to-all-columns-image.webp)
If you want to apply the stylings only to one column or a selected subset of columns, use the subset parameter.
df.style.background_gradient(subset = ["A", "D"])))](images/essential-techniques-to-style-pandas-dataframes-background-gradient-applied-to-all-columns-image.webp)
Formatting
Before we begin with any specific coloring, let’s have a look at some fundamental formatting techniques to make your DataFrame look more polished.
Caption
Adding a caption to a table is essential to provide some context to your audience. You can add the caption to the DataFrame with the .set_caption() method.
df.style.set_caption("Caption Text"))](images/essential-techniques-to-style-pandas-dataframes-caption-added-above-dataframe-image-by-author.webp)
Renaming Columns
If the column names are variable names or abbreviated, it might not be clear to your audience what data they are looking at. Giving the columns intuitive column names, can support your audience’s understanding of the data.
There are two options to rename your columns:
- Renaming all columns at once
- Renaming only a subset of columns
If you need to work with the DataFrame later on, it might make sense to create a copy of the DataFrame for visualization purposes only.
# Create a copy of the DataFrame for visualization purposes
df_viz = df.copy()You can rename all columns at once by changing the columns attribute:
# Rename all columns
df_viz.columns = ["New Column Name A",
"New Column Name B",
"New Column Name C",
"New Column Name D"])](images/essential-techniques-to-style-pandas-dataframes-rename-all-columns-of-dataframe-image-by-author.webp)
Or you can rename only a subset of columns with the .rename() method and a dictionary.
# Rename selection of columns
df_viz.rename(columns = {"A" : "New Column Name A",
"B" : "New Column Name B"},
inplace = True))](images/essential-techniques-to-style-pandas-dataframes-rename-only-a-subset-of-columns-image-by-author.webp)
Hiding the Index
Does the index add any valuable information? If not, you can hide the index with the .hide_index() method.
df.style.hide_index())](images/essential-techniques-to-style-pandas-dataframes-hidden-index-image-by-author-from-kaggle.webp)
Format Columns
Adding thousands-separators or truncating the floating-point numbers to fewer decimal places can increase the readability of your DataFrame. For this purpose, the Styler object can distinguish the display values from the actual values.
By using the .format() method you can manipulate the display values according to a format spec string [3]. You can even add a unit before or after the number as part of the formatting.
df.style.format({"A" : "{:,.0f}",
"B" : "{:d} $",
"C" : "{:.3f}",
"D" : "{:.2f}"}))](images/essential-techniques-to-style-pandas-dataframes-columns-formatted-with-thousands-separator-and.webp)
However, to not disturb the attention, I would recommend putting the unit in square brackets in the column name, e.g., “Salary [$]”.
Styling Properties
Sometimes, all you want to do might be to highlight a single column in the DataFrame by adjusting the background and font color. For this purpose, you can use the .set_properties() method to adjust the relevant CSS properties of the DataFrame such as colors, fonts, borders, etc.
df.style.set_properties(subset = ["C"],
**{"background-color": "lightblue",
"color" : "white",
"border" : "0.5px solid white"}))](images/essential-techniques-to-style-pandas-dataframes-highlighted-column-image-by-author-from-kaggle.webp)
Built-in Styling
The Style class has some built-in methods for common styling tasks.
Highlighting
Highlighting individual cells is an easy way to guide your audience’s attention to what you want to show. Common values you might want to highlight are minimum, maximum, and null values. For these cases, you can use the respective built-in methods.
You can adjust the highlight color with the parameter color for minimum and maximum highlighting and nullcolor for null highlighting.
df.style.highlight_null(null_color = "yellow"))](images/essential-techniques-to-style-pandas-dataframes-highlighted-null-value-image-by-author-from-kaggle.webp)
If you want to highlight both minimum and maximum values, you can do so by chaining both functions together.
df.style.highlight_min(color = "red")\
.highlight_max(color = "green"))](images/essential-techniques-to-style-pandas-dataframes-highlighted-minimum-and-maximum-values-image-by.webp)
Gradients
Adding gradient styles can help the audience understand the relationship of the numerical values within the table, a single column or a single row. For example, gradients can indicate whether a value is large or small, positive or negative, or even good or bad.
There are also two techniques to add gradients to the DataFrame:
- You can apply gradient styles either to the text or
- you can apply gradient styles to the background [2].
With the cmap parameter and vmin and vmax you can set the properties of the gradient. The cmap sets the used colormap and vmin and vmax set the relevant start and end values.
You can apply gradients to the text with the .text_gradient() method:
df.style.text_gradient(subset = ["D"],
cmap = "RdYlGn",
vmin = -1,
vmax = 1))](images/essential-techniques-to-style-pandas-dataframes-gradient-style-applies-to-text-of-column-d-image.webp)
Or you can apply gradients to the background with the .background_gradient() method:
df.style.background_gradient(subset = ["D"],
cmap = "RdYlGn",
vmin = -1,
vmax = 1))](images/essential-techniques-to-style-pandas-dataframes-gradient-style-applied-to-background-of-column-d.webp)
Bars
Another way of visualizing the relationship and order within a column or a row is to draw bars in the cell’s background [2].
Again, there are two essential techniques to utilize bars in your DataFrames:
- The straightforward application is to use a standard uni-colored bar.
- Or you can also create bi-colored bar charts from a mid-point.
For the standard bar chart, simple use the .bar() method as follows:
df.style.bar(subset = ["A"],
color = "lightblue",
vmin = 0))](images/essential-techniques-to-style-pandas-dataframes-bars-added-to-background-of-column-a-image-by.webp)
To create bi-colored bar charts set the alignment to mid and define colors for the lower and upper values. When using this method, I recommend combining it with some borders to increase the readbility.
df.style.bar(subset = ["D"],
align = "mid",
color = ["salmon", "lightgreen"])\
.set_properties(**{'border': '0.5px solid black'}))](images/essential-techniques-to-style-pandas-dataframes-positive-and-negative-value-bars-added-to.webp)
Custom Styling
If the built-in styling methods are not sufficient for your needs, you can write your own styling function and apply it to the DataFrame. You can either apply styling element-wise with the .applymap() method or column- or row-wise with the .apply() method [2].
A popular example of this is to display negative values of a DataFrame in red color as shown below:
def custom_styling(val):
color = "red" if val < 0 else "black"
return f"color: {color}"df.style.applymap(custom_styling))](images/essential-techniques-to-style-pandas-dataframes-highlight-negative-values-in-red-image-by-author.webp)
Export to Excel
If you need your styled DataFrame in Excel format, you can export it including its styling and formatting to an .xlsx file [3]. For this, you need to have the openpyxl package installed.
pip install openpyxlTo export the DataFrame, you can apply the styling and formatting to your DataFrame as usual and follow it with the .to_excel() method.
df.style.background_gradient(subset = ["D"],
cmap = "RdYlGn",
vmin = -1,
vmax = 1)\
.to_excel("styled.xlsx", engine = "openpyxl")Conclusion
The pandas DataFrame’s style attribute enables you to format and style a DataFrame to effectively communicate the insights from your data analysis. This article discussed essential techniques to style pandas DataFrames including how to set global display options, format and customize stylings, and even how to export your DataFrame to Excel format. There are many more styling and formatting options available on the pandas documentation.
For further experimentation, you can download or fork this article’s code including the example dataset from my related Kaggle Notebook.
Below I have summarized all tips in a cheat sheet:

References
[1] “pandas 1.4.2 documentation”, “Options and settings.” pandas.pydata.org. https://pandas.pydata.org/docs/user_guide/options.html (accessed June 13, 2022)
[2] “pandas 1.4.2 documentation”, “Style.” pandas.pydata.org. https://pandas.pydata.org/docs/reference/style.html (accessed June 16, 2022)
[3] “pandas 1.4.2 documentation”, “Table Visualization.” pandas.pydata.org. https://pandas.pydata.org/docs/user_guide/style.html (accessed June 16, 2022)
[4] “Python”, “string – Common string operations.” python.org. https://docs.python.org/3/library/string.html#formatspec (accessed June 13, 2022)
This blog was originally published on Towards Data Science on Jun 27, 2022 and moved to this site on Feb 1, 2026.