2014-09-02 5 views
1

Я делаю сюжет с matplotlib и создаю легенду для этого (см. Код ниже). Я хочу, чтобы строки легенд были выровнены по горизонтали, так что отношения > и < выровнены. Попытка адаптировать this и this код подобных проблем, я застрял.Выровнять строки легенды в matplotlib

Я понимаю основную идею: используйте \makebox[width][alignment]{math expression before aligment}<math expression after alignment как метку, так что пространство, используемое этим эпсилон-выражением, всегда использует одно и то же пространство и выравнивается вправо, следовательно, есть свободное пространство слева.

Но методы \hfill, используемые в ссылках, работают только в том случае, если перед ним есть hfill, или если выравнивание стандартно (слева). Решение должно быть довольно близко, и любая помощь будет оценена. Это как текст легенды должен выглядеть enter image description here

import numpy 
from matplotlib import pyplot as plt 

plt.rc('text', usetex=True) # needed for interpeting tex strings, but changes appearence of axis-tick labels also 
fig = plt.figure(1,figsize=(12.0, 8.0)) 
plt.ion() 

# does not align the '<', '<' and '>' in the legend 
# plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{$\varepsilon_i$}$< -\xi$') 
# plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{$|\varepsilon_i|$}$< \xi$') 
# plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{$\varepsilon_i$}$ > \xi$') 

# \hfill doesnt change anything 
# plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{\hfill$\varepsilon_i$}$< -\xi$') 
# plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{\hfill$|\varepsilon_i|$}$< \xi$') 
# plt.plot(numpy.random.rand(10), label=r'\makebox[24cm][r]{\hfill$\varepsilon_i$}$ > \xi$') 

# the relations are aligned, but i do not want to plot the 'bla' for this 
plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{bla\hfill$\varepsilon_i$}$< -\xi$') 
plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{bla\hfill$|\varepsilon_i|$}$< \xi$') 
plt.plot(numpy.random.rand(10), label=r'\makebox[2cm][r]{bla\hfill$\varepsilon_i$}$ > \xi$') 
plt.legend(loc='upper right') 
plt.show() 
+0

Причина это происходит потому, что поле на рисунке взята из ограничительной рамки выводимого текста, а не от того, где появится на странице, что текст. Попытка найти решение ... – mdurant

+0

Мне кажется, вам нужно будет добавить невидимый символ, либо белого цвета, либо исчезающе маленький - для этого вам потребуется добавить пакет цветов или выбрать масштабируемые шрифты, т. Е. Отредактировать предварительный текст отправлен в LaTeX. – mdurant

+0

@mdurant Я думал о добавлении действительно невидимого символа с помощью '' \ vphantom {} ''. К сожалению, это тоже не имело никакого влияния. Изменение шрифтов кажется излишним. Возможно, я закончу настройку позиции вручную либо с помощью большого количества '' \, '', либо установкой позиции текста аргументом '' set_position''. Но я думал, что это должно как-то работать автоматически. – Nras

ответ

2

Вот решение, где LaTeX отлично alignes математике, но пользователь должен принять боль расположить его внутри легенды. Идея заключается в том, чтобы

  • ничья легенда поле в заданном положении с заполнителем
  • положить amsmath-х array в него вручную

Вот код:

#!/usr/bin/python3 

from numpy import arange 

import matplotlib 
from matplotlib import pyplot as plt 
custom_preamble = { 
    "text.usetex": True, 
    "text.latex.preamble": [ 
     r"\usepackage{amsmath}", # for the array macros 
     ], 
    } 
matplotlib.rcParams.update(custom_preamble) 

x = arange(5) 
y = arange(5) 

fig = plt.figure() 
ax = fig.add_subplot(111) 

l1, = ax.plot(x, y) 
l2, = ax.plot(x * 2, y) 
l3, = ax.plot(x * 3, y) 

leg = ax.legend(
    [l1, l2, l3], 
    ["", "", ""], 
    bbox_to_anchor = (0.98, 0.25), 
    handletextpad = 4, # space between lines and text -- used here as a placeholder 
    labelspacing = 0.1, # space between lines in a legend 
    ) 
leg.set_zorder(1) 

ax.text(0.955, 0.21, 

    r"\begin{array}{rcl}" 
    r"  \varepsilon_i & < & -\xi" 
    r"\\ |\varepsilon_i| & < & \xi" 
    r"\\ \varepsilon_i & > & \xi" 
    r"\end{array}", 

    transform = ax.transAxes, 
    horizontalalignment = 'right', 
    verticalalignment = 'top', 
    zorder = 5, 
     ) 

fig.savefig("mwe.png") 

Результат:

enter image description here

Возможно, вы захотите его скомпилировать дважды: при первой компиляции он может дать вам ошибку, но все остальные попытки будут прекрасными.

Что касается пространства между < знаком в легенде - это может быть уменьшена с сказать:

ax.text(0.94, 0.21, 

    r"\begin{array}{[email protected]{}[email protected]{}l}" 
    r"  \varepsilon_i \,\,& < &\,\, -\xi" 
    r"\\ |\varepsilon_i| \,\,& < &\,\, \xi" 
    r"\\ \varepsilon_i \,\,& > &\,\, \xi" 
    r"\end{array}", 

(все остальное то же самое). Это дает:

enter image description here

+0

Очень красиво, легенда выглядит так, как будто я хотел этого. Единственным недостатком этого является то, что метки меток оси теперь также отображаются в шрифте по умолчанию латекса, а не в стандартном шрифте matplotlib. Такая же проблема возникла для моих попыток, вероятно, из-за команды '' "text.usetex": True''. Любое решение для этого? – Nras

+0

@Nras: почему вы считаете, что проблема? Осевые метки являются цифрами - поэтому их следует набирать с помощью шрифта math.Зачем вам нужны разные математические шрифты на одном и том же сюжете? – Adobe

+0

Ẁell это потому, что для всех других фигур мне не нужно было устанавливать этот параметр, поэтому шрифты теперь разные, и я хочу, чтобы они были согласованными. Может быть, вариант будет состоять в том, чтобы переделать другие цифры, но некоторые из них обработаны после обработки, и это займет много времени, чтобы это сделать. – Nras