Limits and Ticks¶
Control the visible range and tick positions on your axes.
Setting Axis Limits¶
Use set_xlim and set_ylim:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(x, y)
ax.set_xlim((-3*np.pi, 3*np.pi))
ax.set_ylim((-2, 2))
plt.show()
Getting Current Limits¶
print(ax.get_xlim()) # Returns tuple: (-9.42..., 9.42...)
print(ax.get_ylim()) # Returns tuple: (-2.0, 2.0)
Setting Ticks¶
Use set_xticks and set_yticks:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(x, y)
ax.set_yticks(ticks=[-1, 0, 1])
ax.set_xticks(ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi])
plt.show()
Removing Ticks¶
Pass an empty tuple to remove all ticks:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(x, y)
ax.set_xticks(())
ax.set_yticks(())
plt.show()
Tick Labels¶
Set custom labels with the labels parameter:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(x, y)
ax.set_yticks(ticks=[-1, 0, 1])
ax.set_xticks(
ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi],
labels=["$-2\\pi$", "$-\\pi$", "0", "$\\pi$", "$2\\pi$"]
)
plt.show()
Minor Ticks¶
Add minor ticks with minor=True:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(x, y)
# Major ticks
ax.set_yticks(ticks=[-1, 0, 1])
ax.set_xticks(
ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi],
labels=["$-2\\pi$", "$-\\pi$", "0", "$\\pi$", "$2\\pi$"]
)
# Minor ticks (no labels)
ax.set_xticks(
ticks=np.linspace(-2*np.pi, 2*np.pi, 17),
labels=[],
minor=True
)
plt.show()
Getting Current Ticks¶
print(ax.get_xticks())
print(ax.get_yticks())
Complete Example with Spines¶
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(x, y)
# Set ticks and labels
ax.set_yticks(ticks=[-1, 0, 1])
ax.set_xticks(
ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi],
labels=["$-2\\pi$", "$-\\pi$", "0", "$\\pi$", "$2\\pi$"]
)
ax.set_xticks(
ticks=np.linspace(-2*np.pi, 2*np.pi, 17),
labels=[],
minor=True
)
# Move spines to origin
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
plt.show()
tick_params¶
Fine-tune tick appearance:
ax.tick_params(
axis='both', # 'x', 'y', or 'both'
which='major', # 'major', 'minor', or 'both'
direction='out', # 'in', 'out', or 'inout'
length=6, # Tick length
width=2, # Tick width
labelsize=10, # Label font size
rotation=45, # Label rotation
colors='blue' # Tick and label color
)
Key Takeaways¶
set_xlim()andset_ylim()control visible rangeset_xticks()andset_yticks()set tick positions- Use
labelsparameter for custom tick labels - Use
minor=Truefor minor ticks tick_params()provides fine-grained control- Empty tuple
()removes all ticks
Runnable Example: advanced_customization_tutorial.py¶
"""
Matplotlib Tutorial - Intermediate Level
========================================
Topic: Advanced Plot Customization and Styling
Author: Educational Python Course
Level: Intermediate
Learning Objectives:
-------------------
1. Master axes limits and ticks customization
2. Understand different coordinate systems
3. Add annotations and text
4. Customize grids and spines
5. Control legend appearance and positioning
6. Use colormaps effectively
7. Create publication-quality figures
Prerequisites:
-------------
- Completion of beginner tutorials
- Completion of plot() and hist() guides
"""
import matplotlib.pyplot as plt
import numpy as np
# ============================================================================
# SECTION 1: Customizing Axes Limits
# ============================================================================
if __name__ == "__main__":
"""
Controlling what portion of data is visible
"""
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Default limits (automatic)
axes[0, 0].plot(x, y)
axes[0, 0].set_title('Default limits (automatic)')
axes[0, 0].grid(True, alpha=0.3)
# Custom x-limits only
axes[0, 1].plot(x, y)
axes[0, 1].set_xlim(2, 8) # Show only x from 2 to 8
axes[0, 1].set_title('Custom xlim(2, 8)')
axes[0, 1].grid(True, alpha=0.3)
# Custom y-limits only
axes[1, 0].plot(x, y)
axes[1, 0].set_ylim(-2, 2) # Extend y-axis range
axes[1, 0].set_title('Custom ylim(-2, 2)')
axes[1, 0].grid(True, alpha=0.3)
# Both custom limits
axes[1, 1].plot(x, y)
axes[1, 1].set_xlim(3, 7)
axes[1, 1].set_ylim(-0.5, 0.5)
axes[1, 1].set_title('Custom xlim and ylim')
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# ============================================================================
# SECTION 2: Customizing Ticks and Tick Labels
# ============================================================================
"""
Ticks are the marks on the axes.
Tick labels are the text at each tick.
"""
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Default ticks
axes[0, 0].plot(x, y)
axes[0, 0].set_title('Default ticks')
axes[0, 0].grid(True, alpha=0.3)
# Custom tick positions
axes[0, 1].plot(x, y)
axes[0, 1].set_xticks([0, 2, 4, 6, 8, 10]) # Specific positions
axes[0, 1].set_yticks([-1, -0.5, 0, 0.5, 1])
axes[0, 1].set_title('Custom tick positions')
axes[0, 1].grid(True, alpha=0.3)
# Custom tick labels (different from positions)
axes[1, 0].plot(x, y)
axes[1, 0].set_xticks([0, np.pi, 2*np.pi, 3*np.pi])
axes[1, 0].set_xticklabels(['0', 'π', '2π', '3π'])
axes[1, 0].set_title('Custom tick labels')
axes[1, 0].grid(True, alpha=0.3)
# Rotated and formatted labels
axes[1, 1].plot(x, y)
axes[1, 1].set_xticks(np.arange(0, 11, 1))
axes[1, 1].set_xticklabels([f'x={i}' for i in range(11)], rotation=45, ha='right')
axes[1, 1].set_title('Rotated tick labels')
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# ============================================================================
# SECTION 3: Grid Customization
# ============================================================================
"""
Grids help read values from plots
"""
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# No grid
axes[0, 0].plot(x, y)
axes[0, 0].set_title('No grid')
# Basic grid
axes[0, 1].plot(x, y)
axes[0, 1].grid(True)
axes[0, 1].set_title('Basic grid')
# Customized grid (color, style, width)
axes[0, 2].plot(x, y)
axes[0, 2].grid(True, color='red', linestyle='--', linewidth=0.5, alpha=0.7)
axes[0, 2].set_title('Customized grid')
# Grid only on y-axis
axes[1, 0].plot(x, y)
axes[1, 0].grid(True, axis='y', alpha=0.5)
axes[1, 0].set_title('Grid on y-axis only')
# Grid with minor ticks
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')
# Grid behind plot
axes[1, 2].plot(x, y, linewidth=3, zorder=3) # zorder=3 brings line to front
axes[1, 2].grid(True, zorder=0, alpha=0.5) # zorder=0 puts grid in back
axes[1, 2].set_title('Grid behind line (zorder)')
plt.tight_layout()
plt.show()
# ============================================================================
# SECTION 4: Spine Customization
# ============================================================================
"""
Spines are the lines connecting the axis tick marks and noting the boundaries of the data area.
There are 4 spines: 'left', 'right', 'top', 'bottom'
"""
x = np.linspace(-5, 5, 100)
y = x ** 2
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# All spines visible (default)
axes[0, 0].plot(x, y)
axes[0, 0].set_title('All spines (default)')
# Hide top and right spines (common for scientific plots)
axes[0, 1].plot(x, y)
axes[0, 1].spines['top'].set_visible(False)
axes[0, 1].spines['right'].set_visible(False)
axes[0, 1].set_title('Top and right spines hidden')
# Customize spine position (centered at zero)
axes[1, 0].plot(x, y)
axes[1, 0].spines['left'].set_position('zero') # Move left spine to x=0
axes[1, 0].spines['bottom'].set_position('zero') # Move bottom spine to y=0
axes[1, 0].spines['top'].set_visible(False)
axes[1, 0].spines['right'].set_visible(False)
axes[1, 0].set_title('Spines at zero (classic math axes)')
# Customize spine colors and linewidth
axes[1, 1].plot(x, y)
for spine in axes[1, 1].spines.values():
spine.set_edgecolor('red')
spine.set_linewidth(2)
axes[1, 1].set_title('Custom spine color and width')
plt.tight_layout()
plt.show()
# ============================================================================
# SECTION 5: Adding Text and Annotations
# ============================================================================
"""
Text and annotations help explain features in plots
"""
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 6))
ax.plot(x, y, 'b-', linewidth=2)
# Simple text at data coordinates
ax.text(5, 0.5, 'Simple text', fontsize=14)
# Text with background box
ax.text(8, -0.5, 'Text with box', fontsize=12,
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
# Annotation with arrow pointing to data
ax.annotate('Local maximum',
xy=(np.pi/2, 1), # Point to annotate
xytext=(2, 1.3), # Text position
fontsize=12,
arrowprops=dict(arrowstyle='->', color='red', lw=2),
bbox=dict(boxstyle='round', facecolor='yellow', alpha=0.7))
# Another annotation
ax.annotate('Zero crossing',
xy=(np.pi, 0),
xytext=(4, -0.5),
fontsize=12,
arrowprops=dict(arrowstyle='->', color='green', lw=2))
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('sin(x)', fontsize=14)
ax.set_title('Adding Text and Annotations', fontsize=16)
ax.grid(True, alpha=0.3)
plt.show()
# ============================================================================
# SECTION 6: Advanced Legend Customization
# ============================================================================
"""
Legends explain what each line/marker represents
"""
x = np.linspace(0, 10, 100)
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Different legend locations
for i, loc in enumerate(['upper right', 'upper left', 'lower left', 'best']):
ax = axes[i // 2, i % 2]
ax.plot(x, np.sin(x), 'r-', label='sin(x)')
ax.plot(x, np.cos(x), 'b--', label='cos(x)')
ax.plot(x, np.sin(2*x), 'g:', label='sin(2x)')
ax.legend(loc=loc)
ax.set_title(f"loc='{loc}'")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# Highly customized legend
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, np.sin(x), 'r-', linewidth=2, label='sin(x)')
ax.plot(x, np.cos(x), 'b--', linewidth=2, label='cos(x)')
ax.plot(x, np.tan(x), 'g:', linewidth=2, label='tan(x)')
ax.legend(
loc='upper right',
fontsize=12,
frameon=True, # Draw frame
framealpha=0.9, # Frame transparency
shadow=True, # Add shadow
fancybox=True, # Rounded corners
title='Functions', # Legend title
title_fontsize=14
)
ax.set_ylim(-3, 3)
ax.set_title('Customized Legend', fontsize=16)
ax.grid(True, alpha=0.3)
plt.show()
# ============================================================================
# SECTION 7: Colormaps for Multiple Lines
# ============================================================================
"""
When plotting many lines, colormaps provide systematic colors
"""
x = np.linspace(0, 10, 100)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Manual colors (tedious for many lines)
colors = ['red', 'blue', 'green', 'orange', 'purple']
for i, color in enumerate(colors):
axes[0].plot(x, np.sin(x + i*0.5), color=color, label=f'Line {i}')
axes[0].set_title('Manual colors')
axes[0].legend()
# Using colormap (systematic and scalable)
n_lines = 10
colormap = plt.cm.viridis # Choose a colormap
colors = [colormap(i / n_lines) for i in range(n_lines)]
for i, color in enumerate(colors):
axes[1].plot(x, np.sin(x + i*0.3), color=color, label=f'Line {i}')
axes[1].set_title('Using colormap (viridis)')
axes[1].legend()
plt.tight_layout()
plt.show()
# ============================================================================
# SECTION 8: Figure Size and DPI
# ============================================================================
"""
Control figure dimensions and resolution
"""
x = np.linspace(0, 10, 100)
y = np.sin(x)
# Small figure, low DPI
fig1, ax1 = plt.subplots(figsize=(4, 3), dpi=50)
ax1.plot(x, y)
ax1.set_title('4"×3", 50 DPI (looks pixelated)')
plt.show()
# Large figure, high DPI
fig2, ax2 = plt.subplots(figsize=(10, 6), dpi=150)
ax2.plot(x, y, linewidth=2)
ax2.set_xlabel('x', fontsize=14)
ax2.set_ylabel('sin(x)', fontsize=14)
ax2.set_title('10"×6", 150 DPI (sharp and clear)', fontsize=16)
ax2.grid(True, alpha=0.3)
plt.show()
print("Figure size = (width, height) in inches")
print("DPI = dots per inch (resolution)")
print("Pixel dimensions = (width × DPI, height × DPI)")
print("Example: (10, 6) at 150 DPI = 1500×900 pixels")
# ============================================================================
# SECTION 9: Publication-Quality Figure Example
# ============================================================================
"""
Combining everything for a professional-looking plot
"""
# Generate data
x = np.linspace(0, 10, 200)
y1 = np.sin(x)
y2 = np.sin(x) * np.exp(-x/5)
y3 = np.cos(x) * np.exp(-x/5)
# Create figure with specific size and DPI
fig, ax = plt.subplots(figsize=(10, 6), dpi=120)
# Plot with careful styling
line1, = ax.plot(x, y1, color='#1f77b4', linestyle='-', linewidth=2.5,
label='sin(x)', alpha=0.9)
line2, = ax.plot(x, y2, color='#ff7f0e', linestyle='--', linewidth=2.5,
label='sin(x)·exp(-x/5)', alpha=0.9)
line3, = ax.plot(x, y3, color='#2ca02c', linestyle='-.', linewidth=2.5,
label='cos(x)·exp(-x/5)', alpha=0.9)
# Customize axes
ax.set_xlabel('x', fontsize=14, fontweight='bold')
ax.set_ylabel('y', fontsize=14, fontweight='bold')
ax.set_title('Damped Oscillations', fontsize=16, fontweight='bold', pad=20)
# Set limits
ax.set_xlim(0, 10)
ax.set_ylim(-1.2, 1.2)
# Customize ticks
ax.tick_params(axis='both', which='major', labelsize=12, length=6, width=1.5)
ax.minorticks_on()
ax.tick_params(axis='both', which='minor', length=3, width=1)
# Grid
ax.grid(True, which='major', linestyle='-', linewidth=0.8, alpha=0.3)
ax.grid(True, which='minor', linestyle=':', linewidth=0.5, alpha=0.2)
# Customize spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_linewidth(1.5)
ax.spines['bottom'].set_linewidth(1.5)
# Legend
ax.legend(loc='upper right', fontsize=12, framealpha=0.9,
shadow=True, fancybox=True)
# Tight layout to prevent label cutoff
plt.tight_layout()
plt.show()
# ============================================================================
# KEY TAKEAWAYS
# ============================================================================
"""
1. Axes limits: set_xlim(), set_ylim()
2. Ticks: set_xticks(), set_yticks(), set_xticklabels(), set_yticklabels()
3. Grid: grid(True/False), customize with color, linestyle, linewidth, alpha
4. Spines: 4 spines (top, bottom, left, right), can hide or reposition
5. Text: text() for simple text, annotate() for text with arrows
6. Legend: customize location, frame, font, shadow
7. Colormaps: systematic colors for many lines
8. Figure size: figsize=(width, height) in inches
9. DPI: resolution (dots per inch), higher = sharper
10. Publication quality: careful attention to all visual elements
Common Customization Workflow:
-----------------------------
1. Plot data with clear line styles
2. Add labels (xlabel, ylabel, title) with appropriate font sizes
3. Set limits if needed
4. Add grid with alpha < 0.5 for subtlety
5. Hide top/right spines for cleaner look
6. Add legend with framealpha and shadow
7. Set figure size and DPI for intended output
8. Use tight_layout() to prevent cutoff
9. Save with savefig() before show()
"""