Перемещение легенды matplotlib за пределы оси делает его обрезанным по фигуре коробки
Я знаком со следующими вопросами:
Matplotlib savefig с легендой вне сюжета
похоже, что ответы на эти вопросы имеют роскошь иметь возможность возиться с точным сжатием оси, чтобы легенда соответствовала.
сжатие осей, однако, не является идеальным решением, потому что это делает данные меньше, что делает его на самом деле сложнее чтобы интерпретировать; особенно когда его сложный и есть много вещей, происходящих... следовательно, нужна большая легенда
пример сложной легенды в документации демонстрирует необходимость этого, потому что легенда в их графике фактически полностью скрывает несколько точек данных.
http://matplotlib.sourceforge.net/users/legend_guide.html#legend-of-complex-plots
что я хотел бы быть в состоянии сделать это динамически разверните размер блока фигур, чтобы разместить расширяющуюся легенду фигур.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))
ax.grid('on')
обратите внимание, как окончательная метка "обратный загар" на самом деле находится вне рамки рисунка (и выглядит плохо обрезанным - не качество публикации!)

наконец, мне сказали, что это нормальное поведение в R и LaTeX, поэтому я немного смущен, почему это так сложно в python... Есть ли историческая причина? Является ли Matlab одинаково бедным в этом вопросе?
У меня есть (только немного) более длинная версия этого кода на pastebin http://pastebin.com/grVjc007
3 ответов:
извините EMS, но я на самом деле только что получил еще один ответ из списка mailling matplotlib (спасибо выходит в Benjamin Root).
код, который я ищу, настраивает вызов savefig на:
fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox_inches='tight') #Note that the bbox_extra_artists must be an iterableэто, по-видимому, похоже на вызов tight_layout, но вместо этого вы позволяете savefig учитывать дополнительные художники в вычислении. Это действительно изменило размер окна фигуры по желанию.
import matplotlib.pyplot as plt import numpy as np x = np.arange(-2*np.pi, 2*np.pi, 0.1) fig = plt.figure(1) ax = fig.add_subplot(111) ax.plot(x, np.sin(x), label='Sine') ax.plot(x, np.cos(x), label='Cosine') ax.plot(x, np.arctan(x), label='Inverse tan') handles, labels = ax.get_legend_handles_labels() lgd = ax.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5,-0.1)) ax.grid('on') fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox_inches='tight')это производит:
добавлено: я нашел то, что должно сделать трюк сразу, но остальная часть кода ниже также предлагает альтернативу.
использовать
subplots_adjust()функция для перемещения нижней части подзаголовка вверх:fig.subplots_adjust(bottom=0.2) # <-- Change the 0.02 to work for your plot.затем играть со смещением в легенде
bbox_to_anchorчасть команды Легенды, чтобы получить поле легенды, где вы хотите его. Некоторые комбинации установкиfigsizeи с помощьюsubplots_adjust(bottom=...)должен произвести качественный участок для вы.альтернатива: Я просто изменил строку:
fig = plt.figure(1)to:
fig = plt.figure(num=1, figsize=(13, 13), dpi=80, facecolor='w', edgecolor='k')и изменен
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))до
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,-0.02))и он отлично отображается на моем экране (24-дюймовый ЭЛТ-монитор).
здесь
figsize=(M,N)задает окно рисунка размером M дюймов на N дюймов. Просто играть с этим, пока он не выглядит правильно для вас. Преобразуйте его в более масштабируемый формат изображения и используйте GIMP для редактирования, если это необходимо, или просто обрезка с латексомviewportопция при включении графики.
вот еще одно, очень ручное решение. Вы можете определить размер оси, и отступы рассматриваются соответственно (включая легенду и галочки). Надеюсь, это кому-то пригодится.
пример (размер осей одинаковый!):
код:
#================================================== # Plot table colmap = [(0,0,1) #blue ,(1,0,0) #red ,(0,1,0) #green ,(1,1,0) #yellow ,(1,0,1) #magenta ,(1,0.5,0.5) #pink ,(0.5,0.5,0.5) #gray ,(0.5,0,0) #brown ,(1,0.5,0) #orange ] import matplotlib.pyplot as plt import numpy as np import collections df = collections.OrderedDict() df['labels'] = ['GWP100a\n[kgCO2eq]\n\nasedf\nasdf\nadfs','human\n[pts]','ressource\n[pts]'] df['all-petroleum long name'] = [3,5,2] df['all-electric'] = [5.5, 1, 3] df['HEV'] = [3.5, 2, 1] df['PHEV'] = [3.5, 2, 1] numLabels = len(df.values()[0]) numItems = len(df)-1 posX = np.arange(numLabels)+1 width = 1.0/(numItems+1) fig = plt.figure(figsize=(2,2)) ax = fig.add_subplot(111) for iiItem in range(1,numItems+1): ax.bar(posX+(iiItem-1)*width, df.values()[iiItem], width, color=colmap[iiItem-1], label=df.keys()[iiItem]) ax.set(xticks=posX+width*(0.5*numItems), xticklabels=df['labels']) #-------------------------------------------------- # Change padding and margins, insert legend fig.tight_layout() #tight margins leg = ax.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0) plt.draw() #to know size of legend padLeft = ax.get_position().x0 * fig.get_size_inches()[0] padBottom = ax.get_position().y0 * fig.get_size_inches()[1] padTop = ( 1 - ax.get_position().y0 - ax.get_position().height ) * fig.get_size_inches()[1] padRight = ( 1 - ax.get_position().x0 - ax.get_position().width ) * fig.get_size_inches()[0] dpi = fig.get_dpi() padLegend = ax.get_legend().get_frame().get_width() / dpi widthAx = 3 #inches heightAx = 3 #inches widthTot = widthAx+padLeft+padRight+padLegend heightTot = heightAx+padTop+padBottom # resize ipython window (optional) posScreenX = 1366/2-10 #pixel posScreenY = 0 #pixel canvasPadding = 6 #pixel canvasBottom = 40 #pixel ipythonWindowSize = '{0}x{1}+{2}+{3}'.format(int(round(widthTot*dpi))+2*canvasPadding ,int(round(heightTot*dpi))+2*canvasPadding+canvasBottom ,posScreenX,posScreenY) fig.canvas._tkcanvas.master.geometry(ipythonWindowSize) plt.draw() #to resize ipython window. Has to be done BEFORE figure resizing! # set figure size and ax position fig.set_size_inches(widthTot,heightTot) ax.set_position([padLeft/widthTot, padBottom/heightTot, widthAx/widthTot, heightAx/heightTot]) plt.draw() plt.show() #-------------------------------------------------- #==================================================


Comments