When working with data visualization in Python, Matplotlib remains one of my go-to libraries. I’ve learned that creating clear, professional-looking scatter plots is essential, especially when you want your insights to shine without clutter.
One common challenge I frequently encounter is managing subplot layouts. Scatter plots, in particular, can suffer from overlapping labels, cut-off titles, or cramped axes when multiple plots share a figure. That’s where Matplotlib’s tight_layout function becomes a lifesaver.
In this article, I’ll share everything I know about using tight_layout with scatter plots in Python. I’ll cover all possible methods, practical tips, and share full working code examples that you can easily adapt for your own projects.
Use tight_layout with Matplotlib Scatter Plots
When you create scatter plots in Matplotlib, especially multiple subplots, the default spacing can cause axis labels, titles, or tick labels to overlap or get clipped. This results in a messy, unreadable visualization.
From my experience, tight_layout automatically adjusts subplot parameters to give enough padding between plots and ensures all labels are visible. It saves you from manually tweaking margins and spacing, which can be tedious and error-prone.
Method 1: Use plt.tight_layout() for Simple Scatter Plots
The easiest way to fix layout issues is to call plt.tight_layout() right before displaying or saving your figure.
Here’s a simple example where I plot two scatter plots side-by-side and use tight_layout to avoid overlap:
import matplotlib.pyplot as plt
import numpy as np
# Sample data for two groups in the USA (e.g., Age vs Income)
age_group1 = np.random.normal(30, 5, 100)
income_group1 = np.random.normal(60000, 15000, 100)
age_group2 = np.random.normal(45, 7, 100)
income_group2 = np.random.normal(75000, 20000, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.scatter(age_group1, income_group1, color='blue', alpha=0.6)
ax1.set_title('Group 1: Age vs Income')
ax1.set_xlabel('Age (years)')
ax1.set_ylabel('Annual Income ($)')
ax2.scatter(age_group2, income_group2, color='green', alpha=0.6)
ax2.set_title('Group 2: Age vs Income')
ax2.set_xlabel('Age (years)')
ax2.set_ylabel('Annual Income ($)')
# Apply tight_layout to fix spacing issues
plt.tight_layout()
plt.show()You can refer to the screenshot below to see the output.

Calling plt.tight_layout() here automatically adjusts the spacing so axis labels and titles don’t overlap or get cut off.
Method 2: Use fig.tight_layout() for More Control
If you are working with multiple figures or want to be specific, you can call tight_layout on the figure object itself.
This approach helps when you have multiple figures open or want to avoid confusion about which figure to adjust.
Here’s how I use it:
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
for i, ax in enumerate(axs.flat):
x = np.random.normal(50, 10, 100)
y = np.random.normal(100000, 25000, 100)
ax.scatter(x, y, alpha=0.5)
ax.set_title(f'Scatter Plot {i+1}')
ax.set_xlabel('Age')
ax.set_ylabel('Income')
# Call tight_layout on the figure object
fig.tight_layout()
plt.show()You can refer to the screenshot below to see the output.

This method gives me a clean layout across all subplots without manually adjusting spacing.
Method 3: Use tight_layout with Padding and Rect Parameters
Sometimes, the default tight_layout() spacing isn’t enough, or you want to add extra padding.
You can tweak the padding between subplots using the pad argument or reserve space for titles and labels using rect.
Example:
fig, axs = plt.subplots(2, 1, figsize=(8, 10))
for i, ax in enumerate(axs):
x = np.random.normal(40 + i*5, 8, 100)
y = np.random.normal(70000 + i*10000, 15000, 100)
ax.scatter(x, y, alpha=0.7)
ax.set_title(f'Group {i+1} Scatter')
ax.set_xlabel('Age')
ax.set_ylabel('Income')
# Add extra padding between subplots
fig.tight_layout(pad=3.0, rect=[0, 0, 1, 0.95])
# Add a main title above all subplots
fig.suptitle('Age vs Income Scatter Plots for US Groups', fontsize=16)
plt.show()You can refer to the screenshot below to see the output.

In this example, I increased the padding to 3.0 and reserved space at the top for a main title using rect.
Method 4: Combine tight_layout with subplots_adjust
Sometimes, you want to use tight_layout but still need to fine-tune spacing manually. You can call tight_layout first, then use plt.subplots_adjust() to tweak margins.
Example:
fig, axs = plt.subplots(1, 3, figsize=(15, 5))
for i, ax in enumerate(axs):
x = np.random.normal(35 + i*4, 6, 100)
y = np.random.normal(65000 + i*12000, 18000, 100)
ax.scatter(x, y, alpha=0.6)
ax.set_title(f'Group {i+1}')
ax.set_xlabel('Age')
ax.set_ylabel('Income')
fig.tight_layout()
# Manually adjust bottom margin to avoid label cutoff
plt.subplots_adjust(bottom=0.15)
plt.show()You can refer to the screenshot below to see the output.

This approach gives me the best of both worlds: automatic layout adjustment and manual control.
Method 5: Use bbox_inches=’tight’ When Saving Figures
When saving your scatter plots, sometimes labels or titles get clipped in the saved image.
I always recommend combining tight_layout() with the bbox_inches=’tight’ parameter in savefig() to avoid this.
Example:
fig, ax = plt.subplots(figsize=(8, 6))
x = np.random.normal(38, 7, 150)
y = np.random.normal(68000, 16000, 150)
ax.scatter(x, y, c='purple', alpha=0.5)
ax.set_title('Scatter Plot: Age vs Income')
ax.set_xlabel('Age')
ax.set_ylabel('Income')
fig.tight_layout()
# Save figure with tight bounding box
fig.savefig('scatter_plot_tight_layout.png', bbox_inches='tight')This way, the saved image includes all labels and titles perfectly.
Tips from My Experience
- Always call tight_layout() before plt.show() or savefig().
- If your plots have legends outside the axes, tight_layout might not adjust them well. Use bbox_extra_artists or manually adjust margins.
- For very complex layouts, consider GridSpec with manual spacing combined with tight_layout.
- When working with multiple figures, be explicit by calling fig.tight_layout() rather than plt.tight_layout() to avoid confusion.
- Use plt.subplots() to create scatter plot grids instead of multiple plt.figure() calls for easier layout management.
Mastering tight_layout in Matplotlib has greatly improved my Python data visualizations. It saves me hours of manual tweaking and helps me deliver clean, professional scatter plots every time.
Try the methods above in your next project, and you’ll see how much easier it is to create beautiful, readable scatter plots with Python.
If you want to dive deeper, explore Matplotlib’s GridSpec and advanced layout options. But for most use cases, tight_layout combined with these tips will be more than enough.
Related Python Guides you may like:
- Use Matplotlib tick_params Grid Alpha in Python
- Matplotlib tight_layout wspace and hspace in Python
- Matplotlib Tight_Layout for Python Subplots
- How to Use tight_layout and bbox_inches in Matplotlib

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.