How to Add Gridlines in Matplotlib
Gridlines transform data visualizations from abstract shapes into readable, interpretable information. They provide reference points that help viewers accurately estimate values and compare data...
Key Insights
- The
grid()function is your primary tool for adding gridlines, with parameters for color, style, width, and transparency that dramatically affect readability - Control grid visibility per axis using the
axisparameter, and toggle between major/minor grids with thewhichparameter for precise customization - Always use
ax.set_axisbelow(True)when combining grids with bar charts or filled plots to prevent gridlines from obscuring your data
Introduction & Basic Grid Setup
Gridlines transform data visualizations from abstract shapes into readable, interpretable information. They provide reference points that help viewers accurately estimate values and compare data points across your plot. Without gridlines, users must mentally interpolate between axis labels—a task that becomes increasingly difficult as plots grow more complex.
Matplotlib’s grid() function is straightforward. Call it after creating your plot, and gridlines appear. Here’s the fundamental difference:
import matplotlib.pyplot as plt
import numpy as np
# Generate sample data
x = np.linspace(0, 10, 100)
y = np.sin(x)
# Create figure with two subplots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
# Plot without grid
ax1.plot(x, y)
ax1.set_title('Without Grid')
ax1.set_xlabel('X Values')
ax1.set_ylabel('Y Values')
# Plot with grid
ax2.plot(x, y)
ax2.grid(True)
ax2.set_title('With Grid')
ax2.set_xlabel('X Values')
ax2.set_ylabel('Y Values')
plt.tight_layout()
plt.show()
The difference is immediately apparent. The gridded plot allows viewers to quickly identify that the sine wave peaks at approximately 1.0 and troughs at -1.0, while the non-gridded version requires careful eye tracking to the y-axis.
Customizing Grid Appearance
Default gridlines work, but they’re rarely optimal. Matplotlib provides extensive styling options through the grid() function’s parameters. The four critical parameters are color, linestyle, linewidth, and alpha.
The alpha parameter is particularly important—it controls transparency. Heavy, opaque gridlines compete with your data for attention. Subtle, semi-transparent grids guide the eye without dominating the visual hierarchy.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 50)
y1 = np.exp(x/10)
y2 = x**2
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Default grid
axes[0, 0].plot(x, y1)
axes[0, 0].grid(True)
axes[0, 0].set_title('Default Grid')
# Custom color and style
axes[0, 1].plot(x, y1)
axes[0, 1].grid(color='gray', linestyle='--', linewidth=0.5)
axes[0, 1].set_title('Dashed Gray Grid')
# High transparency
axes[1, 0].plot(x, y1)
axes[1, 0].grid(color='blue', linestyle='-', linewidth=1, alpha=0.3)
axes[1, 0].set_title('Semi-Transparent Blue Grid')
# Dotted style with custom width
axes[1, 1].plot(x, y1)
axes[1, 1].grid(color='red', linestyle=':', linewidth=1.5, alpha=0.6)
axes[1, 1].set_title('Dotted Red Grid')
plt.tight_layout()
plt.show()
My recommendation: start with color='gray', linestyle='--', linewidth=0.5, and alpha=0.7. Adjust from there based on your data density and plot background color.
Controlling Grid Axis and Visibility
Not every plot needs gridlines on both axes. Time-series data often benefits from vertical gridlines marking time intervals, while horizontal grids might clutter the visualization. The axis parameter gives you control: 'x', 'y', or 'both'.
The which parameter determines whether you’re styling major grids (aligned with labeled ticks), minor grids (subdivisions between major ticks), or both.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x) * np.exp(-x/10)
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# X-axis only
axes[0, 0].plot(x, y)
axes[0, 0].grid(True, axis='x')
axes[0, 0].set_title('X-Axis Grid Only')
# Y-axis only
axes[0, 1].plot(x, y)
axes[0, 1].grid(True, axis='y')
axes[0, 1].set_title('Y-Axis Grid Only')
# Both axes (default)
axes[1, 0].plot(x, y)
axes[1, 0].grid(True, axis='both')
axes[1, 0].set_title('Both Axes Grid')
# Major and minor grids
axes[1, 1].plot(x, y)
axes[1, 1].minorticks_on()
axes[1, 1].grid(True, which='major', linestyle='-', linewidth=0.8, alpha=0.7)
axes[1, 1].grid(True, which='minor', linestyle=':', linewidth=0.5, alpha=0.4)
axes[1, 1].set_title('Major and Minor Grids')
plt.tight_layout()
plt.show()
Note that minor grids require calling minorticks_on() first. You can then style major and minor grids independently by calling grid() twice with different which parameters.
Working with Subplots and Multiple Axes
Complex figures often contain multiple subplots, each potentially requiring different grid configurations. When working with subplots, apply grid() to individual axes objects rather than using plt.grid().
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Subplot 1: Line plot with subtle grid
x = np.linspace(0, 10, 100)
y = np.sin(x)
axes[0, 0].plot(x, y)
axes[0, 0].grid(True, alpha=0.3)
axes[0, 0].set_title('Line Plot - Subtle Grid')
# Subplot 2: Scatter plot with y-axis grid only
x_scatter = np.random.randn(100)
y_scatter = np.random.randn(100)
axes[0, 1].scatter(x_scatter, y_scatter, alpha=0.6)
axes[0, 1].grid(True, axis='y', linestyle='--', alpha=0.5)
axes[0, 1].set_title('Scatter - Y-Axis Grid Only')
# Subplot 3: Bar chart (grid will be addressed in next section)
categories = ['A', 'B', 'C', 'D']
values = [23, 45, 56, 78]
axes[1, 0].bar(categories, values)
axes[1, 0].grid(True, axis='y', alpha=0.4)
axes[1, 0].set_title('Bar Chart - Y-Axis Grid')
# Subplot 4: Multiple y-axes with different grids
ax1 = axes[1, 1]
ax2 = ax1.twinx()
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x), 'b-', label='sin(x)')
ax2.plot(x, np.exp(x/5), 'r-', label='exp(x/5)')
ax1.grid(True, color='blue', alpha=0.3)
ax1.set_ylabel('sin(x)', color='b')
ax2.set_ylabel('exp(x/5)', color='r')
ax1.set_title('Dual Y-Axes')
plt.tight_layout()
plt.show()
When using secondary axes (twinx() or twiny()), apply grids to the primary axis only. Gridlines from both axes will overlap and create visual confusion.
Advanced Grid Customization with Axis Objects
The most common gridline mistake is placing them above your data. Bar charts, area plots, and heatmaps become significantly less readable when gridlines cut through filled regions. The solution is set_axisbelow(True).
You can also customize major and minor tick positions using tick locators, giving you precise control over grid density.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, AutoMinorLocator
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
# Bar chart with grid behind bars
categories = ['Q1', 'Q2', 'Q3', 'Q4']
values = [23, 45, 56, 78]
ax1.bar(categories, values, color='steelblue', alpha=0.8)
ax1.set_axisbelow(True) # Critical for bar charts
ax1.grid(True, axis='y', linestyle='--', alpha=0.6)
ax1.set_title('Grid Behind Bars')
ax1.set_ylabel('Revenue (Millions)')
# Custom tick spacing with major/minor grids
x = np.linspace(0, 100, 200)
y = np.sin(x/10) * 50 + 50
ax2.plot(x, y, linewidth=2)
# Set major ticks every 20 units, minor every 5
ax2.xaxis.set_major_locator(MultipleLocator(20))
ax2.xaxis.set_minor_locator(MultipleLocator(5))
ax2.yaxis.set_major_locator(MultipleLocator(25))
ax2.yaxis.set_minor_locator(AutoMinorLocator(5))
# Style grids differently
ax2.grid(True, which='major', linestyle='-', linewidth=0.8, alpha=0.6)
ax2.grid(True, which='minor', linestyle=':', linewidth=0.5, alpha=0.3)
ax2.set_title('Custom Tick Spacing')
ax2.set_xlabel('Time (seconds)')
ax2.set_ylabel('Value')
plt.tight_layout()
plt.show()
The set_axisbelow(True) call ensures gridlines render in the background layer. Without it, gridlines appear on top of bars, making values harder to read.
Practical Use Cases & Best Practices
Gridlines improve readability, but they’re not universally necessary. Use them when viewers need to extract specific values or compare magnitudes across multiple data points. Skip them for simple plots where trends matter more than exact values, or when your plot is already visually dense.
Consider accessibility: users with visual impairments benefit from higher contrast gridlines, while users with certain cognitive differences may find dense grids distracting. Test your visualizations with diverse audiences.
Common pitfalls to avoid:
- Too many gridlines: More isn’t better. Dense grids create visual noise.
- Opaque gridlines: Always use transparency (alpha < 1.0).
- Gridlines over data: Use
set_axisbelow(True)for filled plots. - Inconsistent styling: Maintain consistent grid appearance across related plots.
Here’s a practical before-and-after example with a busy scatter plot:
import matplotlib.pyplot as plt
import numpy as np
# Generate dense scatter data
np.random.seed(42)
x = np.random.randn(500)
y = 2 * x + np.random.randn(500)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
# Before: No grid on dense data
ax1.scatter(x, y, alpha=0.5, s=30)
ax1.set_title('Without Grid - Harder to Read Values')
ax1.set_xlabel('X Variable')
ax1.set_ylabel('Y Variable')
# After: Subtle grid improves readability
ax2.scatter(x, y, alpha=0.5, s=30)
ax2.grid(True, linestyle='--', linewidth=0.5, alpha=0.4, color='gray')
ax2.set_axisbelow(True)
ax2.set_title('With Subtle Grid - Easier Value Estimation')
ax2.set_xlabel('X Variable')
ax2.set_ylabel('Y Variable')
plt.tight_layout()
plt.show()
The gridded version allows viewers to quickly estimate that most points fall between -2 and 2 on both axes, and to identify outliers more accurately.
Start with subtle grids and increase visibility only if your audience struggles with value estimation. Your goal is to enhance data interpretation, not to demonstrate Matplotlib’s styling capabilities.