Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib: data being plotted over legend when using twinx

I'm trying to use Python and Matplotlib to plot a number of different data sets. I'm using twinx to have one data set plotted on the primary axis and another on the secondary axis. I would like to have two separate legends for these data sets.

In my current solution, the data from the secondary axis is being plotted over the top of the legend for the primary axis, while data from the primary axis is not being plotted over the secondary axis legend.

I have generated a simplified version based on the example here: http://matplotlib.org/users/legend_guide.html

Here is what I have so far:

import matplotlib.pyplot as plt
import pylab

fig, ax1 = plt.subplots()
fig.set_size_inches(18/1.5, 10/1.5)
ax2 = ax1.twinx()

ax1.plot([1,2,3], label="Line 1", linestyle='--')
ax2.plot([3,2,1], label="Line 2", linewidth=4)

ax1.legend(loc=2, borderaxespad=1.)
ax2.legend(loc=1, borderaxespad=1.)

pylab.savefig('test.png',bbox_inches='tight', dpi=300, facecolor='w', edgecolor='k')

With the result being the following plot: Figure

As shown in the plot, the data from ax2 is being plotted over the ax1 legend and I would like the legend to be over the top of the data. What am I missing here?

Thanks for the help.

like image 290
0235ev Avatar asked Mar 12 '15 12:03

0235ev


People also ask

How do I fix the legend position in matplotlib?

To change the position of a legend in Matplotlib, you can use the plt. legend() function. The default location is “best” – which is where Matplotlib automatically finds a location for the legend based on where it avoids covering any data points.

How do I make a matplotlib legend outside the plot?

In Matplotlib, to set a legend outside of a plot you have to use the legend() method and pass the bbox_to_anchor attribute to it. We use the bbox_to_anchor=(x,y) attribute. Here x and y specify the coordinates of the legend.

How do I get rid of matplotlib legend?

If you want to plot a Pandas dataframe and want to remove the legend, add legend=None as parameter to the plot command.


2 Answers

The trick is to draw your first legend, remove it, and then redraw it on the second axis with add_artist():

legend_1 = ax1.legend(loc=2, borderaxespad=1.)
legend_1.remove()
ax2.legend(loc=1, borderaxespad=1.)
ax2.add_artist(legend_1)

Tribute to @ImportanceOfBeingErnest :
https://github.com/matplotlib/matplotlib/issues/3706#issuecomment-378407795

like image 72
Bkyn Avatar answered Sep 20 '22 16:09

Bkyn


You could replace your legend setting lines with these:

ax1.legend(loc=1, borderaxespad=1.).set_zorder(2)
ax2.legend(loc=2, borderaxespad=1.).set_zorder(2)

And it should do the trick.

Note that locations have changed to correspond to the lines and there is .set_zorder() method applied after the legend is defined.

The higher integer in zorder the 'higher' layer it will be painted on.enter image description here

like image 32
Primer Avatar answered Sep 19 '22 16:09

Primer