2

When the marker in a legend is a dot, dot and text are not aligned vertically. To solve this I tried following:

l = ax.legend()
for text in l.texts:
    text.set_va('center') # Is there some setting for this in matplotlibrc, too??

plt.show()

The vertical alignment of text in a legend seems to be baseline. But no matter whether I choose center, bottom or baseline, etc., things are off: enter image description here

Zooming in, this is what Matplotlib gives us out of the box: enter image description here

What I want is also what other software like Inkscape gives me, when aligning two objects vertically: enter image description here

Can Matplotlib do this for me/us?

  • Perhaps be more specific about what you mean by “properly”. Why are you manually setting the vertical alignment at all? – Jody Klymak Jul 25 '21 at 13:46
  • pls provide some data for others to reproduce your result, then others can contribute. – Jiadong Jul 25 '21 at 14:18
  • [Looks like this is simply the default behaviour](https://matplotlib.org/stable/gallery/lines_bars_and_markers/scatter_with_legend.html#sphx-glr-gallery-lines-bars-and-markers-scatter-with-legend-py): When marker in legend is a dot, the text's baseline is above the dot's. – AltaStatistika Jul 25 '21 at 14:38
  • The markers are not typeset - they are signed in a box that knows nothing about the text in the text box. It’s not clear what behaviour you want, but I don’t think it’s trivial to exactly align these elements in any particular way. – Jody Klymak Jul 25 '21 at 15:19
  • Because what Matplotlib gives us by default is really off I added an image, too... – AltaStatistika Jul 25 '21 at 16:42

2 Answers2

0

This appears to work:

  • Set it to display only a single scatterpoint per legend entry by setting scatterpoints=1 in the call to legend()
  • Set the vertical offset of this point to 0 by setting scatteryoffsets=[0] in the call to legend()
  • After creating the legend, iterate through its text labels and set their vertical alignment to center_baseline, using for t in l.get_texts(): t.set_va('center_baseline')
figure(figsize=(2,2))
scatter([0],[0],marker='s',s=20,label='Thing 1')
scatter([1],[0],marker='s',s=20,label='t')
scatter([2],[0],marker='s',s=20,label='T¹₁')
l = legend(scatterpoints=1,scatteryoffsets=[0],handletextpad=-0.5)
for t in l.get_texts(): t.set_va('center_baseline')
MRule
  • 529
  • 1
  • 6
  • 18
0

Here is what I do:

import numpy as np

import matplotlib
matplotlib.use('Agg')
matplotlib.rcParams['text.latex.preamble'] = r'\usepackage{amsmath}'
matplotlib.rc('text', usetex = True)
from matplotlib import pyplot as py

## setup figure
figure = py.figure(figsize = (7.5, 5.0))
axs = [py.subplot(1, 1, 1)]

## make plot
xs = np.linspace(0.0, np.pi, 100)
ys = np.sin(xs)
axs[0].plot(xs, ys, color = 'dodgerblue', label = r'$n = 1$')
ys = np.sin(2.0 * xs)
axs[0].plot(xs, ys, color = 'seagreen', label = r'$n = 2$')
axs[0].axhline(0.0, color = 'gray', linestyle = 'dashed')

## vertical alignment
legends = axs[0].legend(frameon = False, fontsize = 25, loc = 'lower left')
shift  = np.average([_.get_window_extent(renderer = figure.canvas.get_renderer()).height for _ in legends.get_texts()])
shift /= 3.6
for _ in legends.get_texts():
    _.set_va('center') ## va is alias for verticalalignment
    _.set_position((0, shift))

## save figure
name = 'test.pdf'
py.tight_layout()
py.savefig(name)
py.close()

It is, however, complicated and requires manual adjustments, I am still looking for better solutions.

zyy
  • 1,271
  • 15
  • 25