2012-05-16 35 views
18

Estoy tratando de producir un gráfico y estoy teniendo problemas para anotarlo.Matplotlib: Agregue cadenas como x-ticks personalizados pero también mantenga las etiquetas de marcación existentes (numéricas)? Alternativas a matplotlib.pyplot.annotate?

Mi gráfico tiene una escala de registro en el eje x, que muestra la hora. Lo que quiero poder hacer es mantener las etiquetas numéricas numéricas existentes (pero no predecibles) en 100 unidades, 1000 unidades, 10000 unidades, etc., pero también agregar etiquetas de tilde personalizadas al eje x para dejar claro dónde más "humanos" "intervalos de tiempo legibles", por ejemplo, quiero poder etiquetar "una semana", "un mes", "6 meses", etc.

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

Respuesta

16

Si realmente desea agregar ticks extra, puede obtener los existentes usando axis.xaxis.get_majorticklocs(), agregue lo que quiera agregar, y luego configure los ticks usando axis.xaxis.set_ticks(<your updated array>).

Una alternativa sería agregar líneas verticales using axvline. La ventaja es que no tiene que preocuparse por insertar su tic personalizado en la matriz existente, pero tendrá que anotar las líneas manualmente.

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

+1

Gracias. Creo que tiene más sentido agregar un eje x secundario. Mezclar etiquetas numéricas y de ejes de cadena conduce a molestos problemas de superposición y formateo, así que simplemente voy con twiny(). :-) – FakeDIY

+1

que esta pregunta podría ser útil para usted: http://stackoverflow.com/questions/10514315/how-to-add-a-second-x-axis-in-matplotlib –

12

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 necesitará hacer es obtener el locs y labels y luego modificar 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 ejecutar:

xticks(locs, new_labels) 
+0

Esto funciona, pero no es exactamente lo que quiero hacer. Puedo ver que podría usar xticks() para obtener el resultado deseado con el tiempo, pero de hecho creo que será más nítido y más fácil trazar un segundo eje x como se sugiere a continuación. Gracias. – FakeDIY

+0

OK, entonces debes aceptar esa respuesta. Estoy de acuerdo en que esto es más un truco (pero funciona para uso interno/soluciones rápidas). – deinonychusaur

5

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

  • puede especificar los ejes (útil para ejes gemelos o si se trabaja con múltiples ejes simultáneamente)
  • puede especificar el eje (put garrapatas en el eje x o del eje y)
  • Puede agregar fácilmente nuevas marcas mientras mantiene las automáticas
  • 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') 
1

me gusta la respuesta de Miguel anteriormente. Funcionó bastante bien Sin embargo, se debe hacer un pequeño ajuste. La siguiente:

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

debe cambiarse 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 ​​() dict_keys de retorno y objetos dict_values, que hace matplotlib no como (aparentemente). Más sobre esos dos objetos en PEP 3106.

+0

Gracias, agregué su sugerencia a mi respuesta. – Miguel

Cuestiones relacionadas