Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One secondary label missing when plotting x and y secondary axis

I'm coming from this question Matplotlib: two x axis and two y axis where I learned how to plot two x and y axis on the same plot.

Here's a MWE:

import matplotlib.pyplot as plt
import numpy as np

# Generate random data.    
x1 = np.random.randn(50)
y1 = np.linspace(0, 1, 50)
x2 = np.random.randn(20)+15.
y2 = np.linspace(10, 20, 20)

# Plot both curves.
fig = plt.figure()

ax1 = fig.add_subplot(111)
ax1.set_xlabel('x_1')
ax1.set_ylabel('y_1')
plt.plot(x1, y1, c='r')

ax2 = ax1.twinx().twiny()
ax2.set_xlabel('x_2')
ax2.set_ylabel('y_2')
plt.ylim(min(y2), max(y2))
ax2.plot(x2, y2, c='b')

plt.show()

and this is the output:

enter image description here

The right y axis and the top x axis correspond to the blue curve.

As you can see, the second y label is missing even though it is defined. I've tried a number of different approaches but I can't get it to show. Am I doing something wrong?


Add:

apparently there's an issue with the line:

ax2 = ax1.twinx().twiny()

if I invert it like so:

ax2 = ax1.twiny().twinx()

then it's the second x label that will not show.

like image 826
Gabriel Avatar asked Mar 06 '14 16:03

Gabriel


1 Answers

Basically, what's happening is that there's a third axes object created that you're not currently retaining a reference to. ax2's visible y-axis actually belongs to this third axes object.

You have a couple of options.

  1. Retain a reference to the "hidden" axes object and set its y-label.
  2. Don't use twinx and twiny and instead create an axes in the same position as the first.

The second option is a touch more verbose, but has the advantage that the y-axis limits on the second plot will autoscale as you'd expect. You won't need to manually set them as you're currently doing.

At any rate, here's an example of the first option:

import matplotlib.pyplot as plt
import numpy as np

# Generate random data.
x1 = np.random.randn(50)
y1 = np.linspace(0, 1, 50)
x2 = np.random.randn(20)+15.
y2 = np.linspace(10, 20, 20)

# Plot both curves.
fig, ax1 = plt.subplots()

ax1.set(xlabel='x_1', ylabel='y_1')
ax1.plot(x1, y1, c='r')

tempax = ax1.twinx()
ax2 = tempax.twiny()
ax2.plot(x2, y2, c='b')
ax2.set(xlabel='x_2', ylim=[min(y2), max(y2)])
tempax.set_ylabel('y_2', rotation=-90)

plt.show()

...And here's an example of the second option:

import matplotlib.pyplot as plt
import numpy as np

def twinboth(ax):
    # Alternately, we could do `newax = ax._make_twin_axes(frameon=False)`
    newax = ax.figure.add_subplot(ax.get_subplotspec(), frameon=False)
    newax.xaxis.set(label_position='top')
    newax.yaxis.set(label_position='right', offset_position='right')
    newax.yaxis.get_label().set_rotation(-90) # Optional...
    newax.yaxis.tick_right()
    newax.xaxis.tick_top()
    return newax

# Generate random data.
x1 = np.random.randn(50)
y1 = np.linspace(0, 1, 50)
x2 = np.random.randn(20)+15.
y2 = np.linspace(10, 20, 20)

# Plot both curves.
fig, ax1 = plt.subplots()

ax1.set(xlabel='x_1', ylabel='y_1')
ax1.plot(x1, y1, c='r')

ax2 = twinboth(ax1)
ax2.set(xlabel='x_2', ylabel='y_2')
ax2.plot(x2, y2, c='b')

plt.show()

Both produce identical output:

enter image description here

like image 124
Joe Kington Avatar answered Sep 28 '22 08:09

Joe Kington