subplot python
Matplotlib savefig con una leyenda fuera de la trama (3)
Aunque este método funciona con leyenda, parece que no funciona bien con figlegend cuando hay múltiples subparcelas y queremos una única leyenda general. figlegend aún se recorta cuando savefig. Acabo de pegar mi solución temporal a continuación en caso de que alguien se enfrenta a un caso así.
import matplotlib.pyplot as plt
para = {
## this parameter will indicate the position of
## subplot within figure, but will not be shown
## if using bbox_inches=''tight'' when saving
''figure.subplot.top'': 0.5
}
#plt.rcParams.update(para)
fig = plt.figure()
ax=fig.add_subplot(221)
## only needed when what to manually control
## subplot ration
#ax.set_position([0.1,0.6,0.5, 0.4])
ax.plot([1,1,1])
ax=fig.add_subplot(222)
#ax.set_position([0.7,0.6,0.5, 0.4])
ax.plot([2,2,2])
ax=fig.add_subplot(223)
#ax.set_position([0.1,0.1,0.5, 0.4])
ax.plot([3,3,3])
ax=fig.add_subplot(224)
#ax.set_position([0.7,0.1,0.5, 0.4])
p1, = ax.plot([4,4,4])
p2, = ax.plot([2,3,2])
## figlegend does not work fine with tight bbox
## the legend always get cropped by this option
## even add bbox extra will not help
## had to use legend, and manually adjust it to
## arbitary position such as (0.3, 2.5)
## http://matplotlib.org/users/tight_layout_guide.html
## according to this link, tight layout is only
## an experimental feature, might not support figlegend
#lgd = plt.figlend(
lgd = plt.legend(
[p1,p2],
[''a'', ''b''],
## by default, legend anchor to axis, but can
## also be anchored to arbitary position
## positions within [1,1] would be within the figure
## all numbers are ratio by default
bbox_to_anchor=(-0.1, 2.5),
## loc indicates the position within the figure
## it is defined consistent to the same Matlab function
loc=''center'',
ncol=2
#mode="expand",
#borderaxespad=0.
)
#plt.show()
plt.savefig(''temp.png'', bbox_inches=''tight'')#, bbox_extra_artist=[lgd])
Leyendo el siguiente artículo, logré poner una leyenda fuera de la trama.
código:
import matplotlib.pyplot as pyplot
x = [0, 1, 2, 3, 4]
y = [xx*xx for xx in x]
fig = pyplot.figure()
ax = fig.add_subplot(111)
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width*0.8, box.height])
ax.plot(x, y)
leg = ax.legend([''abc''], loc = ''center left'', bbox_to_anchor = (1.0, 0.5))
#pyplot.show()
fig.savefig(''aaa.png'', bbox_inches=''tight'')
pyplot.show()
muestra el trazado correcto con una leyenda fuera de él. Pero cuando lo fig.savefig()
como un archivo con fig.savefig()
, la leyenda se trunca.
Algunos google me muestran soluciones como agregar bbox_extra_artists=[leg.legendPatch]
o bbox_extra_artists=[leg]
a savefig()
, pero ninguno funcionó.
¿Cuál es la forma correcta de hacerlo? La versión Matplotlib es 0.99.3.
Gracias.
El problema es que cuando traza dinámicamente, matplotlib
determina los bordes automáticamente para que se ajusten a todos sus objetos. Cuando guarda un archivo, las cosas no se están haciendo automáticamente, por lo que debe especificar el tamaño de su figura y luego el cuadro delimitador de su objeto de ejes. Aquí es cómo corregir su código:
import matplotlib.pyplot as pyplot
x = [0, 1, 2, 3, 4]
y = [xx*xx for xx in x]
fig = pyplot.figure(figsize=(3,3))
ax = fig.add_subplot(111)
#box = ax.get_position()
#ax.set_position([0.3, 0.4, box.width*0.3, box.height])
# you can set the position manually, with setting left,buttom, witdh, hight of the axis
# object
ax.set_position([0.1,0.1,0.5,0.8])
ax.plot(x, y)
leg = ax.legend([''abc''], loc = ''center left'', bbox_to_anchor = (1.0, 0.5))
fig.savefig(''aaa.png'')
Si todo lo demás falla, utilizo las funciones de recuadro delimitador de Inkscape para tratar lo que llamaría errores persistentes en la salida de matplotlib. Si está ejecutando GNU / Linux, simplemente guarde lo que Matplotlib le proporcione como pdf, y luego envíelo a la siguiente
def tightBoundingBoxInkscape(pdffile,use_xvfb=True):
"""Makes POSIX-specific OS calls. Preferably, have xvfb installed, to avoid any GUI popping up in the background. If it fails anyway, could always resort to use_xvfb=False, which will allow some GUIs to show as they carry out the task
pdffile: the path for a PDF file, without its extension
"""
usexvfb=''xvfb-run ''*use_xvfb
import os
assert not pdffile.endswith(''.pdf'')
os.system("""
inkscape -f %(FN)s.pdf -l %(FN)s_tmp.svg
inkscape -f %(FN)s_tmp.svg --verb=FitCanvasToDrawing /
--verb=FileSave /
--verb=FileQuit
inkscape -f %(FN)s_tmp.svg -A %(FN)s-tightbb.pdf
"""%{''FN'':pdffile}