Conception d'interfaces graphiques interactives pour la visualisation de données et le rendu d'images en Python

La création d'applications de bureau nécessitant une interaction utilisateur et un retour visuel repose sur l'intégration de zones de saisie et de contenuers graphiques. Ce processus combine la conception d'une interface utilisateur (UI) réactive avec des moteurs de calcul et de rendu backend. L'objectif est de capturer des paramètres via des champs de texte, de les traiter, et de projeter le résultat sous forme de graphiques ou d'images générées dynamiquement.

Visualisation de séries numériques avec Tkinter et Matplotlib

Pour les besoins simples de traçage de données, l'association de Tkinter et de Matplotlib est très efficace. L'utilisateur fournit une série de valeurs numériques, qui sont ensuite converties et projetées sur un canevas graphique intégré directement dans la fenêtre principale.


import tkinter as tk
from tkinter import messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

def render_chart():
    try:
        raw_values = data_input_field.get()
        numeric_data = [float(val) for val in raw_values.split(',') if val.strip()]
        if not numeric_data:
            raise ValueError
            
        chart_axis.clear()
        chart_axis.plot(numeric_data, marker='o', linestyle='-', color='teal')
        chart_axis.set_title("Évolution des valeurs")
        chart_axis.set_ylabel("Amplitude")
        chart_axis.grid(True, linestyle='--', alpha=0.7)
        canvas_widget.draw()
    except ValueError:
        messagebox.showwarning("Erreur de format", "Veuillez entrer une liste de nombres séparés par des virgules.")

app_window = tk.Tk()
app_window.title("Analyse de données")
app_window.geometry("700x500")

control_panel = tk.Frame(app_window)
control_panel.pack(pady=15)

tk.Label(control_panel, text="Série de données :").pack(side=tk.LEFT, padx=5)
data_input_field = tk.Entry(control_panel, width=45)
data_input_field.pack(side=tk.LEFT)

figure_obj = Figure(figsize=(6, 4), dpi=100)
chart_axis = figure_obj.add_subplot(111)
canvas_widget = FigureCanvasTkAgg(figure_obj, master=app_window)
canvas_widget.get_tk_widget().pack(expand=True, fill=tk.BOTH, padx=10, pady=10)

tk.Button(app_window, text="Générer le graphique", command=render_chart, bg="lightgray").pack(pady=10)

app_window.mainloop()

Architecture orientée objet avec PyQt5 et Matplotlib

Lorsque l'application nécessite une structure plus robuste, PyQt5 offre une approche orientée objet. Le code suivant illustre comment encapsuler la logique de traitement et d'affichage dans une clase dédiée, facilitant ainsi l'extension des fonctionnalités. Ici, les données sont représentées sous forme d'histogramme pour varier les types de visualisation.


import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QLineEdit, QPushButton, QWidget, QMessageBox
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

class DataVisualizer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Tableau de bord analytique")
        self.resize(800, 600)

        main_layout = QVBoxLayout()

        self.input_box = QLineEdit()
        self.input_box.setPlaceholderText("Entrez les valeurs séparées par des virgules")
        main_layout.addWidget(self.input_box)

        self.process_btn = QPushButton("Visualiser les données")
        self.process_btn.clicked.connect(self.execute_plotting)
        main_layout.addWidget(self.process_btn)

        self.graph_figure = Figure(figsize=(5, 4), dpi=100)
        self.plot_canvas = FigureCanvas(self.graph_figure)
        main_layout.addWidget(self.plot_canvas)

        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

    def execute_plotting(self):
        try:
            text_data = self.input_box.text()
            values = [float(x) for x in text_data.split(',') if x.strip()]
            if not values:
                raise ValueError

            axis = self.graph_figure.add_subplot(111)
            axis.clear()
            axis.bar(range(len(values)), values, color='skyblue', edgecolor='navy')
            axis.set_title("Distribution des valeurs")
            axis.set_xlabel("Index")
            axis.set_ylabel("Valeur")
            self.plot_canvas.draw()
        except ValueError:
            QMessageBox.warning(self, "Données invalides", "Assurez-vous de fournir des nombres valides séparés par des virgules.")

if __name__ == "__main__":
    qt_app = QApplication(sys.argv)
    main_window = DataVisualizer()
    main_window.show()
    sys.exit(qt_app.exec_())

Génération et affichage d'images dynamiques via Pillow

Au-delà des graphiques mathématiques standards, il est possible de générer des images pixel par pixel ou d'y incruster des résultats de calcul. L'exemple ci-dessous utilise Pillow pour créer une image dont les dimensions et le contenu textuel dépendent du carré d'un nombre saisi par l'utilisateur. L'image générée est ensuite convertie en format compatible Tkinter pour être affichée dans un label.


import tkinter as tk
from PIL import Image, ImageDraw, ImageTk

def generate_result_image():
    try:
        user_value = float(entry_widget.get())
        computed_result = user_value ** 2
        
        img_width = max(300, int(computed_result) + 50)
        img_height = 150
        dynamic_image = Image.new('RGB', (img_width, img_height), color='lightyellow')
        drawer = ImageDraw.Draw(dynamic_image)
        
        bar_height = 50
        drawer.rectangle([20, 50, 20 + min(int(computed_result), 250), 50 + bar_height], fill='coral')
        
        result_text = f"Valeur au carré : {computed_result:.2f}"
        drawer.text((20, 110), result_text, fill='darkblue')
        
        tk_image = ImageTk.PhotoImage(dynamic_image)
        display_label.configure(image=tk_image)
        display_label.image = tk_image
        
        status_label.config(text="Calcul réussi.", fg="green")
    except ValueError:
        display_label.configure(image='')
        display_label.image = None
        status_label.config(text="Erreur : Veuillez entrer un nombre valide.", fg="red")

root_window = tk.Tk()
root_window.title("Calcul et Rendu d'Image")

tk.Label(root_window, text="Nombre à calculer :").pack(pady=5)
entry_widget = tk.Entry(root_window)
entry_widget.pack()

tk.Button(root_window, text="Calculer et Afficher", command=generate_result_image).pack(pady=10)

status_label = tk.Label(root_window, text="", fg="black")
status_label.pack()

display_label = tk.Label(root_window)
display_label.pack(pady=10)

root_window.mainloop()

L'intégration de ces composants permet de transformer des entrées textuelles brutes en représentations visuelles exploitables, offrant ainsi une rétroaction immédiate et personnalisée à l'utilisateur au sein de l'interface graphique.

Étiquettes: Python Tkinter PyQt5 Matplotlib Pillow

Publié le 22 juin à 22h23