Python: cuadro de texto de posición fijado en esquina y alineado correctamente

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:

introduzca la descripción de la imagen aquí

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') :

introduzca la descripción de la imagen aquí

y 2- fallará si el texto es demasiado largo (aquí establezco prec=5 en el MWE anterior):

introduzca la descripción de la imagen aquí

¿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() 

introduzca la descripción de la imagen aquí

Debido a que hemos especificado la alineación superior y derecha, funciona con sus dos casos de borde:

introduzca la descripción de la imagen aquí

introduzca la descripción de la imagen aquí


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() 

introduzca la descripción de la imagen aquí

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) 

introduzca la descripción de la imagen aquí