How to center x/y labels on the visible axes spine, not the plot area

Question:

My plot has ylim(0,0.08), but I am only displaying up to 0.06. The problem is, my ylabel is centered on a spine that is 0.08, instead of 0.06. Is there a way to have the label centered only on the visible spine?

enter image description here

Asked By: The Nightman

||

Answers:

import matplotlib.pyplot as plt #3.5
import numpy as np

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 5))

ax1.set_yticks(np.linspace(0, 0.08, 9))
ax1.set_ylim(0, 0.08)
ax1.set_ylabel('Fraction', loc='center')

ax2.set_yticks(np.linspace(0, 0.06, 7))
ax2.set_ylim(0, 0.06)
ax2.set_ylabel('Fraction', loc='center')

enter image description here

Answered By: Joao_PS

The y label gets positioned in "axes coordinates" relative to the main plot area (0 at the bottom, 1 at the top, so 0.5 to have it centered).

You can recalculate the position proportional to the ylim and the extreme y ticks.

The following example uses sns.despine(trim=True) to cut the y-axis. A maximum y-tick of 0.05 is used to better illustrate the new position.

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

fig, ax = plt.subplots()
t = np.linspace(0, 2 * np.pi, 500)
ax.plot(np.sin(5 * t), (np.cos(3 * t) + 1) / 30)
ylim_max = 0.08
ax.set_ylim(0, ylim_max)
ytick_max = 0.05
ax.set_yticks(np.arange(0, ytick_max + 1e-6, 0.01))
ylabel = ax.set_ylabel('test label')
ylabel.set_y(0.5 * ytick_max / ylim_max)
sns.despine(ax=ax, trim=True)  # cut the axis at the extreme ticks
plt.show()

recentering the ylabel between min and max ticks

Here is a more general example, using np.interp in case the lower y tick or ylim are different from 0:


import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

fig, ax = plt.subplots()
t = np.linspace(0, 2 * np.pi, 500)
ax.plot(np.sin(2 * t), (np.sin(9 * t) + 1) / 30)
ax.set_ylim(-0.03, 0.08)
ax.set_yticks(np.arange(0.01, 0.05 + 1e-6, 0.01))
ylabel = ax.set_ylabel('test label')
ylabel.set_y(np.interp(np.mean(ax.get_yticks()[[0, -1]]), ax.get_ylim(), [0, 1]))
sns.despine(ax=ax, trim=True)  # cut the axis at the extreme ticks
plt.show()

recentering ylabel by ticks, more general situation

Answered By: JohanC