Je souhaite tracer un graphique a partir d'un tableau Excel, qui doit afficher en abscisses les numéros de semaine. Le souci c'est que mon outil affiche les dates en ordre croissant ce qui n'est pas toujours le cas dans le tableau. Le principe est que l'outil affiche 10 semaines en partant de la date la plus récente et en revenant en arrière par ordre décroissant, et si une date est éloignée de paquet de 10 il l'affiche pas, aves vous une idée sur comment puis je régler ca svp ?
La partie de code concernée :
e2 = data1.iloc[0:4, 0:11] #Récupérer la data
#dans le tableau
CWmax = e2['Unnamed: 3'][0].isocalendar()[1]
x = []
for i in range(CWmax, CWmax - 10, -1):
x.append('CW' + str(i))
y1 = e2.loc[1] #Coverage
y2 = e2.loc[2] #Completness
y3 = e2.loc[3] #Consistency
Y1 = np.ma.masked_where(y1 == 0, y1) #Si la donnée = 0 On met un trou dans le graphe
Y2 = np.ma.masked_where(y2 == 0, y2)
Y3 = np.ma.masked_where(y3 == 0, y3)
plt.figure(figsize=(10, 5))
plt.grid(True)
plt.plot(x, Y1, '-o', label='Coverage', lw=3)
plt.plot(x, Y2, '-o', label='Completness', lw=3)
plt.plot(x, Y3, '-o', label='Consistency', lw=3)
Le tableau :
Le graphe obtenu avec l'outil (faux) :
En essayant de dessiner ca sur Excel, j'ai eu le graphique en dessous et c'est ce que je cherche plus ou moins d'afficher avec l'outil (dont le code est sur la photo en haut) :
si tes données ne correspondent pas à ces x, comment python peut-il le savoir ? lui il fait la correspondance x[0] <=> y[0] il ne connait pas la date dans le fichier. A la limite, convertit chaque date en numéro de semaine pour x.
Sinon, c'est bien ce que je fais la, convertir chaque date en numéro de semaine ?
CWmax = e2['Unnamed: 3'][0].isocalendar()[1]
Je suis tout a fait d'accord pour la correspondance mais je ne vois pas trop comment la faire, genre de relier les x avec les y, auras tu une idée stp ?
il faudrait afficher ce que vaut e2['Unnamed: 3'][i] à chaque tour (on va peut-être trop loin)
x=[]
for i in range(len(e2['Unnamed: 3'])):
print(f"valeur pour i={i}: {e2['Unnamed: 3']}")
try:
x.append('CW' + str(e2['Unnamed: 3'][i].isocalendar()[1]))
except:
print("erreur conversion date")
Apparemment c'est une erreur de dimension, et pourtant avec la 1ere version du code y a pas ce problème.
Ah oui pour les 4 tours de boucle, c'est la même date qu'il prenne, cela a peut être une relation avec "have shapes (1, ) and (10, ), donc e2['Unnamed: 3'] c'est que la 1ere date !
e2 = data1.iloc[0:4, 0:11] #Récupérer la data dans le tableau
CWmax = e2.loc[0].isocalendar()[1]
x=[]
for i in range(len(e2.loc[0])):
print(f"valeur pour i={i}: {e2.loc[0]}")
try:
x.append('CW' + str(e2.loc[0][i].isocalendar()[1]))
except:
print("erreur conversion date")
j'ai eu ca :
File "<ipython-input-24-83efcc4ef028>", line 263, in part1
CWmax = e2.loc[0].isocalendar()[1]
File "C:\Users\HP\anaconda3\lib\site-packages\pandas\core\generic.py", line 5139, in __getattr__
return object.__getattribute__(self, name)
AttributeError: 'Series' object has no attribute 'isocalendar'
En effet, j'ai retiré carrément la ligne CWmax puisque on en a plus besoin vu que dans la boucle on s'en sert plus, mais j'ai encore deux problèmes :
1 er problème:
En commentant CWmax, ca m'affiche cela :
File "C:\Users\HP\anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 399, in _plot_args
raise ValueError(f"x and y must have same first dimension, but "
ValueError: x and y must have same first dimension, but have shapes (8,) and (10,)
Je ne comprend pas le problème de dimension en x y, sachant que sur le tableau y a 8 semaines contre 8 y. J'ai remarqué que ca peut être cette ligne la ou il récupère les données de tableau, donc j'ai mis a la place de 11 un 8 et ca a fonctionner sauf que de base le tableau continent 11 colonnes et pas 8, ce cas de figure est juste un exemple, d'ailleurs mon but des le départ est que l'outil s'adapte a tous les cas de figures. As tu une idée de régler ce probleme de dimension sans avoir toucher le 11 stp ?
e2 = data1.iloc[0:4, 0:11]
2 ème problème :
En affichant le graphes après avoir remplacer le 8 par 11, ca donne comme la photo en bas, c'est bien les bons numéros de semaines qu'il affiche sur l'axe des abscisses, par contre ce n'est pas exactement ce je cherche. Je cherche a avoir un graphe qui ressemble a celui obtenu par Excel, c'est a dire de mettre la plus récente date a la fin de graphe (qui est toujours présentée sur la 1 ère colonnes de tableau) et ensuite de prendre 10 semaines avant cette date consécutives en ordre décroissant, peu importe s'il sont présentes dans le tableau ou pas, après si une date n'est pas présente il trace uniquement le tri sans mettre le grand point (.), exemple la semaine juste avant CW35 (dernière semaine) CW34 (elle n'est pas présente dans le tableau.
Le graphe obtenu en remplacant le 11 par 8 :
Le graphe que je veux avoir :
Le code :
e2 = data1.iloc[0:4, 0:11] #de base c'est 11 colonnes et pas 8
#CWmax = e2.loc[0].isocalendar()[1]
x=[]
for i in range(len(e2.loc[0])):
print(f"valeur pour i={i}: {e2.loc[0]}")
try:
x.append('CW' + str(e2.loc[0][i].isocalendar()[1]))
except:
print("erreur conversion date")
self.progress_bar["value"] = 40
root.update()
y1 = e2.loc[1] #Coverage
y2 = e2.loc[2] #Completness
y3 = e2.loc[3] #Consistency
Y1 = np.ma.masked_where(y1 == 0, y1) #Si la donnée = 0 On met un trou dans le graphe
Y2 = np.ma.masked_where(y2 == 0, y2)
Y3 = np.ma.masked_where(y3 == 0, y3)
plt.figure(figsize=(10, 5))
#plt.figure(figsize=(20, 10))
plt.grid(True)
plt.plot(x, Y1, '-o', label='Coverage', lw=3)
plt.plot(x, Y2, '-o', label='Completness', lw=3)
plt.plot(x, Y3, '-o', label='Consistency', lw=3)
1er problème: ça doit provenir d'erreur de conversion de date pour x (tu dois voir afficher 2 erreurs dans la console) => faire x.append(0) dans le else du try
2ème problème: dans ton tableau, tu n'as pas toutes les semaines, il faut donc créer les valeurs manquantes et ensuite ne retenir que les semaines voulues (ton graphe excel ne prends pas les 10 dernières semaines (du 9/6/21 au 1/9/21, il y a plus de 10 semaines ). Les numéros de semaines comme tu les enregistres (CW25) sont pour matplotlib des catégories (comme pomme, poire, ananas, banane, il n'y a de classement logique entre 2 catégories), pas une succession de valeurs.
A essayer, remplir ton x avec la valeur de la semaine uniquement, sans la transformer en chaine, et voir le résultat.
A essayer ensuite, prendre les vraies dates pour tracer la courbes et modifier xticklabel avec les numéros de semaine.
Premièrement, je te remercie infiniment pour ton temps et tes explications.
1er problème : Ca a bien fonctionner en mettant x.append(0) dans le except de try. Le problème de dimension n'apparait plus, je comprend qu'il affecte 0 aux deux autres valeurs de x (avant de changer le except : x and y must have same first dimension, but have shapes (8,) and (10,))
2eme problème :je ne comprend pas quand tu disais il faut créer les valeurs manquantes, tu veux dire sur le tableau Excel (ce qui n'est pas possible puisque le tableau a été donné ainsi) ou bien dans le code sachant que les dates changes chaque semaine (en général ce sont des dates consécutives mais il peut y avoir un trou comme ce cas de figure). Il y a pas un moyen comme en mathématique, quand on a deux points on trace une ligne droite entre les deux points puisque on ne connais les valeurs de points entre eux. Je comprends bien qu'il n'y a pas de classement logique entre 2 catégories, y a t'il un moyen de les rendre comme des points et pas des catégories stp ?
J'ai essayé ta 1ere proposition (ce que j'ai compris) mais ca affiche la même chose sauf a la place des numéros, il met la date entière :
e2 = data1.iloc[0:4, 0:11] #de base c'est 11 colonnes et pas 8
#CWmax = e2.loc[0].isocalendar()[1]
x=[]
for i in range(len(e2.loc[0])):
print(f"valeur pour i={i}: {e2.loc[0]}")
try:
#x.append('CW' + str(e2.loc[0][i].isocalendar()[1]))
x.append('CW' + str(e2.loc[0][i]))
except:
x.append(0)
#print("erreur conversion date")
Le graphique en sortie :
- Effectivement il y a plus de 10 semaine dans le graphe Excel mais cela ne me pose pas trop de problème, si je peux avoir un truc qui ressemble a cela avec les numéros de semaines en abscisse c'est tout ce que je cherche. Apres, il y'a peut être un moyen de limite le nombre de semaine a afficher non ? genre d'afficher de 03/09 jusqu'à 30/06 (ce qui fait 10 semaines) et de laisser les autres même s'il sont présentées dans le tableau. Apres, comme je disais cela ne me posera pas un grand problème même s'il affiche les 13 semaines comme sur le graphe d'Excel c'est TOP, sauf quand une date est très éloignée de reste comme 09/02 celle la on l'affiche pas comme exactement sur Excel.
Peux tu stp me proposer un bout de code pour résoudre ca, je suis un peu perdu, je cherche seulement a avoir un truc similaire au graphe d'Excel avec des numéros de semaines successifs même que certaines ne sont pas présentes dans le tableau ?
Mon code actuel :
e2 = data1.iloc[0:4, 0:11] #de base c'est 11 colonnes et pas 8
#CWmax = e2.loc[0].isocalendar()[1]
x=[]
for i in range(len(e2.loc[0])):
print(f"valeur pour i={i}: {e2.loc[0]}")
try:
#x.append('CW' + str(e2.loc[0][i].isocalendar()[1]))
x.append(str(e2.loc[0][i]))
except:
x.append(0)
#print("erreur conversion date")
self.progress_bar["value"] = 40
root.update()
y1 = e2.loc[1] #Coverage
y2 = e2.loc[2] #Completness
y3 = e2.loc[3] #Consistency
Y1 = np.ma.masked_where(y1 == 0, y1) #Si la donnée = 0 On met un trou dans le graphe
Y2 = np.ma.masked_where(y2 == 0, y2)
Y3 = np.ma.masked_where(y3 == 0, y3)
plt.figure(figsize=(10, 5))
#plt.figure(figsize=(20, 10))
plt.grid(True)
plt.plot(x, Y1, '-o', label='Coverage', lw=3)
plt.plot(x, Y2, '-o', label='Completness', lw=3)
plt.plot(x, Y3, '-o', label='Consistency', lw=3)
Merci beaucoup pour ton aide, je 'approche a ce que je cherche.
Néanmoins, j'ai 3 petites dernières question :
1ère question : A la place d'affecter un 0 aux semaines manquantes dans le tableau, y 'a t'il un moyen de donner la valeur de y précédent en mode que ce fasse une ligne entre les points (mais sans afficher un grand . sur la ligne au niveau de ces semaine manquantes).
J'ai essaye de remplacer le 0 par y1 et y2 et y3 et ca a planté, et en essayant de mettre comme sur le code suivant, ca donne le graphe d'aprés et si bien ce que je cherche mais sans les grands cercles sur la ligne au niveau des semaines manquantes.
l'Ideal est que ca s'adapte aux valeurs qu'on a, par exemple -10 par rapport a la valeur la plus faible et +10 par rapport la valeur la plus haute, en arrondissant a la dizaine en dessous ou en au-dessus, cela permettra de mieux voir le détail quand on traine entre 95% et 100% et même si on a des valeur moins de 50%. J'ai essayé de faire cela
ax.set_ylim([min(e2) - 10,max(e2) + 10])
TypeError: unsupported operand type(s) for -: 'str' and 'int'
3ème question : J'ai un autre cas a prendre en considération, est que au début de l'année prochaine on se retrouvera avec des semaine de la nouvelle année et des semaine de l'année d'avant, avec le code actuel l'outil va afficher CW0, CW-1, CW-2... ce qui n'est pas bien, il devait afficher CW1, CW52 (ou CW53), CW51(ou CW52), …. A savoir que existe des années qui contiennent 52 semaines et d'autres ont 53 semaines, et ce cas la je l'ai bien étudié avec mon ancien code ( code en bas ) mais je ne sais pas comment intégré cela avec le nouveau code ? :
x = []
year = datetime.now().year - 1 #current year - 1
nb_Week = Week.last_week_of_year(year).week #renvoie le nombre de semaines de l'année précisée
for i in range(CWmax, CWmax - 10, -1):
if i<=0 : #si i <= 0 (i = 0 pour commencer avec semaine 1 au lieu semaine 0 ) donc :
W = nb_Week + i #l'indice de la semaine = le nombre de semaines en année + (-i)(on est dans la partie négative)
else :
W = i #Si on est dans la partie positive est égal a i
x.append('CW' + str(W))
Je m'excuse que si mon sujet a tellement durer aussi longtemps.
2) c'est quoi e2 déjà ? c'est plutôt le max sur les y qu'il faut déterminer
1) à la place de 0, il faut mettre un np.nan; par défaut, matplotlib ne les affiche pas sur les courbes mais normalement, avec le masquage (ligne 29 à 31) ça devrait fonctionner aussi; enfin ne pas mettre de point pour ces valeurs
1&3) comme je t'avais prooposé avant, conserver pour X les valeurs réelles de la date et afficher en xticklabel la semaine. ça devrait donner un truc comme ça
ax.set_ylim([min(map(min,range(round(Y1),round(Y2),round(Y3))))-10,max(map(max,range(round(Y1),round(Y2),round(Y3))))+10])
ValueError: cannot convert float NaN to integer
2eme point :
Je voulais aussi te demander est ce que t'as une idée sur comment régler le problème des numéros de semaines négatifs au début de nouvelle années (question 3- message précèdent), je l'ai bien étudier avec mon ancien code en faisant appel aux fonctions datetime.now() et last_week_of_year() comme le montre le code suivant :
x = []
year = datetime.now().year - 1 #current year - 1
nb_Week = Week.last_week_of_year(year).week #renvoie le nombre de semaines de l'année précisée
for i in range(CWmax, CWmax - 10, -1):
if i<=0 : #si i <= 0 (i = 0 pour commencer avec semaine 1 au lieu semaine 0 ) donc :
W = nb_Week + i #l'indice de la semaine = le nombre de semaines en année + (-i)(on est dans la partie négative)
else :
W = i #Si on est dans la partie positive est égal a i
x.append('CW' + str(W))
Pour retirer les valeurs nan, il faut faire Y1=y1[~np.isnan(y1)] ou Y1=y1[np.logical_not(np.isnan(y1))] mais bon ça ne marche qu'avec des np.array, pas des listes grrr; donc autant simplifié les choses à la base.
sinon ton erreur en 1, c'est qu'apparemment au moins un des Y ne contient qu'une valeur
Je viens de tester le nouveau code, il renvoie encore une erreur de unpacking en mode :
File "<ipython-input-6-b9fa2f09ef39>", line 391, in part1
year,week,day=e2.loc[0][i].isocalendar()[1]
TypeError: cannot unpack non-iterable int object
@PB68
PB68 a écrit:
Bonjour.
Pour ton problème avec les numéros de semaine, tu peux éventuellement compléter les labels d'abscisses avec l'année de la semaine concernée.
CW52/2021 ----> CW01/2022 ----> CW02/2022
Je vois bien, mais l'essentiel pour moi est qu'il n'affiche pas les nombres négatifs au début de l'année prochaine de sorte : CW-1 ----> CW0 ---->CW01, après si je rajoute l'année j'ai peur que la case ne suffira pas et y aura un chevauchement d'écriture avec une superposition des caractères donc on ne pourra pas voir ce qui est ecrit. Le fait d'afficher : CW52 (ou CW53) ----> CW01 ----> CW02 ... c'est déjà top pour moi.
arf, encore un oubli: il faut supprimer les crochets finaux (correction faite dans le code)
pourquoi il y aurait des nombres négatifs? le calcul du numéro de semaine est faite par isocalendar() qui renverra la bonne valeur.
(dans la version précédente du code, ça aurait été possible avec le week = week-1, mais aurait en théorie été supprimé ensuite, car par de valeurs associées dans ce cas là)
Ah cool, mais je crois que les dates sont inversées et y'a des points que ne sont pas en face des dates :
Est ce normal que les points sont un peu décalées ?
Pour le problème de l'inversement des dates j'ai cru que c'était a cause de cette lignes que j'ai du rajouter pour le tout premier code mais je l'ai commenté après et y a toujours le problème qui persiste :
En fait, comme je l'ai dit, on trace le graphe avec les vrais dates, donc le tracé se fait dans l'ordre des dates, qu'importe leur placement (sauf erreur de ma part) donc la date la plus ancienne à la date la plus récente; ce qui ne correspond pas à l'ordre des labels contenu dans X qui sont affichés dans l'ordre de la liste.
Donc, effectivement, il faudrait inverser la liste X (on pourrait faire X.reverse())
Mais le mieux serait ici de remplacer les append par des insert(0,..) (on insère les nouvelles données en début de liste)
"Mais le mieux serait ici de remplacer les append par des insert(0,..) (on insère les nouvelles données en début de liste)"
Je ne crois pas d'avoir bien compris ce que tu veux dire, peux tu modifier sur le code stp ?
Apres aussi si tu regarde dans le graphe la semaine de 26 on doit bien avoir un point mais je ne le vois pas.
Enfaite ce graphe la est très juste :
On avait besoin seulement de retirer la semaine 6 puisque elle est très loin et de créer l'espace entre la semaine 35 et 28 (une ligne sans points dessus) .
Apres je crois que c'est plus juste que les points ne sont pas en face des numéros de dates vu la semaine commence le lundi et dans le tableau la plupart des jours sont des vendredi même y 'a un jeudi. Le problème que dans le nouvel graphe y a des points qui n'ont pas de sens comme celui ci par exemple :
J'ai rajouté le X.reverse(), mais ca n'a rien fait, toujours le même graphe :
les points sur le graph correspondent aux semaines 25, 26, 27, 28 et 35 dans cet ordre (ordre inverse de l'affichage en bas, mais j'ai déjà expliqué pourquoi)
"remplacer append par insert(0,..)" bah il faut remplacer les appels de fonctions, rien de plus
year,week,day=e2.loc[0][0].isocalendar()
#Insérer un 0 avant le numéro de semaine si < 10
if week < 10:
week = "0" + str(week)
x.insert(0, f"CW{week}/{year}")
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
PB68
PB68