Python Pandas: How to Apply Custom Row Formatting
Row formatting is essential when presenting tabular data, allowing you to highlight outliers, visualize trends, or simply improve readability. While Python's standard output can be formatted with strings, the most powerful row formatting capabilities exist within the Pandas library for data analysis.
This guide focuses on using the Pandas Styler object to apply custom CSS styling to rows based on specific data conditions.
Understanding the Pandas Styler
Pandas DataFrames have a .style property that returns a Styler object. This object allows you to apply CSS styling to the rendered HTML representation of the DataFrame (commonly used in Jupyter Notebooks or when exporting to HTML/Excel).
The key method is .apply(), which passes data (either column-wise or row-wise) to a styling function.
Styles usually do not affect the console output (print(df)). They are visualized in rich environments like Jupyter Notebooks, VS Code Data Viewer, or HTML exports.
Method 1: Formatting Rows Based on Conditions
To style an entire row based on the value of a specific column, you must use df.style.apply(func, axis=1). The axis=1 ensures the function iterates over rows, not columns.
The Logic
The styling function must return a list of CSS strings exactly matching the number of columns in the row.
Dealing with Shape Mismatch Errors
A common mistake is returning a single string or a list of the wrong length.
import pandas as pd
import numpy as np
# Sample Data
data = {
'Employee': ['Alice', 'Bob', 'Charlie', 'David'],
'Department': ['Sales', 'IT', 'Sales', 'HR'],
'Performance': [95, 70, 88, 60]
}
df = pd.DataFrame(data)
# ⛔️ Incorrect: Returning a single string causes a ValueError
# Pandas expects a list of styles for every cell in the row
def incorrect_highlight(row):
if row['Performance'] < 65:
return 'background-color: red' # Error!
return ''
try:
df.style.apply(incorrect_highlight, axis=1)
except Exception as e:
print(f"Error: {e}")
Output:
Error: Function returned 'str' object, but expected a list-like object of length 3
Correct Approach
You must generate a list of strings, one for each column.
import pandas as pd
import numpy as np
# Sample Data
data = {
'Employee': ['Alice', 'Bob', 'Charlie', 'David'],
'Department': ['Sales', 'IT', 'Sales', 'HR'],
'Performance': [95, 70, 88, 60]
}
df = pd.DataFrame(data)
# ✅ Correct: Return a list of CSS strings matching row length
def highlight_low_performance(row):
# Check condition
if row['Performance'] < 65:
# Return red background for ALL columns in this row
return ['background-color: #ffcccc; color: black'] * len(row)
elif row['Performance'] > 90:
# Return green background for ALL columns
return ['background-color: #ccffcc; color: black'] * len(row)
else:
# Return default (empty string) for ALL columns
return [''] * len(row)
# Apply style row-wise (axis=1)
styled_df = df.style.apply(highlight_low_performance, axis=1)
# In a Jupyter notebook, you would simply type 'styled_df' to render it.
print("Styling applied successfully.")
Method 2: Formatting Specific Cells within Rows
Sometimes you want to analyze a row, but only highlight specific columns (e.g., if a student fails math, highlight only the math grade, not their name).
import pandas as pd
import numpy as np
# Sample Data
data = {
'Employee': ['Alice', 'Bob', 'Charlie', 'David'],
'Department': ['Sales', 'IT', 'Sales', 'HR'],
'Performance': [95, 70, 88, 60]
}
df = pd.DataFrame(data)
def highlight_specific_cells(row):
# Initialize empty styles for all columns
styles = [''] * len(row)
# Logic: If Department is 'Sales', make the Employee name bold
if row['Department'] == 'Sales':
# Find index of 'Employee' column
idx = row.index.get_loc('Employee')
styles[idx] = 'font-weight: bold; color: blue'
return styles
# ✅ Correct: Apply logic row-wise
styled_df_specific = df.style.apply(highlight_specific_cells, axis=1)
You can chain multiple styles together:
df.style.apply(style_func_1, axis=1).apply(style_func_2, axis=1)
Method 3: Exporting Formatted Data
Styles applied via Pandas are not saved in CSV files (which are plain text). To preserve row formatting, you must export to Excel or HTML.
# ✅ Correct: Exporting to Excel with styles
# Requires 'openpyxl' library installed
try:
styled_df.to_excel('styled_report.xlsx', engine='openpyxl', index=False)
print("Exported to styled_report.xlsx")
except ImportError:
print("Please install openpyxl: pip install openpyxl")
# ✅ Correct: Exporting to HTML
html_output = styled_df.to_html()
with open("report.html", "w") as f:
f.write(html_output)
Conclusion
Custom row formatting in Python relies heavily on the Pandas Styler object.
- Use
df.style.apply(func, axis=1)to process data row-by-row. - Match Dimensions: Your styling function must return a list of CSS strings equal to the number of columns.
- Chain Methods: Combine multiple styling functions for complex visualizations.
- Export Properly: Save as Excel or HTML to retain the visual formatting.