Afficher le graphique Matplotlib dans une fenêtre tkinter

Matplotlib via tkinter

a marqué ce sujet comme résolu.

Bonjour à tous ! J’ai un problème avec mon projet en python dont Voici le code :

Date = datetime.now()
year = Date.strftime("%Y")
req = """
      SELECT SUM((vQty * vDetail) + (vQty * vGros)) as CAffaire, vDate FROM eMarque
      INNER JOIN eModele ON eMarque.marqueID = eModele.marqueID
      INNER JOIN sales ON eModele.modeleID = sales.modeleID
      WHERE extract( year FROM vDate ) = %s GROUP BY vDate
   """
 
insert = (year,)
cursor.execute(req, insert)
 
CA = cursor.fetchall()
cf = DataFrame(CA, columns = ['Chiffre Affaire', 'Date'])
 
Month = cf["Date"]
Sales = cf["Chiffre Affaire"]
 
fig = Figure(figsize = (6, 6), dpi = 60)
ax = fig.add_subplot(111)           
ax.bar(Sales, Month, width= 1, edgecolor= "white", linewidth=0.7)          
ax.legend()
 
graph = FigureCanvasTkAgg(fig, master= datSet)
canvas = graph.get_tk_widget()
canvas.place(x= 700, y= 170)

J’aimerais afficher le résultat de mon dataframe sous forme de graphique matplotlib mais que ce resultat s’affiche sur une fenêtre tkinter et non sur plt.show de matplotlib. J’ai besoin de votre aide pour trouver la solution. Merci  pour votre aide!

+0 -0

Salut,

Il faut utiliser le backend FigureCanvasTkAgg. Il y a un exemple dans la documentation. Ce qui t’intéresse est surtout le début, jusqu’au canvas = FigureCanvasTkAgg(fig, master=root) qui prend une figure matplotlib et une fenêtre tkinter. canvas.draw() permet ensuite de tracer le plot lui-même.

+0 -0

Ah, je vois que tu as édité et que tu utilises maintenant FigureCanvasTkAgg. Du coup, quel est ton problème, à présent? On ne peut pas tester ton code, un exemple qu’on pourrait faire tourner nous même sur des données bidons serait plus utile. Là, on n’a pas besoin de ta requête SQL ; par contre on a besoin de datSet et des imports variés que tu fais qui n’apparaissent pas dans le code que tu donnes.

+0 -0

Quand tu dis que "cela ne marche pas", ça veut dire quoi ? Qu’est-ce que tu observes ? Il est aussi important de nous fournir un code que l’on peut exécuter nous-même plutôt que des bouts isolés…

Là en l’occurrence, en recopiant l’exemple donné plus haut avec tes données, ça marche bien pour moi :

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt


def main():
    month = [8, 9, 10, 11, 12]
    turnover = [1360, 818, 8900, 7730, 1825]

    fig, axis = plt.subplots()
    axis.bar(month, turnover, label='turnover')
    axis.legend()

    root = tk.Tk()
    canvas = FigureCanvasTkAgg(fig, master=root)
    canvas.draw()
    canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    tk.mainloop()


if __name__ == "__main__":
    main()

Ça ne devrait pas être trop compliqué à adapter à ton cas je pense.

+2 -0

Bonjour, J’ai un projet un peu identique et étant débutant je n’arrive pas utiliser les données d’un dataframe. Dans votre exemple, les données du df remplaceraient month et turnover. J’ai créé le dataframe dans une fonction que j’appelle dans un menu tkinter mais ensuite je voudrais appeler une autre fonction pour faire un graphique avec les données de ce dataframe. Pourtant mon df est en variable globale. Auriez-vous une méthode pour arriver à mes fins ? Merci.

Salut,

Sans ton code, on ne va pas pouvoir magiquement deviner ce qui pose problème. Par ailleurs, plutôt que d’avoir un dataframe en variable globale, tu ferais mieux de le passer en argument de la fonction chargée de créer le graphique. Les variables globales sont dans l’immense majorité des cas un anti-pattern à éviter car elles rendent le code beaucoup plus difficile à suivre (et donc à débugger et maintenir) que des fonctions isolées avec des entrées et sorties explicites.

+1 -0

Mon premier script python non abouti :p

fen = tk.Tk()
fen.geometry("1200x900")
fen.config(bg = "#87CEEB")
fen.title("Voici mon programme en python")
frame = tk.Frame(fen)
frame.pack()
df = pd.DataFrame()
df2 = pd.DataFrame()
def traitement(): 
    global df # variable globale
    fichier = askopenfilename(initialdir=r"C:\Téléchargements", title="Choisir le fichier à ouvrir",filetypes=[(" CSV Files ","*.csv*")])
    csv_name = path.basename(fichier)
       df = pd.read_csv(fichier, sep=";"
        ,names=["ref", "date", "article", "cara","mat","iddoc","type","gar"]        
        ,index_col='date',parse_dates=True) 
    return df
    
def analyse1():
    df2 = df.drop"article", "cara","mat","iddoc","type","gar"] , axis = 1)
    df2['ref'] = pd.to_numeric(df['ref']) # on convertit les données en entier
    # variable pour le graphique
    month = df2['ref']
    fig = Figure(figsize = (6, 6), dpi = 60) #objet fig pour créer un graphique
    graph = FigureCanvasTkAgg(fig, master= fen) #objet graph qui relie l'objet fig à un objet tkinter 
    ax = fig.add_subplot(2,2,2)  # sous figure à la figure ROW=nombre de lignesCOLONNE=nombre de colonnesPOSITION= position du graphique que vous tracez    
    ax.bar(month, width= 1, edgecolor= "white", linewidth=0.7)          
    ax.legend()
    canvas = graph.get_tk_widget()
    canvas.place(x= 700, y= 170)

#def analyse2():
 
#def exportpdf():                             
menuBar = Menu(fen) # on cree la barre des menus
menuFile = Menu(menuBar, tearoff=0) # On cree un menu principal, on va rappeler la barre des menus "menubar" pour mettre le menuFile dedans.
menuGraphs = Menu(menuBar, tearoff=0)
menuExport = Menu(menuBar, tearoff=0)
menuBar.add_cascade(label="Fichier",menu=menuFile) #on ajoute le menu principal le menufile a la barre de menu qu'on nomme File
menuBar.add_cascade(label="Graphique",menu=menuGraphs)
menuBar.add_cascade(label="Exporter",menu=menuExport)
menuFile.add_command(label="Ouvrir", command=traitement)
menuFile.add_command(label="Fermer", command=fen.destroy)
menuGraphs.add_command(label="Analyse1", command=analyse1)
#menuGraphs.add_command(label="Analyse2", command=analyse2)

#menuExport.add_command(label="Exporter en pdf", command=exportpdf)
                     
fen.config(menu=menuBar)# permet de lier le menu avec la barre de menus

fen.mainloop()
+0 -0

Dis nous ce qui se passe quand tu veux faire marcher ton programme.
Visiblement, tu n’as pas donné un morceau de code complet, on voit juste des fonctions sans leur appel.
Ce code n’est pas un code de débutant, je pense que tu l’as pompé quelque part.

+0 -2

Si c’est bien mon code (créé après des recherches), mais je suis loin d’avoir fini. J’en suis à la fonction 1/3 …

Alors, J’arrive à créer mon dataframe dans la première fonction (via le menu). D’ailleurs faut-il créer les variables df en dehors de la fonction ou bien la variable "global" suffit-elle ? Ensuite je veux faire des graphiques toujours via mon menu tkinter et donc j’ai commencé à coder la fonction analyse. Après m’être documenté, j’ai vu qu’il fallait modifié le dataframe pour avoir les données souhaitées. (cf https://www.youtube.com/watch?v=qHRLG5hsW9I à partir de 2min50 sur index de type datetime) Ici ref et date : je veux un graphique des references par date. Le champ date, je l’ai mis en index_col dans la première fonction mais ensuite dans la fonction analyse1 comment faire pour récupérer sur l’axe x, le champ date c’est-à-dire l’index ?

Ma méthode n’est peut-être pas la bonne, je débute , soyez indulgent.

Merci beaucoup pour votre aide.

+0 -0

Visiblement, tu n’as pas donné un morceau de code complet, on voit juste des fonctions sans leur appel.

Les appels sont fait lors des clicks sur des boutons, les fonctions sont liées avec .add_command.

D’ailleurs faut-il créer les variables df en dehors de la fonction ou bien la variable "global" suffit-elle ?

Pas sûr de comprendre ta question mais oui il faut que df existe dans le scope global si tu veux pouvoir y accéder de partout. Encore une fois, c’est pas une super idée par contre… Quel est le contexte de ton exercice ? Qu’est-ce que tu connais en Python (dans les grandes lignes) ?

Après m’être documenté, j’ai vu qu’il fallait modifié le dataframe pour avoir les données souhaitées

Non, t’en as absolument pas besoin. Tu peux très bien ne plotter que certaines colonnes d’un dataframe sans le modifier d’abord. Autrement dit, df2 est inutile.

Je pense que ton problème vient surtout du placement de ton graphique. Est-ce que tu aurais un fichier de données pour qu’on puisse faire tourner ton code chez nous ? Modifie le si il y a des données sensibles, l’essentiel c’est qu’on puisse faire tourner ton programme tel quel pour diagnostiquer le problème (ou bien que tu sois beaucoup plus précis sur le problème que tu as…).

+0 -0

@adri1 merci beaucoup pour ta réponse. Après beaucoup de recherches, j’ai trouvé comment faire : il suffisait de récupérer la variable et de mettre variable.index et variable.values dans ax.bar Je voudrait maintenant afficher dans tkinter avec mon graph df.head(), je cherche du côté des widgets mais je ne vois pas comment faire pour le moment. Et pour générer le graphique un pdf, il y a un module fpdf ? Comment récupérer le graphique ? Bref, encore plein de questions mais j’avance. :D

Ça pourrait être bien de répondre aux questions que l’on te pose et de montrer ton code au-fur-et-à-mesure… On n’est pas magiciens et en savoir plus sur le contexte dans lequel t’a été posé l’exercice ainsi que l’état courant de ton code nous aiderait à t’aider.

Pour afficher df.head dans une GUI, l’idéal serait un truc dans le genre des table view comme ont Qt ou GTK, mais ça n’a pas l’air d’exister avec tkinter. Tu pourrais utiliser grid pour placer plein de labels sous forme d’une table. C’est du bricolage, mais en même temps tkinter n’est pas franchement conçu pour faire des interfaces complexes.

Pour avoir un pdf, ben tu peux sauvegarder le graphique matplotlib avec Figure.savefig.

+0 -0

Merci encore merci @adri1

Pour afficher le df.head, j’essaye de m’inspirer de ce code :

import pandas as pd import numpy as np

import sys from tkinter import *

root = Tk() root.geometry(’580x250’)

dates = pd.date_range(’20210101’, periods=8) dframe = pd.DataFrame(np.random.randn(8,4),index=dates,columns=list(’ABCD’))

txt = Text(root) txt.pack()

class PrintToTXT(object): def write(self, s): txt.insert(END, s)

sys.stdout = PrintToTXT()

print (’Pandas date range of 8 values in 1 timestamp column adjacent to a numpy random float array of 8 rows and 4 columns, displayed in a Tkinter table’)

print (dframe)

mainloop()

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte