web-dev-qa-db-fra.com

Date et rotation dans matplotlib

J'ai un problème à essayer de faire pivoter mes ticks de date dans matplotlib. Un petit exemple de programme est ci-dessous. Si j'essaie de faire pivoter les ticks à la fin, les ticks ne sont pas soumis à une rotation. Si j'essaie de faire pivoter les ticks, comme indiqué dans le commentaire "Crashes", alors lib lib de Matplot se bloque.

Cela ne se produit que si les valeurs x sont des dates. Si je remplace la variable dates par la variable t dans l'appel à avail_plot, l'appel xticks(rotation=70) fonctionne parfaitement à l'intérieur de avail_plot.

Des idées?

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

def avail_plot(ax, x, y, label, lcolor):
    ax.plot(x,y,'b')
    ax.set_ylabel(label, rotation='horizontal', color=lcolor)
    ax.get_yaxis().set_ticks([])

    #crashes
    #plt.xticks(rotation=70)

    ax2 = ax.twinx()
    ax2.plot(x, [1 for a in y], 'b')
    ax2.get_yaxis().set_ticks([])
    ax2.set_ylabel('testing')

f, axs = plt.subplots(2, sharex=True, sharey=True)
t = np.arange(0.01, 5, 1)
s1 = np.exp(t)
start = dt.datetime.now()
dates=[]
for val in t:
    next_val = start + dt.timedelta(0,val)
    dates.append(next_val)
    start = next_val

avail_plot(axs[0], dates, s1, 'testing', 'green')
avail_plot(axs[1], dates, s1, 'testing2', 'red')
plt.subplots_adjust(hspace=0, bottom=0.3)
plt.yticks([0.5,],("",""))
#doesn't crash, but does not rotate the xticks
#plt.xticks(rotation=70)
plt.show()
128
Neal

Si vous préférez une approche non orientée objet, déplacez plt.xticks (rotation = 70) vers la droite avant les deux appels de avail_plot, par exemple

plt.xticks(rotation=70)
avail_plot(axs[0], dates, s1, 'testing', 'green')
avail_plot(axs[1], dates, s1, 'testing2', 'red')

Ceci définit la propriété rotation avant de configurer les étiquettes. Puisque vous avez deux axes ici, plt.xticks devient confus une fois que vous avez créé les deux parcelles. Au moment où plt.xticks ne fait rien, plt.gca () fait not vous donne les axes que vous souhaitez modifier, et ainsi plt.xticks, qui agit sur les axes actuels, est ne va pas au travail.

Pour une approche orientée objet qui n’utilise pas plt.xticks, vous pouvez utiliser

plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )

after les deux appels de avail_plot. Ceci définit spécifiquement la rotation sur les bons axes.

198
cge

La solution fonctionne pour matplotlib 2.1 +

Il existe une méthode d'axes tick_params pouvant modifier les propriétés des ticks. Il existe également en tant que méthode d'axe comme set_tick_params

ax.tick_params(axis='x', rotation=45)

Ou

ax.xaxis.set_tick_params(rotation=45)

En guise de remarque, la solution actuelle mélange l'interface à états (avec pyplot) à l'interface orientée objet à l'aide de la commande plt.xticks(rotation=70). Comme le code de la question utilise l'approche orientée objet, il est préférable de s'en tenir à cette approche. La solution donne une bonne solution explicite avec plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )

65
Ted Petrou

Une solution simple qui évite de passer en boucle sur les ticklabes consiste simplement à utiliser

fig.autofmt_xdate()

Cette commande fait automatiquement pivoter les étiquettes xaxis et ajuste leur position. Les valeurs par défaut sont un angle de rotation de 30 ° et un alignement horizontal "à droite". Mais ils peuvent être modifiés dans l'appel de fonction

fig.autofmt_xdate(bottom=0.2, rotation=30, ha='right')

L'argument additionnel bottom équivaut à la définition de plt.subplots_adjust(bottom=bottom), qui permet de définir une valeur plus grande pour le remplissage des axes inférieurs afin d'héberger les étiquettes croisées pivotées.

En gros, vous avez ici tous les paramètres nécessaires pour avoir un axe de date Nice en une seule commande.

Un bon exemple peut être trouvé sur la page matplotlib.

36

Une autre façon d'appliquerhorizontalalignment et rotation à chaque étiquette de tick est de faire une boucle for sur les étiquettes de tick que vous souhaitez modifier:

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

now = dt.datetime.now()
hours = [now + dt.timedelta(minutes=x) for x in range(0,24*60,10)]
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)]
hours_value = np.random.random(len(hours))
days_value = np.random.random(len(days))

fig, axs = plt.subplots(2)
fig.subplots_adjust(hspace=0.75)
axs[0].plot(hours,hours_value)
axs[1].plot(days,days_value)

for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels():
    label.set_rotation(30)
    label.set_horizontalalignment("right")

enter image description here

Et voici un exemple si vous souhaitez contrôler l'emplacement des ticks majeurs et mineurs:

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

fig, axs = plt.subplots(2)
fig.subplots_adjust(hspace=0.75)
now = dt.datetime.now()
hours = [now + dt.timedelta(minutes=x) for x in range(0,24*60,10)]
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)]

axs[0].plot(hours,np.random.random(len(hours)))
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True)
x_minor_lct = matplotlib.dates.HourLocator(byhour = range(0,25,1))
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct)
axs[0].xaxis.set_major_locator(x_major_lct)
axs[0].xaxis.set_minor_locator(x_minor_lct)
axs[0].xaxis.set_major_formatter(x_fmt)
axs[0].set_xlabel("minor ticks set to every hour, major ticks start with 00:00")

axs[1].plot(days,np.random.random(len(days)))
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True)
x_minor_lct = matplotlib.dates.DayLocator(bymonthday = range(0,32,1))
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct)
axs[1].xaxis.set_major_locator(x_major_lct)
axs[1].xaxis.set_minor_locator(x_minor_lct)
axs[1].xaxis.set_major_formatter(x_fmt)
axs[1].set_xlabel("minor ticks set to every day, major ticks show first day of month")
for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels():
    label.set_rotation(30)
    label.set_horizontalalignment("right")

enter image description here

12
Pablo Reyes