Matplotlib: ¿Agregar cadenas como marcas x personalizadas pero también mantener las tags existentes (numéricas)? Alternativas a matplotlib.pyplot.annotate?

Estoy tratando de producir un gráfico y tengo algunos problemas para anotarlo.

Mi gráfica tiene una escala de registro en el eje x, que muestra el tiempo. Lo que quiero poder hacer es mantener las tags numéricas existentes (pero no predecibles) en 100 unidades, 1000 unidades, 10000 unidades, etc., pero también agregar tags personalizadas al eje x que dejen en claro dónde hay más “humanos”. legibles “ocurren intervalos de tiempo, por ejemplo, quiero poder etiquetar ‘una semana’, ‘un mes’, ‘6 meses’, etc.

Puedo usar matplotlib.pyplot.annotate () para marcar los puntos pero realmente no hace lo que quiero. Realmente no quiero texto y flechas en la parte superior de mi gráfico, solo quiero agregar algunas marcas de verificación personalizadas adicionales. ¿Algunas ideas?

Si realmente desea agregar axis.xaxis.get_majorticklocs() adicionales, puede obtener las existentes usando axis.xaxis.get_majorticklocs() , agregar lo que quiera agregar y luego configurar las axis.xaxis.set_ticks() usando axis.xaxis.set_ticks() .

Una alternativa sería agregar líneas verticales usando axvline . La ventaja es que no tiene que preocuparse por insertar su marca personalizada en la matriz existente, sino que tendrá que anotar las líneas manualmente.

Otra alternativa sería agregar un eje vinculado con sus marcas personalizadas.

De http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.xticks :

 # return locs, labels where locs is an array of tick locations and # labels is an array of tick labels. locs, labels = xticks() 

Así que todo lo que debe hacer es obtener las locs y labels y luego modificar las labels a su gusto (ejemplo ficticio):

 labels = ['{0} (1 day)','{0} (1 weak)', '{0} (1 year)'] new_labels = [x.format(locs[i]) for i,x in enumerate(labels)] 

y luego ejecute:

 xticks(locs, new_labels) 

Esta es mi solución. Las principales ventajas son:

  • Puede especificar los ejes (útil para ejes gemelos o si trabaja con varios ejes simultáneamente)
  • Puede especificar el eje (poner marcas en el eje x o el eje y)
  • Puedes agregar fácilmente nuevos ticks manteniendo los automáticos.
  • Se reemplaza automáticamente si agrega una marca que ya existe.

Código:

 #!/usr/bin/python from __future__ import division import matplotlib.pyplot as plt import numpy as np #Function to add ticks def addticks(ax,newLocs,newLabels,pos='x'): # Draw to get ticks plt.draw() # Get existing ticks if pos=='x': locs = ax.get_xticks().tolist() labels=[x.get_text() for x in ax.get_xticklabels()] elif pos =='y': locs = ax.get_yticks().tolist() labels=[x.get_text() for x in ax.get_yticklabels()] else: print("WRONG pos. Use 'x' or 'y'") return # Build dictionary of ticks Dticks=dict(zip(locs,labels)) # Add/Replace new ticks for Loc,Lab in zip(newLocs,newLabels): Dticks[Loc]=Lab # Get back tick lists locs=list(Dticks.keys()) labels=list(Dticks.values()) # Generate new ticks if pos=='x': ax.set_xticks(locs) ax.set_xticklabels(labels) elif pos =='y': ax.set_yticks(locs) ax.set_yticklabels(labels) #Get numpy arrays x=np.linspace(0,2) y=np.sin(4*x) #Start figure fig = plt.figure() ax=fig.add_subplot(111) #Plot Arrays ax.plot(x,y) #Add a twin axes axr=ax.twinx() #Add more ticks addticks(ax,[1/3,0.75,1.0],['1/3','3/4','Replaced']) addticks(axr,[0.5],['Miguel'],'y') #Save figure plt.savefig('MWE.pdf') 

Me gusta la respuesta de Miguel arriba. Funcionó bastante bien. Sin embargo, hay que hacer un pequeño ajuste. El seguimiento:

 # Get back tick lists locs=Dticks.keys() labels=Dticks.values() 

debe ser cambiado a

 # Get back tick lists locs=list(Dticks.keys()) labels=list(Dticks.values()) 

ya que, en Python 2.7 + / 3, Dict.keys () y Dict.values ​​() devuelven dict_keys y dict_values ​​objetos, que a matplotlib no le gusta (aparentemente). Más sobre esos dos objetos en PEP 3106 .