Je rencontre des problèmes lors de l'ajout de lignes Matplotlib dans l'intrigue Pandas. J'essaie de tracer une ligne droite en utilisant la pente pour déterminer quels sont les points de départ et d'arrivée. Mais le graphique résultant ne ressemble pas du tout à une ligne droite.

J'ai simplifié le cas au MVCE ci-dessous. La partie initiale est pour la configuration pour reproduire la caractéristique clé du dataframe compliqué que j'ai.

import pandas as pd
import matplotlib.pyplot as plt

LEN_SER = 23
dates = pd.date_range('2015-07-03', periods=LEN_SER, freq='B')
df = pd.DataFrame(range(1,LEN_SER+1), index=dates)
ts = df.iloc[:,0]

# The above is the setup of the MVCE to replicate the issue.

fig = plt.figure()
ax1 = plt.subplot2grid((1, 1), (0, 0))
ax1.plot([ts.index[5], ts.index[20]],
        [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-')
ts.plot(ax=ax1)
plt.show()

Cela donne un graphique qui a une ligne ondulée en raison des week-ends. Le Matplotlib affecte la façon dont Pandas trace la série. Si je retire la ligne ax1.plot (), alors cela devient une ligne droite.

enter image description here

La question est donc: comment dessiner des lignes droites sur mon tracé Pandas avec Matplotlib? En d'autres termes, je veux que le tracé traite les étiquettes des axes comme des catégories afin que les week-ends soient ignorés. De cette façon, j'espère que Matplotlib et Pandas donneront tous les deux une ligne droite.

0
Spinor8 16 août 2020 à 10:35

4 réponses

Meilleure réponse

Comme vous l'observez correctement, si vous supprimez la ligne ax1.plot (), alors matplotlib traite vos dates comme des catégories, et le graphique des pandas est une belle ligne droite. Cependant, dans la commande

ax1.plot([ts.index[5], ts.index[20]],
    [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-')

Vous demandez à matplotlib d'interpoler entre deux points, dans le processus d'interpolation de matplotlib reconnaître les dates dans l'axe des x. C'est pourquoi le graphique des pandas en ligne droite par rapport aux catégories de dates (5 par semaine) devient une ligne ondulée par rapport aux dates (7 par semaine). Ce qui est également correct, car en ce qui concerne les dates, vos données ne sont tout simplement pas représentées par une ligne droite.

Vous pouvez forcer l'interprétation des catégories en remplaçant les dates par des chaînes via

df.index = df.reset_index().apply(lambda x: x['index'].strftime('%Y-%m-%d'), axis=1)

Avant de définir ts. Cela aboutit à l'intrigue

enter image description here

Maintenant, le graphique matplotlib n'est que deux catégories contre deux valeurs et matplotlib ne prend pas la peine de se rendre compte que les deux catégories font partie des catégories du graphique pandas. (La modification de l'ordre des deux tracés enregistre au moins votre axe x.) La modification du tracé matplotlib en

ax1.plot([5, 20], [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-')

Trace une ligne entre les catégories 5 et 20, et vous donne enfin deux lignes droites par rapport à l'axe des x des catégories.

enter image description here

Code complet:

import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('seaborn') # (optional - style was set when I produced my graph)

LEN_SER = 23
dates = pd.date_range('2015-07-03', periods=LEN_SER, freq='B')
df = pd.DataFrame(range(1,LEN_SER+1), index=dates)

df.index = df.reset_index().apply(lambda x: \
    x['index'].strftime('%Y-%m-%d'), axis=1) # dates -> categories (string)
ts = df.iloc[:,0]

# The above is the setup of the MVCE to replicate the issue.

fig = plt.figure()
ax1 = plt.subplot2grid((1, 1), (0, 0))
ax1.plot([5, 20], [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-') 
# x coordinates 'categories' 5 and 20
ts.plot(ax=ax1)
plt.show()
1
Westfalenmats 20 août 2020 à 06:57

Pour simplifier, j'ai commencé du 05/07/2015 au 04 . Est-ce que ça marche pour vous?

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

LEN_SER = 21
dates = pd.date_range('2015-07-04', periods=LEN_SER, freq='B')
the_axes = []
# take the_axes like monday and friday for each week
for monday, friday in zip(dates[dates.weekday==0], dates[dates.weekday==4]):
  the_axes.append([monday.date(), friday.date()])
x = dates
y = range(1,LEN_SER+1)
n_Axes = len(the_axes)
fig,(axes) = plt.subplots(1, n_Axes, sharey=True, figsize=(15,8))

for i in range(n_Axes):
  ax = axes[i]
  ax.plot(x, y)
  ax.set_xlim(the_axes[i])
  fig.autofmt_xdate()
print(dates)
plt.show()

breaklines

0
Ricardo Rendich 19 août 2020 à 09:21

Vous avez raison - c'est dû aux week-ends. Vous pouvez le dire par la pente - cinq jours consécutifs ont une pente plus nette (+1 par jour) que les trois jours consécutifs (+1 au total). Alors, que voulez-vous exactement tracer? Si vous voulez littéralement tracer la ligne bleue, vous pouvez interpoler les points entre vos deux points comme ceci:

...
# ts.plot(ax=ax1)
ts.iloc[[5,20]].resample('1D').interpolate(how='mean').plot(ax=ax1)
plt.show()
0
Landmaster 16 août 2020 à 07:54

Vous avez déjà répondu à la question: "probablement en raison du week-end"

Replace: dates = pd.date_range ('2015-07-03', périodes = LEN_SER, freq = 'B')

Avec

dates = pd.date_range('2015-07-03', periods=LEN_SER, freq='D')

B - fréquence des jours ouvrables D - fréquence des jours civils

Et vos lignes sont redressées.

0
Robert Altena 16 août 2020 à 07:47