Ответ 1
Я провел несколько часов, пробираясь вчера, и сделал немного прогресса, поэтому я расскажу об этом ниже вместе с некоторыми предложениями, продвигающимися вперед.
Во-первых, кажется, что мы можем, конечно, повернуть и перевести ограничительную рамку (bbox) или рамку вокруг легенды. В первом примере ниже вы можете увидеть, что может применяться a transform
, хотя и требует некоторых странно больших чисел перевода после применения поворота на 90 градусов. Но на самом деле проблемы с сохранением переведенного кадра легенды в файл изображения, поэтому мне пришлось сделать снимок экрана из ноутбука IPython. Я также добавил некоторые комментарии.
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import matplotlib.transforms
fig = plt.figure()
ax = fig.add_subplot('121') #make room for second subplot, where we are actually placing the legend
ax2 = fig.add_subplot('122') #blank subplot to make space for legend
ax2.axis('off')
ax.plot([4,5,6], label = 'test')
transform = matplotlib.transforms.Affine2D(matrix=np.eye(3)) #start with the identity transform, which does nothing
transform.rotate_deg(90) #add the desired 90 degree rotation
transform.translate(410,11) #for some reason we need to play with some pretty extreme translation values to position the rotated legend
legend = ax.legend(bbox_to_anchor=[1.5,1.0])
legend.set_title('test title')
legend.get_frame().set_transform(transform) #This actually works! But, only for the frame of the legend (see below)
frame = legend.get_frame()
fig.subplots_adjust(wspace = 0.4, right = 0.9)
fig.savefig('rotate_legend_1.png',bbox_extra_artists=(legend,frame),bbox_inches='tight', dpi = 300) #even with the extra bbox parameters the legend frame is still getting clipped
Затем я подумал, что было бы разумно исследовать get_methods()
других компонентов легенды. Вы можете сортировать эти вещи с помощью dir(legend)
и legend.__dict__
и так далее. В частности, я заметил, что вы можете сделать это: legend.get_title().set_transform(transform)
, что, по-видимому, означает, что мы могли бы перевести текст легенды (а не только рамку, как указано выше). Посмотрим, что произойдет, когда я попробую:
fig2 = plt.figure()
ax = fig2.add_subplot('121')
ax2 = fig2.add_subplot('122')
ax2.axis('off')
ax.plot([4,5,6], label = 'test')
transform = matplotlib.transforms.Affine2D(matrix=np.eye(3))
transform.rotate_deg(90)
transform.translate(410,11)
legend = ax.legend(bbox_to_anchor=[1.5,1.0])
legend.set_title('test title')
legend.get_frame().set_transform(transform)
legend.get_title().set_transform(transform) #one would expect this to apply the same transformation to the title text in the legend, rotating it 90 degrees and translating it
frame = legend.get_frame()
fig2.subplots_adjust(wspace = 0.4, right = 0.9)
fig2.savefig('rotate_legend_1.png',bbox_extra_artists=(legend,frame),bbox_inches='tight', dpi = 300)
Название легенды, похоже, исчезло на снимке экрана из ноутбука IPython. Но если мы посмотрим на сохраненный файл, название легенды теперь находится в левом нижнем углу и, похоже, проигнорировало компонент поворота преобразования (почему?):
У меня были схожие технические трудности с этим типом подхода:
bbox = matplotlib.transforms.Bbox([[0.,1],[1,1]])
trans_bbox = matplotlib.transforms.TransformedBbox(bbox, transform)
legend.set_bbox_to_anchor(trans_bbox)
Другие примечания и предложения:
- Может быть разумной идеей разобраться в различиях в поведении между заголовком легенды и объектами фрейма - почему они оба принимают преобразования, но только кадр принимает поворот? Возможно, можно было бы подклассировать объект легенды в исходном коде и внести некоторые изменения.
- Нам также нужно найти решение для фрейма с вращающейся/переведенной легендой, которая не сохраняется на выходе, даже после того, как будет следовать различным связанным предположениям о SO (т.е. Matplotlib savefig с легендой снаружи сюжет).