Почему легенда о моем сюжете matplotlib всегда обрезается? - PullRequest
0 голосов
/ 24 октября 2018

Я ищу программный способ добавить легенду к вне моего matplotlib графика, чтобы он не был обрезан при сохранении рисунка в SVG-файл.В следующем примере вы увидите, что метка оси x, а также легенда обрезаны в полученном изображении SVG:

import matplotlib
import matplotlib.backends.backend_svg

fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],loc='upper right',borderpad=0.06,handletextpad=0.1,handlelength=1.5,bbox_to_anchor=(1.0, 1.235),frameon=False,columnspacing=1.0,ncol=2)

fig.set_canvas(matplotlib.backends.backend_svg.FigureCanvasSVG(fig))
fig.savefig('C:\plot.svg')
fig.clear()

enter image description here

В идеале я хотел бы создать график, а затем расширить холст некоторым методом без обрезки существующего пробела, чтобы сделать график более компактным.Должны быть расширены только те области холста, которые в противном случае привели бы к обрезанию элементов, таких как внешние условные обозначения или метки осей. Единственное ограничение, которое у меня есть, это то, что я не могу использовать pyplot.

Конечно, я могу настроить свойства легенды, пока не найду конфигурацию, которая может работать именно для этого графика.Но я надеюсь, что есть универсальный способ решить эту проблему для любого вида сюжета.

Любой ответ высоко ценится.

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Если я правильно понимаю, вы хотите ограничить опцию "tight", чтобы только расширить фигуру, а не обрезать ее.Так как такой предопределенной опции не существует, вам нужно сначала вычислить ограниченную рамку и использовать только те значения из нее, которые меньше / больше, чем размеры фигуры.

import matplotlib.figure
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.transforms import Bbox

fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],
                        loc='upper right',borderpad=0.06,handletextpad=0.1,
                        handlelength=1.5,bbox_to_anchor=(1.0, 1.235),
                        frameon=False,columnspacing=1.0,ncol=2)

canvas = FigureCanvasAgg(fig)

fig.canvas.draw()
renderer = fig._cachedRenderer
tightbox = fig.get_tightbbox(renderer)
w,h = fig.get_size_inches()
bbox = Bbox.from_extents(min(tightbox.x0,0), min(tightbox.y0,0),
                         max(tightbox.x1,w), max(tightbox.y1,h))

fig.savefig('cropplot.png', bbox_inches=bbox, facecolor="#fff9e3")

enter image description here

Здесь я сделал фон рисунка разноцветным, чтобы хорошо видеть границы.Также обратите внимание, что я заменил холст svg обычным холстом agg, потому что иначе нет доступного рендерера.

Следующий код должен работать для более старых версий matplotlib.Это оставит ширину фигуры нетронутой и только увеличит фигуру в вертикальном направлении.

import matplotlib.figure
from matplotlib.backends.backend_agg import FigureCanvasAgg

def CreateTightBbox(fig):
    from matplotlib.transforms import Affine2D, Bbox, TransformedBbox
    from matplotlib import rcParams

    w,h = fig.get_size_inches()
    renderer = fig._cachedRenderer
    bbox_artists = fig.get_default_bbox_extra_artists()
    bbox_filtered = []

    for a in bbox_artists:
        bbox = a.get_window_extent(renderer)
        if a.get_clip_on():
            clip_box = a.get_clip_box()
            if clip_box is not None:
                bbox = Bbox.intersection(bbox, clip_box)
            clip_path = a.get_clip_path()
            if clip_path is not None and bbox is not None:
                clip_path = clip_path.get_fully_transformed_path()
                bbox = Bbox.intersection(bbox, clip_path.get_extents())
        if bbox is not None and (bbox.width != 0 or bbox.height != 0):
            bbox_filtered.append(bbox)

    if bbox_filtered:
        _bbox = Bbox.union(bbox_filtered)
        trans = Affine2D().scale(1.0 / fig.dpi)
        bbox_extra = TransformedBbox(_bbox, trans)
        bbox_inches = Bbox.union([fig.bbox_inches, bbox_extra])

    pad = rcParams['savefig.pad_inches']
    bbox_inches = bbox_inches.padded(pad)
    bbox = Bbox.from_extents(0, min(bbox_inches.y0,0), w, max(bbox_inches.y1,h))

    return bbox


#create the figure
fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],
                        loc='upper right',borderpad=0.06,handletextpad=0.1,
                        handlelength=1.5,bbox_to_anchor=(1.0, 1.235),
                        frameon=False,columnspacing=1.0,ncol=2)

#set the canvas
canvas = FigureCanvasAgg(fig)
fig.canvas.draw()
w,h = fig.get_size_inches()

#create tight bbox
bbox = CreateTightBbox(fig)

#print bbox
fig.savefig('cropplot.png', bbox_inches=bbox, facecolor="#fff9e3")
0 голосов
/ 24 октября 2018

Не работает ли передача bbox_inches='tight' в savefig()?

import matplotlib
import matplotlib.backends.backend_svg

fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],loc='upper right',borderpad=0.06,handletextpad=0.1,handlelength=1.5,bbox_to_anchor=(1.0, 1.235),frameon=False,columnspacing=1.0,ncol=2)

fig.set_canvas(matplotlib.backends.backend_svg.FigureCanvasSVG(fig))
fig.savefig('C:\plot.jpg', bbox_inches='tight')
fig.clear()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...