Skip to content
Ilya Flyamer edited this page Jul 8, 2018 · 7 revisions

About

This simple library lets you automatically adjust text position on matplotlib plots to avoid or minimize overlaps - with other individual text labels, or with some specified coordinates (for example, the original text coordinates to simplify labelling scatter plots), or most arbitrary matplotlib objects such as bars or the legend (however their bounding boxes are used, not the actual object edges, so with non-rectangular objects it won't work quite that nicely).

Getting started

Installation

To use the library, you can simply install it from pypi (pip install adjustText) or directly from GitHub (pip install https://github.com/Phlya/adjustText/archive/master.zip) and import the main function like this: from adjustText import adjust_text.

Please report issues in this repository, and I am happy to consider pull requests to improve this library!

Using the library

Using the adjust_text function for simple plots is very easy, while for complicated plots it is quite configurable. The minimal call signature only requires a list of matplotlib.text.Text objects. With no other other arguments, it will move those objects to avoid overlaps between all of them, and with their original positions - this makes it super easy to quickly annotate a scatter plot without hiding the data.

Note, that you should call adjust_text last after everything else has been set up, and the final axes dimensions are determined. This is because to move texts the function needs to use the dimensions of the axes, and without knowing the final size of the plots the results will be completely nonsensical, or suboptimal.

A simple example

from adjustText import adjust_text
import numpy as np
np.random.seed(0)
x, y = np.random.random((2,30))
fig, ax = plt.subplots()
plt.plot(x, y, 'bo')
texts = [plt.text(x[i], y[i], 'Text%s' %i, ha='center', va='center') for i in range(len(x))]

Clearly, the overlap here is suboptimal, and doesn't allow to read the labels properly - and hides the location of data. Now we repeat this, but add the adjust_text call at the end.

fig, ax = plt.subplots()
plt.plot(x, y, 'bo')
texts = [plt.text(x[i], y[i], 'Text%s' %i, ha='center', va='center') for i in range(len(x))]
adjust_text(texts)

24

This looks much better now with no overlaps and clearly visible points! And the 24 output that we see before the plots is returned by adjust_text function - it shows how many iterations it took to remove overlaps. Not generally very useful, but might be helpful for optimizing parameters if time is important - the process can be rather slow at times.

However currently in come cases it is a little unclear, which point is labelled with with annotation... For example, Text7 and Text20 are both next to one point, while another point nearby doesn't have a label next to it! So we need to add some arrows to point from texts to the data points. To do that adjust_text creates annotation objects with no text to point from each text to its original location. We simply need to add an arrowprops argument to the adjust_text call and we will get arrows! Let's see.

fig, ax = plt.subplots()
plt.plot(x, y, 'bo')
texts = [plt.text(x[i], y[i], 'Text%s' %i, ha='center', va='center') for i in range(len(x))]
adjust_text(texts, arrowprops=dict(arrowstyle='->', color='red'))

24

Well, this is even better now! Looks quite good, and everything is clearly labelled.

Please see more usage examples as a reproducible Jupyter Notebook in this repository (https://github.com/Phlya/adjustText/blob/master/docs/source/Examples.ipynb) together with the example data used there (https://github.com/Phlya/adjustText/tree/master/figures). If you have a nice plot showcasing adjustText, I would be happy to add it there if you would like that.

Clone this wiki locally