Ответ 1
Я придумал что-то, что работает для меня. Обратите внимание на серые пунктирные линии:
Вращение должно быть установлено вручную, но это должно быть сделано ПОСЛЕ draw()
или макета. Поэтому мое решение состоит в том, чтобы связать строки с аннотациями, затем прокрутить их и сделать следующее:
- получить преобразование данных линии (т.е. перейти от координат данных к отображению координат)
- преобразует две точки вдоль линии для отображения координат
- найти наклон отображаемой строки
- установите поворот текста в соответствии с этим наклоном
Это не идеально, потому что обработка matplotlib повернутого текста неверна. Он выравнивается ограничивающей рамкой, а не базовой базой текста.
Некоторые основы шрифтов, если вас интересует рендеринг текста: http://docs.oracle.com/javase/tutorial/2d/text/fontconcepts.html
В этом примере показано, что делает matplotlib: http://matplotlib.org/examples/pylab_examples/text_rotation.html
Единственный способ, которым я нашел ярлык рядом с линией, - это выровнять по центру как по вертикали, так и по горизонтали. Затем я смещаю метку на 10 пунктов влево, чтобы она не перекрывалась. Достаточно хорошо для моего приложения.
Вот мой код. Я рисую линию, но я хочу, затем нарисую аннотацию, а затем привяжу ее к вспомогательной функции:
line, = fig.plot(xdata, ydata, '--', color=color)
# x,y appear on the midpoint of the line
t = fig.annotate("text", xy=(x, y), xytext=(-10, 0), textcoords='offset points', horizontalalignment='left', verticalalignment='bottom', color=color)
text_slope_match_line(t, x, y, line)
Затем вызовите другую вспомогательную функцию после макета, но до savefig
(для интерактивных изображений, я думаю, вам придется регистрироваться на события рисования и вызывать update_text_slopes
в обработчике)
plt.tight_layout()
update_text_slopes()
Помощники:
rotated_labels = []
def text_slope_match_line(text, x, y, line):
global rotated_labels
# find the slope
xdata, ydata = line.get_data()
x1 = xdata[0]
x2 = xdata[-1]
y1 = ydata[0]
y2 = ydata[-1]
rotated_labels.append({"text":text, "line":line, "p1":numpy.array((x1, y1)), "p2":numpy.array((x2, y2))})
def update_text_slopes():
global rotated_labels
for label in rotated_labels:
# slope_degrees is in data coordinates, the text() and annotate() functions need it in screen coordinates
text, line = label["text"], label["line"]
p1, p2 = label["p1"], label["p2"]
# get the line data transform
ax = line.get_axes()
sp1 = ax.transData.transform_point(p1)
sp2 = ax.transData.transform_point(p2)
rise = (sp2[1] - sp1[1])
run = (sp2[0] - sp1[0])
slope_degrees = math.degrees(math.atan(rise/run))
text.set_rotation(slope_degrees)