0
# adjustText
1
2
A Python library for iteratively adjusting text position in matplotlib plots to minimize overlaps between text annotations and data points. Inspired by the ggrepel R package, adjustText implements an intelligent algorithm that automatically repositions matplotlib text labels to improve plot readability without manual intervention.
3
4
## Package Information
5
6
- **Package Name**: adjustText
7
- **Language**: Python
8
- **Installation**: `pip install adjustText`
9
- **Dependencies**: numpy, matplotlib, scipy
10
11
## Core Imports
12
13
```python
14
from adjustText import adjust_text
15
```
16
17
Import with version:
18
19
```python
20
from adjustText import adjust_text, __version__
21
```
22
23
Import utility functions:
24
25
```python
26
from adjustText import overlap_intervals
27
```
28
29
Alternative import:
30
31
```python
32
import adjustText
33
# Access: adjustText.adjust_text()
34
```
35
36
## Basic Usage
37
38
```python
39
import matplotlib.pyplot as plt
40
import numpy as np
41
from adjustText import adjust_text
42
43
# Create sample data
44
x = np.random.randn(20)
45
y = np.random.randn(20)
46
47
# Create scatter plot
48
fig, ax = plt.subplots()
49
ax.scatter(x, y)
50
51
# Create text labels
52
texts = []
53
for i, (xi, yi) in enumerate(zip(x, y)):
54
texts.append(ax.text(xi, yi, f'Point {i}', fontsize=9))
55
56
# Automatically adjust text positions to avoid overlaps
57
adjust_text(texts, ax=ax)
58
59
plt.show()
60
```
61
62
Advanced usage with additional objects to avoid:
63
64
```python
65
import matplotlib.pyplot as plt
66
import numpy as np
67
from adjustText import adjust_text
68
69
# Create data and plot
70
x = np.random.randn(15)
71
y = np.random.randn(15)
72
73
fig, ax = plt.subplots(figsize=(10, 8))
74
scatter = ax.scatter(x, y, s=100, c='red', alpha=0.7)
75
76
# Add some additional objects to avoid
77
objects = [scatter]
78
79
# Create text labels
80
texts = []
81
for i, (xi, yi) in enumerate(zip(x, y)):
82
texts.append(ax.text(xi, yi, f'Label {i}', fontsize=10))
83
84
# Adjust text positions avoiding both other texts and scatter points
85
adjust_text(texts,
86
objects=objects,
87
expand=(1.1, 1.3),
88
force_text=(0.05, 0.25),
89
force_static=(0.02, 0.25),
90
ax=ax)
91
92
plt.show()
93
```
94
95
## Capabilities
96
97
### Text Position Adjustment
98
99
Automatically adjusts the positions of matplotlib text objects to minimize overlaps using an iterative physics-based algorithm.
100
101
```python { .api }
102
def adjust_text(
103
texts,
104
x=None,
105
y=None,
106
objects=None,
107
target_x=None,
108
target_y=None,
109
avoid_self=True,
110
prevent_crossings=True,
111
force_text=(0.1, 0.2),
112
force_static=(0.1, 0.2),
113
force_pull=(0.01, 0.01),
114
force_explode=(0.1, 0.5),
115
pull_threshold=10,
116
expand=(1.05, 1.2),
117
max_move=(10, 10),
118
explode_radius="auto",
119
ensure_inside_axes=True,
120
expand_axes=False,
121
only_move={"text": "xy", "static": "xy", "explode": "xy", "pull": "xy"},
122
ax=None,
123
min_arrow_len=5,
124
time_lim=None,
125
iter_lim=None,
126
*args,
127
**kwargs
128
):
129
"""
130
Iteratively adjusts the locations of texts to minimize overlaps.
131
132
Must be called after all plotting is complete, as the function needs
133
the final axes dimensions to work correctly.
134
135
Parameters:
136
- texts: List of matplotlib.text.Text objects to adjust
137
- x, y: Array-like coordinates of points to repel from (optional, with avoid_self=True original text positions are added)
138
- objects: List of matplotlib objects to avoid or PathCollection/list of Bbox objects (must have get_window_extent() method)
139
- target_x, target_y: Array-like coordinates to connect adjusted texts to (optional, defaults to original text positions)
140
- avoid_self: Whether to repel texts from their original positions (bool, default True)
141
- prevent_crossings: Whether to prevent arrows from crossing each other (bool, default True, experimental)
142
- force_text: Multiplier for text-text repulsion forces (tuple[float, float] | float, default (0.1, 0.2))
143
- force_static: Multiplier for text-object repulsion forces (tuple[float, float] | float, default (0.1, 0.2))
144
- force_pull: Multiplier for pull-back-to-origin forces (tuple[float, float] | float, default (0.01, 0.01))
145
- force_explode: Multiplier for initial explosion forces (tuple[float, float] | float, default (0.1, 0.5))
146
- pull_threshold: Distance threshold for pull-back forces in display units (float, default 10)
147
- expand: Multipliers for expanding text bounding boxes (tuple[float, float], default (1.05, 1.2))
148
- max_move: Maximum movement per iteration in display units (tuple[int, int] | int | None, default (10, 10))
149
- explode_radius: Initial explosion radius in display units or "auto" (str | float, default "auto")
150
- ensure_inside_axes: Whether to keep texts inside axes boundaries (bool, default True)
151
- expand_axes: Whether to expand axes to fit all texts (bool, default False)
152
- only_move: Movement restrictions per force type (dict, default {"text": "xy", "static": "xy", "explode": "xy", "pull": "xy"})
153
- ax: Matplotlib axes object (matplotlib.axes.Axes | None, uses plt.gca() if None)
154
- min_arrow_len: Minimum arrow length to draw in display units (float, default 5)
155
- time_lim: Maximum time for adjustment in seconds (float | None, default None)
156
- iter_lim: Maximum number of iterations (int | None, default None)
157
- args, kwargs: Additional arguments passed to FancyArrowPatch for arrow styling
158
159
Returns:
160
- texts: List of adjusted text objects (list)
161
- patches: List of arrow patches connecting texts to targets (list of FancyArrowPatch or Annotation objects)
162
"""
163
```
164
165
### Package Version
166
167
Access the package version:
168
169
```python { .api }
170
__version__: str
171
# Package version string (e.g., "1.3.0")
172
```
173
174
### Utility Functions
175
176
The package exports utility functions for advanced use cases:
177
178
```python { .api }
179
def overlap_intervals(starts1, ends1, starts2, ends2, closed=False, sort=False):
180
"""
181
Find overlapping intervals between two sets of intervals.
182
183
Parameters:
184
- starts1, ends1: First set of interval coordinates (numpy.ndarray)
185
- starts2, ends2: Second set of interval coordinates (numpy.ndarray)
186
- closed: Whether to treat intervals as closed (bool)
187
- sort: Whether to sort results (bool)
188
189
Returns:
190
- overlap_ids: Array of overlapping interval pair indices (numpy.ndarray)
191
"""
192
```
193
194
```python { .api }
195
def arange_multi(starts, stops=None, lengths=None):
196
"""
197
Create concatenated ranges of integers for multiple start/length pairs.
198
199
Parameters:
200
- starts: Start values for each range (numpy.ndarray)
201
- stops: Stop values for each range (numpy.ndarray, optional)
202
- lengths: Length values for each range (numpy.ndarray, optional)
203
204
Returns:
205
- concat_ranges: Concatenated ranges (numpy.ndarray)
206
207
Notes:
208
Either stops or lengths must be provided, but not both.
209
"""
210
```
211
212
### Additional Importable Functions
213
214
The following functions are technically importable from the main module but are primarily intended for internal use:
215
216
```python { .api }
217
def get_renderer(fig):
218
"""
219
Get a renderer for the given figure.
220
221
Parameters:
222
- fig: Matplotlib figure object
223
224
Returns:
225
- renderer: Figure renderer object
226
227
Raises:
228
- ValueError: If unable to determine renderer
229
"""
230
```
231
232
```python { .api }
233
def intersect(seg1, seg2):
234
"""
235
Check if two line segments intersect.
236
237
Parameters:
238
- seg1: First line segment as (x1, y1, x2, y2) tuple
239
- seg2: Second line segment as (x3, y3, x4, y4) tuple
240
241
Returns:
242
- intersects: Whether segments intersect (bool)
243
"""
244
```
245
246
```python { .api }
247
def get_bboxes(objs, r=None, expand=(1, 1), ax=None):
248
"""
249
Get bounding boxes for matplotlib objects.
250
251
Parameters:
252
- objs: List of objects or PathCollection to get bboxes from
253
- r: Renderer (optional, deduced from ax if None)
254
- expand: Expansion factors for bboxes (x, y) (tuple, default (1, 1))
255
- ax: Axes object (optional, uses current axes if None)
256
257
Returns:
258
- bboxes: List of bounding box objects
259
"""
260
```
261
262
**Note**: These functions are not part of the stable public API and may change in future versions. They are documented here for completeness as they are technically accessible via import.
263
264
## Types
265
266
```python { .api }
267
# Force specification types
268
ForceValue = tuple[float, float] | float
269
270
# Movement restriction values
271
MovementRestriction = str # "x", "y", "xy", "x+", "x-", "y+", "y-"
272
273
# Only move dictionary type
274
OnlyMoveDict = dict[str, MovementRestriction] # Keys: "text", "static", "explode", "pull"
275
```
276
277
## Algorithm Overview
278
279
The adjustText algorithm works in several phases:
280
281
1. **Explosion Phase**: Initially separates overlapping texts using KDTree proximity detection
282
2. **Iterative Adjustment**: Applies multiple forces simultaneously:
283
- **Repulsion forces**: Push texts away from each other and static objects
284
- **Pull forces**: Gently pull texts back toward original positions
285
- **Boundary forces**: Keep texts within axes if `ensure_inside_axes=True`
286
3. **Arrow Generation**: Creates connecting arrows between final text positions and target points
287
288
The algorithm is highly configurable through force multipliers, movement restrictions, and termination conditions, making it suitable for both simple automatic adjustment and fine-tuned control for complex visualizations.
289
290
## Common Use Cases
291
292
- **Scientific publications**: Automatically position labels on scatter plots and data visualizations
293
- **Data exploration**: Quickly make plots readable without manual text positioning
294
- **Automated reporting**: Generate clear visualizations in data processing pipelines
295
- **Complex multi-series plots**: Handle overlapping labels across multiple data series
296
297
The library is designed to be called as the final step in plot creation, after all other plotting operations are complete, ensuring optimal text positioning based on the final plot layout.