8

When mixing labels that have subscripts with labels without them, they do not vertically align properly in the legend. Since matplotlib determines bounding boxes internally based on printing characters, using a vphantom character does not work to align these legend labels, and I have not had any luck changing the vertical alignment of the labels with set_va, either.

Below is a MWE that illustrates problem I am trying to solve. I would like the labels to align to the text baseline if at all possible, otherwise to the text top.

import numpy as np
import matplotlib as mpl
mpl.rcParams['text.usetex'] = True
import matplotlib.pyplot as plt

x = np.arange(10)
plt.plot(x, np.random.uniform(size=(10,)), c='red', label=r'test')
plt.scatter(x, np.random.uniform(size=(10,)), c='blue', label=r'test${}_{xy}$')
plt.legend(ncol=2)                                                                          
plt.show()

mwe image

emprice
  • 912
  • 11
  • 21

2 Answers2

10

Set the text.latex.preview parameter to True:

import numpy as np
import matplotlib as mpl
mpl.rcParams['text.usetex'] = True
mpl.rcParams['text.latex.preview'] = True
import matplotlib.pyplot as plt

x = np.arange(10)
plt.plot(x, np.random.uniform(size=(10,)), c='red', label=r'test')
plt.scatter(x, np.random.uniform(size=(10,)), c='blue', label=r'test${}_{xy}$')
plt.legend(ncol=2)                                                      

plt.show()

Image with baseline-aligned labels

For the effect of the preview argument, also refer to this example.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
pulupa
  • 120
  • 1
  • 7
  • 1
    Note: `text.latex.preview` was deprecated in matplotlib 3.3.0; see [here](https://matplotlib.org/3.3.0/gallery/text_labels_and_annotations/usetex_baseline_test.html) for some more details. – der_herr_g Dec 06 '22 at 21:34
2

You can have a look on Text alignment in a Matplotlib legend.

Or you can just shift down the second legend text,

h_legend = plt.legend(ncol=2)
y_shift = -2.5
h_legend.texts[1].set_position((0, y_shift))

You can peak your shift distance based on the extent of the legend window using something like:

h_legend = plt.legend(ncol=2)    
renderer = plt.gcf().canvas.get_renderer()
y_shift = -0.2*h_legend.texts[0].get_window_extent(renderer).height
h_legend.texts[1].set_position((0, y_shift))

this will shift the second text by 20% of the full legend window height.

Community
  • 1
  • 1
hashmuke
  • 3,075
  • 2
  • 18
  • 29
  • Thanks for the quick response, @hashmuke. I'm curious, though, whether there's a way to automate shifting the labels, as my actual use case has many labels which may change over time. – emprice Nov 05 '16 at 17:50