Estoy tratando de imitar el método de legend
en matplotlib.pyplot
donde se puede usar loc='lower right'
para colocar el cuadro de leyenda fijo y correctamente alineado sin importar el eje y el contenido del cuadro.
El uso del text
está fuera, ya que esto requiere la entrada manual de las coordenadas y busco algo automático.
He intentado usar anotar y me ha llegado hasta la mitad, pero aún así no funcionará bien.
Esto es lo que tengo hasta ahora:
import matplotlib.pyplot as plt # Define some names and variables to go in the text box. xn, yn, cod = 'r', 'p', 'abc' prec = 2 ccl = [546.35642, 6785.35416] ect = [12.5235, 13.643241] fig = plt.figure() ax = fig.add_subplot(111) plt.xlim(-1., 10.) plt.ylim(-1., 1.) # Generate text to write. text1 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(xn, ccl[0], ect[0], c=cod, p=prec) text2 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(yn, ccl[1], ect[1], c=cod, p=prec) text = text1 + '\n' + text2 ax.annotate(text, xy=(0.75, 0.9), xycoords='axes fraction', fontsize=10, bbox=dict(facecolor='white', alpha=0.8), horizontalalignment='left', verticalalignment='bottom') plt.savefig('annotate_test.png', dpi=150)
lo que resulta en:
Esto escalará correctamente para cambiar los límites de los ejes, pero el problema es que: 1- fallará si los ejes están configurados en ax.set_aspect('equal')
:
y 2- fallará si el texto es demasiado largo (aquí establezco prec=5
en el MWE anterior):
¿Cómo puedo indicar a matplotlib
que coloque el cuadro de texto siempre en la esquina superior derecha y lo alinee correctamente para que no quede fuera de la imagen (es decir, qué loc
hace en la legend
)?
La forma rápida y sucia es usar el texto alineado a la derecha y arriba y colocarlo en un desplazamiento fijo en puntos desde la esquina de los ejes:
import matplotlib.pyplot as plt # Define some names and variables to go in the text box. xn, yn, cod = 'r', 'p', 'abc' prec = 2 ccl = [546.35642, 6785.35416] ect = [12.5235, 13.643241] fig = plt.figure() ax = fig.add_subplot(111) ax.axis([-1, 10, -1, 1]) # Generate text to write. text1 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(xn, ccl[0], ect[0], c=cod, p=prec) text2 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(yn, ccl[1], ect[1], c=cod, p=prec) text = text1 + '\n' + text2 ax.annotate(text, xy=(1, 1), xytext=(-15, -15), fontsize=10, xycoords='axes fraction', textcoords='offset points', bbox=dict(facecolor='white', alpha=0.8), horizontalalignment='right', verticalalignment='top') plt.show()
Debido a que hemos especificado la alineación superior y derecha, funciona con sus dos casos de borde:
La desventaja de esto es que el texto está alineado a la derecha. Lo ideal sería que la alineación del texto esté separada de la alineación del cuadro. El módulo matplotlib.offsetbox
tiene varios métodos para manejar este tipo de cosas.
Si desea imitar un cuadro de leyenda (hasta los códigos de ubicación), eche un vistazo a matplotlib.offsetbox.AnchoredText
. (Tenga en cuenta que puede ajustar el relleno, etc. a través del pad
y borderpad
kwargs: http://matplotlib.org/api/offsetbox_api.html#matplotlib.offsetbox.AnchoredOffsetbox )
import matplotlib.pyplot as plt import matplotlib.offsetbox as offsetbox # Define some names and variables to go in the text box. xn, yn, cod = 'r', 'p', 'abc' prec = 5 ccl = [546.35642, 6785.35416] ect = [12.5235, 13.643241] fig = plt.figure() ax = fig.add_subplot(111) ax.axis([-1, 10, -1, 1]) # Generate text to write. text1 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(xn, ccl[0], ect[0], c=cod, p=prec) text2 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(yn, ccl[1], ect[1], c=cod, p=prec) text = text1 + '\n' + text2 ob = offsetbox.AnchoredText(text, loc=1) ax.add_artist(ob) plt.show()
Un inconveniente de esto es que ajustar los parámetros de fuente y cuadro para el resultado es un poco contraintuitivo. AnchoredText
acepta un diccionario de parámetros de fuente como el prop
kwarg. El cuadro se puede ajustar después de la inicialización a través del atributo de patch
. Como un ejemplo rápido:
ob = offsetbox.AnchoredText(text, loc=1, prop=dict(color='white', size=20)) ob.patch.set(boxstyle='round', color='blue', alpha=0.5) ax.add_artist(ob)