Python Matplotlib - Spine coloring issue in a double-y axis plot

Viewed 905

I'm writing a script to draw plot via matplotlib, the following code is an analogy to my original script that reproduce the issue that I've encountered.

def func(ax, data, color, position):    # A function for plotting
    ax.plot(data[0], data[1], color=color)
    ax.spines[position].set_color(color)

fig = plt.figure()
data_1 = [np.linspace(0, 1, 10), np.linspace(0, 10, 10)]
data_2 = [np.linspace(0, 1, 10), np.linspace(10, 0, 10)]

ax = fig.add_subplot(111)
func(ax, data_1, 'r', 'left')

ax_1 = ax.twinx()
func(ax_1, data_2, 'b', 'right')

plt.show()

The expected plot should have both y axis colored, however, only right spine is colored, as shown below. enter image description here

When zooming into left spine you can find a red shadow around y-axis, that means my colored spine is covered by another one, how to solve this issue by only modifying func()?

3 Answers

twinx does not only "twin" the y axis spine but all other three spines, too. So the red spine on the left is basically overdrawn (like you recognized already in your own answer). Instead of setting their color to None, you can set_visible() their visibility to False, which seems to be the preferred way, compared to lines 18-22 here.

So:

def func(ax, data, color, position):    # A function for plotting
    ax.plot(data[0], data[1], color=color)
    ax.spines[position].set_color(color)
    for pos in ['left', 'right']:
        if pos != position:
            ax.spines[pos].set_visible(False)

Seems like other spines would be created after executing this code: ax_1 = ax.twinx(), so I find a "dumb" solution:

def func(ax, data, color, position):    # A function for plotting
    ax.plot(data[0], data[1], color=color)
    ax.spines[position].set_color(color)

    if position == 'left':
        other = 'right'
    elif position == 'right':
        other = 'left'
    ax.spines[other].set_color('None')

Result:

enter image description here

This can solve my problem, but I'm still open for other beautiful solutions.

I am copying an answer to the question from the matplotlib documentation that could be found in the following link: https://matplotlib.org/api/spines_api.html

Here is a function that could be used:

def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.values():
    sp.set_visible(False)

And, an example of using it in the following:

import matplotlib.pyplot as plt


def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.values():
        sp.set_visible(False)


fig, host = plt.subplots()
fig.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

# Offset the right spine of par2.  The ticks and label have already been
# placed on the right by twinx above.
par2.spines["right"].set_position(("axes", 1.2))
# Having been created by twinx, par2 has its frame off, so the line of its
# detached spine is invisible.  First, activate the frame but make the patch
# and spines invisible.
make_patch_spines_invisible(par2)
# Second, show the right spine.
par2.spines["right"].set_visible(True)

p1, = host.plot([0, 1, 2], [0, 1, 2], "b-", label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], "r-", label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], "g-", label="Velocity")

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

host.yaxis.label.set_color(p1.get_color())
par1.yaxis.label.set_color(p2.get_color())
par2.yaxis.label.set_color(p3.get_color())

tkw = dict(size=4, width=1.5)
host.tick_params(axis='y', colors=p1.get_color(), **tkw)
par1.tick_params(axis='y', colors=p2.get_color(), **tkw)
par2.tick_params(axis='y', colors=p3.get_color(), **tkw)
host.tick_params(axis='x', **tkw)

lines = [p1, p2, p3]

host.legend(lines, [l.get_label() for l in lines])

plt.show()

Which creates the following plot:

Plot multiple Y axes with different spine colors

Related