4

Python beginner so apologies if incorrect terminology at any point.

I am using the legend(loc='best', ...) method and it works 99% of the time. However, when stacking more than 9 plots (i.e. i>9 in example below) on a single figure, with individual labels, it defaults to center and covers the data.

Is there a way to run a test in the script that will give a true/false value if the legend is covering any data points?

Very simplified code:

fig = plt.figure()
    for i in data:
        plt.plot(i[x, y], label=LABEL)
fig.legend(loc='best')
fig.savefig()

Example of legend covering data

Bart
  • 9,825
  • 5
  • 47
  • 73
MattCryer
  • 135
  • 1
  • 8
  • You may want to take a look at this question for some alternatives on placing the legend, http://stackoverflow.com/questions/4700614/how-to-put-the-legend-out-of-the-plot – user2699 Oct 20 '16 at 13:09

1 Answers1

2

One way is to add some extra space at the bottom/top/left or right side of the axis (in your case I would prefer top or bottom), by changing the limits slightly. Doing so makes the legend fit below the data. Add extra space by setting a different y-limit with ax.set_ylim(-3e-4, 1.5e-4) (the upper limit is approximately what it is in your figure and -3 is a estimate of what you need).

What you also need to do is to add split the legend into more columns, with the keyword ncol=N when creating the legend.

Figure

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()

ax = fig.add_subplot(111)

x = np.linspace(0, 1, 100)
y = 3.5 * x - 2
for i in range(9):
    ax.plot(x, y + i / 10., label='iiiiiiiiiiii={}'.format(i))

ax.set_ylim(-3, 1.5)
ax.legend(loc='lower center', ncol=3)  # ncol=3 looked nice for me, maybe you need to change this
plt.show()

EDIT

Another solution is to put the legend in a separate axis like I do in the code below. The data-plot does not need to care about making space for the legend or anything and you should have enough space in the axis below to put all your line-labels. If you need more space, you can easily change the ratio of the upper axis to the lower axis.

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()

ax = fig.add_subplot(211)
ax_leg = fig.add_subplot(212)

x = np.linspace(0, 1, 100)
y = 3.5 * x - 2
lines = []
for i in range(9):  #for plotting the actual data
    li, = ax.plot(x, y + i / 10., label='iiiiiiiiiiii={}'.format(i))
    lines.append(li)

for line in lines:  # just to make the legend plot
    ax_leg.plot([], [], line.get_color(), label=line.get_label())
ax_leg.legend(loc='center', ncol=3, )  # ncol=3 looked nice for me, maybe you need to change this
ax_leg.axis('off')
fig.show()

enter image description here

pathoren
  • 1,634
  • 2
  • 14
  • 22
  • Thanks pathoren, that has worked nicely for the example plot I posted. If I wanted to do this dynamically do you think the best approach would be to just apply a variable to ylim and ncol and adjust these based on my inputs? – MattCryer Oct 20 '16 at 22:04
  • I guess you can always figure out where your bottom-point of the data is, and if you know that you always have let say 3 rows of legends you can beforehand figure out how much of the axis is needed for the legend (in my case it is about 0.2 in axis coordinates) and then add the corresponding offset in data-coordinates. If you have 4 rows it might be 0.25 in axis coordinates that is needed. – pathoren Oct 21 '16 at 10:02
  • Btw, how much might the number of lines your plotting change? You said > 9 plots...what is the estimated upper limit? – pathoren Oct 21 '16 at 10:04