Data being plotted over legend when using twinx
Asked Answered
V

3

15

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?

Various answered 12/3, 2015 at 12:43 Comment(0)
B
15

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

Badgett answered 11/2, 2019 at 13:9 Comment(0)
S
12

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

Swee answered 12/3, 2015 at 14:13 Comment(3)
This actually isn't quite what I'm looking for. Though it seems counterintuitive on this particular plot, I want the legends in their current locations so they are close to the axis for which the data belong. Leaving the legend location the same (as in my example) and changing zorder does not solve the problem.Various
Well the thing is that the legends as they are now belong to different axes and axes are drawn on top of previously initiated ones. So it seems to me that keeping legends where they are and changing zorder might not help. You have at least two options: 1) put legends outside of chart area 2) create second label in the second (later) ax and it will be drawn on top layer. There are examples in SO of how to do both of these options.Swee
Worked for me, except I had to use a higher zorder. 3 didn't work, but 10 did.Scrag
A
0
all_axes = fig.get_axes()
for axis in all_axes:
    legend = axis.get_legend()
    if legend is not None:
        legend.remove()
        all_axes[-1].add_artist(legend)

From https://github.com/matplotlib/matplotlib/issues/3706#issuecomment-817268918

Antler answered 31/7, 2023 at 3:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.