How to center x/y labels on the visible axes spine, not the plot area
Question:
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')
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()
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()
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')
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()
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()