Matt Stokes
Matt Stokes

Reputation: 4958

Python Numpy Matplotlib Set Y-Label inline

I'm wondering how I might set the Y label in the following plot all inline with one another. Currently they are misaligned since the Y values are not of equal space.

enter image description here

Upvotes: 2

Views: 650

Answers (3)

tmdavison
tmdavison

Reputation: 69116

You can do this more elegantly with ax.yaxis.set_label_coords, using a constant value for the x coordinate, as shown here. For your example:

import matplotlib.pyplot as plt

labels = ['$P_{EUC}[mm]$', '$P_z[mm]$', '$P_Y[mm]$', '$P_X[mm]$']

fig,axs=plt.subplots(4,1,sharex=True)

axs[0].set_ylim(-1000,0)
axs[1].set_ylim(-0.0010,0.0020)
axs[2].set_ylim(0,5)
axs[3].set_ylim(0,20)

[axs[i].set_ylabel(labels[i]) for i in range(4)]

labelx = -0.1 # Change this to suit your needs
[axs[i].yaxis.set_label_coords(labelx,0.5) for i in range(4)]

fig.savefig('labelx.png')

enter image description here

Upvotes: 2

Joe Kington
Joe Kington

Reputation: 284602

In this case, it's probably easier to not use the ylabel at all. Instead, use annotate to place the text at a constant offset from the left side of the axes.

As an example of your problem:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=4, sharex=True)
yranges = [(-1000, 100), (-0.001, 0.002), (0, 5), (0, 20)]
labels = ['$P_{EUC}[mm]$', '$P_z[mm]$', '$P_Y[mm]$', '$P_X[mm]$']

for ax, yrange, label in zip(axes, yranges, labels):
    ax.set(ylim=yrange, ylabel=label)

plt.show()

enter image description here

To solve this, it's easiest to use annotate. The trick is to position the text at y=0.5 in axes coordinates, and then 5 points from the left hand edge of the figure in the x-direction. The syntax is a bit verbose, but is relatively easy to read. The key is in the xycoords and textcoords kwargs that control how xy and xytext are interpreted:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=4, sharex=True)
yranges = [(-1000, 100), (-0.001, 0.002), (0, 5), (0, 20)]
labels = ['$P_{EUC}[mm]$', '$P_z[mm]$', '$P_Y[mm]$', '$P_X[mm]$']

for ax, yrange, label in zip(axes, yranges, labels):
    ax.set(ylim=yrange)
    ax.annotate(label, xy=(0, 0.5), xytext=(5, 0), rotation=90,
                xycoords=('figure fraction', 'axes fraction'),
                textcoords='offset points', va='center', ha='left')

plt.show()

enter image description here

Upvotes: 2

Bennett Brown
Bennett Brown

Reputation: 5373

You can offset x and y labels using the set_ylabel method on the AxesSubplots. http://matplotlib.org/api/axes_api.html?highlight=y%20label#matplotlib.axes.Axes.set_ylabel

You can also format the y tick mark labels. http://matplotlib.org/api/axes_api.html?highlight=y%20label#matplotlib.axes.Axes.set_yticklabels

When working with matplotlib text objects, you can use the argument transform=ax.transAxes to use Figure coordinates instead of Axes coordinates if you want to loop through the subfigures.

But I think what you're looking for is just to offset them. When the docs are sparse, use dir() to poke through the namespace.

fig, ax = plt.subplots(1, 1)

dir(ax) includes yaxis.

dir(ax.yaxis) includes get_label.

dir(ax.yaxis.get_label()) includes set_x.

help(ax.yaxis.get_label().set_x says:

set_x(self, x) method of matplotlib.text.Text instance
    Set the *x* position of the text

    ACCEPTS: float

Upvotes: 0

Related Questions