Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent a matplotlib annotation being clipped by other axes

I have a plot in matplotlib with multiple subplots(axes), and I want to annotate the points within the axes. However, subsequent axes overlay annotations from previous axes (eg annotation on subplot(4,4,1) goes under subplot(4,4,2)). I have set the annotation zorder nice and high, but to no avail :/

I've used a modified version of Joe Kington's awesome DataCursor for the annotations.

Any help would be greatly appreciated

Here's an example: enter image description here

like image 559
Josha Inglis Avatar asked Dec 12 '12 02:12

Josha Inglis


People also ask

How do you avoid overlapping plots in Python?

Dot Size. You can try to decrease marker size in your plot. This way they won't overlap and the patterns will be clearer.

How do you stop subplots from overlapping?

Often you may use subplots to display multiple plots alongside each other in Matplotlib. Unfortunately, these subplots tend to overlap each other by default. The easiest way to resolve this issue is by using the Matplotlib tight_layout() function.

How do I stop Matplotlib overlapping?

Use legend() method to avoid overlapping of labels and autopct. To display the figure, use show() method.


1 Answers

One way to do it is to pop the text created by annotate out of the axes and add it to the figure. This way it will be displayed on top of all of the subplots.

As a quick example of the problem you're having:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=5, ncols=5)
plt.setp(axes.flat, xticks=[], yticks=[], zorder=0)

ax = axes[0,0]
ax.annotate('Testing this out and seeing what happens', xy=(0.5, 0.5), 
            xytext=(1.1, .5), textcoords='axes fraction', zorder=100)

plt.show()

enter image description here

If we just pop the text object out of the axes and add it to the figure instead, it will be on top:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=5, ncols=5)
plt.setp(axes.flat, xticks=[], yticks=[], zorder=0)

ax = axes[0,0]
ax.annotate('Testing this out and seeing what happens', xy=(0.5, 0.5), 
            xytext=(1.1, .5), textcoords='axes fraction', zorder=100)

fig.texts.append(ax.texts.pop())

plt.show()

enter image description here

You mentioned the DataCursor snippet, and there you'd want to change the annotate method:

def annotate(self, ax):
    """Draws and hides the annotation box for the given axis "ax"."""
    annotation = ax.annotate(self.template, xy=(0, 0), ha='right',
            xytext=self.offsets, textcoords='offset points', va='bottom',
            bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
            arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')
            )
    # Put the annotation in the figure instead of the axes so that it will be on
    # top of other subplots.
    ax.figure.texts.append(ax.texts.pop())

    annotation.set_visible(False)
    return annotation

I haven't tested the last bit, but it should work...

like image 108
Joe Kington Avatar answered Sep 29 '22 11:09

Joe Kington