Skip to main content

Python Pandas: How to Apply Custom Formats to Table Rows (in Jupyter Notebook)

In Python data analysis, presenting raw data can often be overwhelming. Visual cues, such as highlighting specific rows based on criteria (e.g., high risk, failing grades, or outliers), significantly improve readability. The primary tool for this in the Python ecosystem is the Pandas Styler API.

This guide explains how to apply custom CSS styles to DataFrame rows based on data conditions using pandas.DataFrame.style.

Understanding the Pandas Styler

Pandas DataFrames have a .style property that returns a Styler object. This object renders the data as HTML (for Jupyter Notebooks or web reports) and allows you to apply CSS.

To style rows, we use the .apply() method with axis=1.

  • axis=0: Apply function column-wise.
  • axis=1: Apply function row-wise (this is what we want).
  • axis=None: Apply function element-wise (entire table).
note

The styling function you write must accept a Series (the row) and return a list of strings (the CSS styles) of the exact same length as the row.

Method 1: Conditional Row Highlighting

The most common use case is highlighting a row if a specific column meets a condition.

Step-by-Step Implementation:

  1. Define a function that takes a row (Series).
  2. Check the condition on a specific column.
  3. Return a list of CSS strings matching the row length.
import pandas as pd

# Create sample data
data = {
'Project': ['Alpha', 'Beta', 'Gamma', 'Delta'],
'Status': ['Complete', 'In Progress', 'Failed', 'Complete'],
'Budget': [10000, 25000, 5000, 12000]
}
df = pd.DataFrame(data)

# ✅ Define the styling function
def highlight_failed_rows(row):
# Check if the 'Status' of this row is 'Failed'
if row['Status'] == 'Failed':
# Return a list of red background styles for every cell in the row
return ['background-color: #ffcccc; color: red'] * len(row)
else:
# Return a list of empty styles for normal rows
return [''] * len(row)

# Apply the style row-wise (axis=1)
styled_df = df.style.apply(highlight_failed_rows, axis=1)

# In a Jupyter Notebook, simply typing 'styled_df' renders the colored table
display(styled_df)

Result: The row for Project "Gamma" will have a light red background and red text.

Method 2: Multi-Condition (Gradient) Styling

You can apply complex logic, such as a traffic light system, by expanding the if/elif/else logic within your styling function.

import pandas as pd

df = pd.DataFrame({
'Student': ['Alice', 'Bob', 'Charlie', 'David'],
'Score': [95, 55, 75, 88]
})

def grade_traffic_light(row):
score = row['Score']

# Define CSS strings
green = 'background-color: #d4edda; color: #155724' # Pass
yellow = 'background-color: #fff3cd; color: #856404' # Average
red = 'background-color: #f8d7da; color: #721c24' # Fail
default = ''

# Logic
if score >= 90:
style = green
elif score >= 60:
style = yellow
else:
style = red

# Apply this style to all columns in the row
return [style] * len(row)

# ✅ Apply complex logic
styled_report = df.style.apply(grade_traffic_light, axis=1)
display(styled_report)

Common Error: Shape Mismatch

A frequent ValueError occurs when the styling function returns a single string instead of a list, or a list of the wrong length. Pandas expects the returned styles to map 1-to-1 with the cells in that row.

Example of Error

import pandas as pd

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})

def broken_highlighter(row):
if row['A'] > 1:
# ⛔️ Incorrect: Returning a single string instead of a list
return 'background-color: yellow'
return ''

try:
df.style.apply(broken_highlighter, axis=1).to_html()
except Exception as e:
print(f"Error: {e}")

Output:

Error: Function returned scalar: 'background-color: yellow'
... expecting list-like with length 2

Solution

Ensure the return value is a list multiplied by len(row).

def fixed_highlighter(row):
if row['A'] > 1:
# ✅ Correct: Create a list of styles matching row length
return ['background-color: yellow'] * len(row)
# ✅ Correct: Even the "no style" return must be a list
return [''] * len(row)

# This works successfully
html_output = df.style.apply(fixed_highlighter, axis=1).to_html()
print("Styling applied successfully.")
warning

When using axis=1, your function iterates over rows. If your DataFrame has 5 columns, your function must return a list of exactly 5 strings for every single row processed.

Conclusion

To apply custom formats to table rows in Python Pandas:

  1. Define a Function: Create a Python function that accepts a row (Series).
  2. Logic: Inside the function, check your data conditions (e.g., if row['val'] > 0).
  3. Return Format: Return a list of CSS strings (['style: val'] * len(row)).
  4. Apply: Use df.style.apply(func, axis=1) to render the changes.

This technique allows you to export professional, readable HTML tables or Excel sheets directly from your data analysis scripts.