jumeaux-numeriques/twin_plot_qt.py

313 lines
11 KiB
Python

import sys
import random
import importlib
import matplotlib
import matplotlib.pyplot as plts
import csv
import xml.etree.ElementTree as ET # Creating/parsing XML file
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plts
###############################################################################
# twin_plot_qt.py
# @title: Visualisation des données (pyQt5+Matplotlib)
# @project: Blender-EduTech
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2023 Philippe Roy
# @license: GNU GPL
###############################################################################
# Lecture des configurations
twin_config = ET.parse('twin_config.xml').getroot()
plot_config_tree = ET.parse('plot_config.xml').getroot()
plot_config={}
# csv_file= locals()['csv_file']
# print(locals()['file_csv'])
###############################################################################
# Configuration des plots
###############################################################################
# Génère le dictionnaire plot_config à partir du fichier XML plot_config.xml
def plot_config_dict():
for var in plot_config_tree[0][0]:
var_dict={}
for i in range (len(var)):
if var[i] is not None:
var_dict.update({var[i].tag : var[i].text})
plot_config.update({var.text: var_dict})
# Nombre de groupe de courbe(s)
def plot_nb():
plot_config_list=list(plot_config)
nbgroup = 0
# Regroupement ('group' > 0)
for var in plot_config_list:
if ('group' in plot_config[var]):
if nbgroup < int(plot_config[var]['group']):
nbgroup = int(plot_config[var]['group'])
# Plot solitaire ('group' = 0)
# 'group' = -1 -> variable non affichée
for var in plot_config_list:
if ('group' in plot_config[var]):
if int(plot_config[var]['group']) == 0:
nbgroup +=1
return nbgroup
###############################################################################
# Zone de dessin
###############################################################################
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig, self.plt = plts.subplots(plot_nb(), 1, sharex=True) # plot_nb() : nombre de graphiques
super(MplCanvas, self).__init__(fig)
###############################################################################
# Graphique dynamique
###############################################################################
class DynamicPlot(QtWidgets.QMainWindow):
# Création du graphique
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
self.setCentralWidget(self.canvas)
n_data = 50
# self.xdata = list(range(n_data))
# self.ydata = [random.randint(0, 10) for i in range(n_data)]
self.xdata = [0]
self.ydata = [0]
self.update_plot()
self.show()
# Timer pour le update_plot
fps = 120 # Blender est cadencé à 60 fps
self.timer = QtCore.QTimer()
# self.timer.setInterval(int(1000/fps))
self.timer.setInterval(1)
self.timer.timeout.connect(self.update_plot)
self.timer.start()
print("Qt : Canvas ready\n")
# Lecture des données et mise à jour du graphique
def update_plot(self):
plt = self.canvas.subplot
# Données
msg=""
for line in sys.stdin:
msg = line.rstrip()
break
print("Qt : ", msg)
# Essai
new_x=self.xdata[len(self.xdata)-1]+1
self.xdata.append(new_x)
self.ydata.append(random.randint(0, 10))
# Lecture du Pipe simple
# msg=""
# print (sys.stdin)
# contents = sys.stdin.read(1)
# # contents = sys.stdin.buffer
# print ("contents :", contents)
# for line in sys.stdin:
# msg = line.rstrip()
# break
# print(msg)
# X et Y
# FIXME : temps et une valeur
# msg_list=msg.split(',')
# print(msg_list)
# if msg_list[0] != "":
# self.xdata = self.xdata + [float(msg_list[0])]
# self.ydata = self.ydata + [float(msg_list[1])]
# # Lecture du Pipe
# # i=0
# # lines = sys.stdin.readlines()
# # print (lines)
# # print ("b")
# msg_line=""
# # msg_lines=[]
# for line in sys.stdin:
# # i+=1
# # print (i)
# msg_line = line.rstrip()
# # msg_lines.append(msg_line)
# # print("Qt msg_lines :", msg)
# # if i==2:
# # break
# break
# print("Qt :", msg_line)
# # print("Qt msg_lines :", msg_lines)
# # X et Y
# # FIXME : temps msg_list[0] et une seule valeur msg_list[1]
# msg_list=msg_line.split(',')
# # print(msg_list)
# if msg_list[0] != "":
# self.xdata = self.xdata + [float(msg_list[0])]
# self.ydata = self.ydata + [float(msg_list[1])]
# for line in msg_lines:
# msg_list=line.split(',')
# # print(msg_list)
# if msg_list[0] != "":
# self.xdata = self.xdata + [float(msg_list[0])]
# self.ydata = self.ydata + [float(msg_list[1])]
# for line in sys.stdin:
# msg_list=msg.split(',')
# print(msg_list)
# if msg_list[0] != "":
# self.xdata = self.xdata + [float(msg_list[0])]
# self.ydata = self.ydata + [float(msg_list[1])]
# self.ydata = self.ydata + [random.randint(0, 10)]
# Drop off the first y element, append a new one.
# self.ydata = self.ydata[1:] + [random.randint(0, 10)]
# Redraw
plt.cla()
plt.plot(self.xdata, self.ydata, 'r')
self.canvas.draw()
###############################################################################
# Graphique statique
###############################################################################
class MainWindow(QtWidgets.QMainWindow):
# Création du graphique
def __init__(self, *args, **kwargs):
# Configuration des plots
plot_config_dict()
# Zone graphique (barre d'outil et graphique)
# FIXME : perd de la place quand on agrandi
super(MainWindow, self).__init__(*args, **kwargs)
self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
# print (self.canvas.getContentsMargins())
toolbar = NavigationToolbar(self.canvas, self)
# print (toolbar.getContentsMargins())
# Implantation de la fenêtre
layout = QtWidgets.QVBoxLayout()
# print (layout.getContentsMargins())
# layout.setContentsMargins(0,0,0,0)
layout.addWidget(toolbar)
layout.addWidget(self.canvas)
widget = QtWidgets.QWidget()
# print (widget.getContentsMargins())
widget.setLayout(layout)
self.setCentralWidget(widget)
# print (self.getContentsMargins())
# Lecture fichier CSV
fields = []
rows = []
# with open(csv_file, newline='') as csv_buff:
with open(sys.argv[1], newline='') as csv_buff:
csv_reader = csv.reader(csv_buff, delimiter=';')
fields = next(csv_reader)
for row in csv_reader:
rows.append(row)
# Mise en tableau à deux colonnes (xdata,ydata)
xdata=[]
ydata=[]
i=0
for field in fields:
xdata_row=[]
ydata_row=[]
for row in rows:
xdata_row.append(float(row[0].replace(',', '.'))) # Revenir au format US des décimaux
ydata_row.append(float(row[i].replace(',', '.'))) # Revenir au format US des décimaux
xdata.append(xdata_row)
ydata.append(ydata_row)
i+=1
# Plots
plt_i=0 # Compteur de plot
plt_grp=[] # Groupe de plot
for i in range(len(fields)):
var = fields[i]
plt_current=-1 # Numéro du plot à créer
if ('group' in plot_config[var]): # Pas de Plot
if int(plot_config[var]['group']) !=-1: # Pas de Plot
# Plot solitaire
if int(plot_config[var]['group']) ==0:
plt_current = plt_i
plt_grp.append([plt_i, 0])
plt_i +=1
# Plot groupé
else:
plt_new = True # Flag d'un nouveau groupe
for j in range(len(plt_grp)):
if plt_grp[j][1] == int(plot_config[var]['group']): # Groupe déjà existant
plt_current = plt_grp[j][0]
plt_new = False
break
# Nouveau groupe
if plt_new:
plt_current = plt_i
plt_grp.append([plt_i, int(plot_config[var]['group'])])
plt_i +=1
# Création du plot
if twin_config[1][0].text == "True": # Configuration des plots activée
self.canvas.plt[plt_current].plot(xdata[i], ydata[i], label=var, color=plot_config[var]['color'],
linewidth=plot_config[var]['linewidth'], linestyle=plot_config[var]['linestyle'], marker=plot_config[var]['marker'])
else:
self.canvas.plt[plt_current].plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
# for i in range(len(fields)):
# if i != 0 : # i=0 -> Ne pas afficher car c'est temps (variable t)
# if twin_config[1][0].text == "True": # Configuration des plots activée
# self.canvas.plt[0].plot(xdata[i], ydata[i], label=fields[i], color=plot_config[fields[i]]['color'],
# linewidth=plot_config[fields[i]]['linewidth'], linestyle=plot_config[fields[i]]['linestyle'], marker=plot_config[fields[i]]['marker'])
# else:
# self.canvas.plt[0].plot(xdata[i], ydata[i], '.-', label=fields[i])
# Décoration
self.canvas.plt[plt_i-1].set_xlabel("Temps (s)")
# self.canvas.plt[0].set_ylabel("Valeurs")
self.canvas.plt[0].set_title(sys.argv[1])
for i in range (plt_i):
self.canvas.plt[i].axhline(linewidth=1, color='k')
self.canvas.plt[i].grid(True, linestyle='--')
self.canvas.plt[i].legend()
# Redraw
self.canvas.draw()
self.show()
###############################################################################
# Application
###############################################################################
app = QtWidgets.QApplication(sys.argv)
# w = DynamicPlot()
w = MainWindow() # StaticPlot()
app.exec_()
sys.exit(0)