mirror of
https://forge.apps.education.fr/blender-edutech/jumeaux-numeriques.git
synced 2024-01-27 06:56:18 +01:00
Factorisation de la création des plots
This commit is contained in:
parent
b1be7d960d
commit
4d809d45da
@ -18,7 +18,7 @@ scene = bge.logic.getCurrentScene()
|
|||||||
|
|
||||||
# Configuration des variables publiques
|
# Configuration des variables publiques
|
||||||
# 'nom_variable' :
|
# 'nom_variable' :
|
||||||
# - Objet 3D : [nom de l'objet 3D, propriété du stockage de la valeur (activate ou activated_real), échelle (1 si ommis)]
|
# - Objet 3D : [nom de l'objet 3D, propriété associée à la valeur (activate ou activated_real), type de la valeur ('d' (digital, binary), 'a', (analog) ou 'n' (numeric)), échelle (1 si ommis)]
|
||||||
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
|
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
|
||||||
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (matplotlib)
|
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (matplotlib)
|
||||||
#
|
#
|
||||||
|
1
monte_charge/twin_file_wx.py
Symbolic link
1
monte_charge/twin_file_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_file_wx.py
|
1
monte_charge/twin_plot.py
Symbolic link
1
monte_charge/twin_plot.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot.py
|
1
monte_charge/twin_plot_wx.py
Symbolic link
1
monte_charge/twin_plot_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot_wx.py
|
1
poppy_ergo_jr/twin_file_wx.py
Symbolic link
1
poppy_ergo_jr/twin_file_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_file_wx.py
|
1
poppy_ergo_jr/twin_plot.py
Symbolic link
1
poppy_ergo_jr/twin_plot.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot.py
|
1
poppy_ergo_jr/twin_plot_wx.py
Symbolic link
1
poppy_ergo_jr/twin_plot_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot_wx.py
|
@ -18,7 +18,7 @@ scene = bge.logic.getCurrentScene()
|
|||||||
|
|
||||||
# Configuration des variables publiques
|
# Configuration des variables publiques
|
||||||
# 'nom_variable' :
|
# 'nom_variable' :
|
||||||
# - Objet 3D : [nom de l'objet 3D, propriété du stockage de la valeur (activate ou activated_real)]
|
# - Objet 3D : [nom de l'objet 3D, propriété associée à la valeur (activate ou activated_real), type de la valeur ('d' (digital, binary), 'a', (analog) ou 'n' (numeric)), échelle (1 si ommis)]
|
||||||
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut ('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
|
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut ('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
|
||||||
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (Codification de Matplotlib)
|
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (Codification de Matplotlib)
|
||||||
#
|
#
|
||||||
@ -27,27 +27,27 @@ scene = bge.logic.getCurrentScene()
|
|||||||
# Ce distinguo ne concerne que les entrées, les sorties réelles sont forcées par les sorties numériques et vice-versa.
|
# Ce distinguo ne concerne que les entrées, les sorties réelles sont forcées par les sorties numériques et vice-versa.
|
||||||
|
|
||||||
public_vars = {
|
public_vars = {
|
||||||
't' : [['System','time'], [], []],
|
't' : [['System','time','a'],[],[]],
|
||||||
'bp_ext' : [['Bp cote rue','activated'], ['pin', 'd','i'], ['.','-', 'green', 1]],
|
'bp_ext' : [['Bp cote rue','activated','d'],['pin','d','i'],['.','-','green',1]],
|
||||||
'bp_ext_r' : [['Bp cote rue','activated_real'], [], ['.','--', 'green', 1]],
|
'bp_ext_r' : [['Bp cote rue','activated_real','d'],[],['.','--','green',1]],
|
||||||
'bp_int' : [['Bp cote cour','activated'], ['pin', 'd','i'], ['.','-', 'darkgreen', 1]],
|
'bp_int' : [['Bp cote cour','activated','d'],['pin','d','i'],['.','-','darkgreen',1]],
|
||||||
'bp_int_r' : [['Bp cote cour','activated_real'], [], ['.','--', 'darkgreen', 1]],
|
'bp_int_r' : [['Bp cote cour','activated_real','d'],[],['.','--','darkgreen',1]],
|
||||||
'fdc_o' : [['Microrupteur fdc ouvert','activated'], ['pin', 'd','i'], ['.','-', 'orange', 1]],
|
'fdc_o' : [['Microrupteur fdc ouvert','activated','d'],['pin','d','i'],['.','-','orange',1]],
|
||||||
'fdc_o_r' : [['Microrupteur fdc ouvert','activated_real'], [], ['.','--', 'orange', 1]],
|
'fdc_o_r' : [['Microrupteur fdc ouvert','activated_real','d'],[],['.','--','orange',1]],
|
||||||
'fdc_f' : [['Microrupteur fdc ferme','activated'], ['pin', 'd','i'], ['.','-', 'darkorange', 1]],
|
'fdc_f' : [['Microrupteur fdc ferme','activated','d'],['pin','d','i'],['.','-','darkorange',1]],
|
||||||
'fdc_f_r' : [['Microrupteur fdc ferme','activated_real'], [], ['.','--', 'darkorange', 1]],
|
'fdc_f_r' : [['Microrupteur fdc ferme','activated_real','d'],[],['.','--','darkorange',1]],
|
||||||
'mot_o' : [['Moteur','open'], ['pin_open', 'd','o'], ['.','-', 'violet', 1]],
|
'mot_o' : [['Moteur','open','d'],['pin_open','d','o'],['.','-','violet',1]],
|
||||||
'mot_f' : [['Moteur','close'], ['pin_close', 'd','o'], ['.','-', 'darkviolet', 1]],
|
'mot_f' : [['Moteur','close','d'],['pin_close','d','o'],['.','-','darkviolet',1]],
|
||||||
'mot_angle' : [['Moteur','alpha'], [], ['.','-', 'blue', 1]],
|
'mot_angle' : [['Moteur','alpha','a'],[],['.','-','blue',1]],
|
||||||
'mot_vitesse' : [['Moteur','speed'], [], ['.','-', 'darkblue', 1]],
|
'mot_vitesse' : [['Moteur','speed','a'],[],['.','-','darkblue',1]],
|
||||||
'mot_pas' : [['Moteur','step'], [], []],
|
'mot_pas' : [['Moteur','step','a'],[],[]],
|
||||||
'portail_x' : [['Portail','x'], [], ['.','-', 'turquoise', 1]],
|
'portail_x' : [['Portail','x','a'],[],['.','-','turquoise',1]],
|
||||||
'portail_vitesse' : [['Portail','speed'], [], ['.','-', 'darkturquoise', 1]],
|
'portail_vitesse' : [['Portail','speed','a'],[],['.','-','darkturquoise',1]],
|
||||||
'portail_pas' : [['Portail','step'], [], []],
|
'portail_pas' : [['Portail','step','a'],[],[]],
|
||||||
'gyr' : [['Led','activated'], ['pin', 'd','.'], ['.','-', 'gold', 1]],
|
'gyr' : [['Led','activated','d'],['pin','d','.'],['.','-','gold',1]],
|
||||||
'ir_emet' : [['Emetteur IR', 'activated'], ['pin', 'd','o'],['.','-', 'red', 1]],
|
'ir_emet' : [['Emetteur IR','activated','d'],['pin','d','o'],['.','-','red',1]],
|
||||||
'ir_recep' : [['Recepteur IR','activated'], ['pin', 'd','i'],['.','-', 'darkred', 1]],
|
'ir_recep' : [['Recepteur IR','activated','d'],['pin','d','i'],['.','-','darkred',1]],
|
||||||
'ir_recep_r' : [['Recepteur IR','activated_real'], [],['.','--', 'darkred', 1]]}
|
'ir_recep_r' : [['Recepteur IR','activated_real','d'],[],['.','--','darkred',1]]}
|
||||||
|
|
||||||
# Couleurs
|
# Couleurs
|
||||||
color_passive = (0.800, 0.005, 0.315,1) # bouton non activable : magenta
|
color_passive = (0.800, 0.005, 0.315,1) # bouton non activable : magenta
|
||||||
|
Binary file not shown.
1
portail_coulissant/twin_file_wx.py
Symbolic link
1
portail_coulissant/twin_file_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_file_wx.py
|
1
portail_coulissant/twin_plot.py
Symbolic link
1
portail_coulissant/twin_plot.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot.py
|
1
portail_coulissant/twin_plot_wx.py
Symbolic link
1
portail_coulissant/twin_plot_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot_wx.py
|
10
twin_daq.py
10
twin_daq.py
@ -34,8 +34,8 @@ daq_data=[]
|
|||||||
|
|
||||||
def get(data):
|
def get(data):
|
||||||
if data in daq_config:
|
if data in daq_config:
|
||||||
if len (daq_config[data][0])>2: # Echelle à prendre en compte
|
if len (daq_config[data][0])>3: # Echelle à prendre en compte
|
||||||
return(scene.objects[daq_config[data][0][0]][daq_config[data][0][1]]*daq_config[data][0][2])
|
return(scene.objects[daq_config[data][0][0]][daq_config[data][0][1]]*daq_config[data][0][3])
|
||||||
else:
|
else:
|
||||||
return(scene.objects[daq_config[data][0][0]][daq_config[data][0][1]])
|
return(scene.objects[daq_config[data][0][0]][daq_config[data][0][1]])
|
||||||
else:
|
else:
|
||||||
@ -126,6 +126,8 @@ def plot_config_generate(data_groups):
|
|||||||
xml_color.text=daq_config[var][2][2]
|
xml_color.text=daq_config[var][2][2]
|
||||||
xml_size = ET.SubElement(xml_var, 'linewidth')
|
xml_size = ET.SubElement(xml_var, 'linewidth')
|
||||||
xml_size.text=str(daq_config[var][2][3])
|
xml_size.text=str(daq_config[var][2][3])
|
||||||
|
xml_type = ET.SubElement(xml_var, 'type')
|
||||||
|
xml_type.text=str(daq_config[var][0][2])
|
||||||
|
|
||||||
# Détection de groupe de graphique
|
# Détection de groupe de graphique
|
||||||
data_group_i=0
|
data_group_i=0
|
||||||
@ -160,9 +162,9 @@ def plot(data_groups):
|
|||||||
##
|
##
|
||||||
|
|
||||||
def plot_generate_thread(csv_file):
|
def plot_generate_thread(csv_file):
|
||||||
if sys.platform=="linux": # wxPython ne s'installe pas bien sur GNU/linux -> Qt6
|
if sys.platform=="linux": # wxPython ne s'installe pas bien sur GNU/linux -> Qt5
|
||||||
command = sys.executable + " " + os.path.join(sys.executable, os.getcwd(), "twin_plot_qt.py") + " "+ csv_file
|
command = sys.executable + " " + os.path.join(sys.executable, os.getcwd(), "twin_plot_qt.py") + " "+ csv_file
|
||||||
else: # Qt6 ne s'installe pas bien sur Windows -> wxPython
|
else: # Qt5 ne s'installe pas bien sur Windows -> wxPython
|
||||||
command = sys.executable + " " + os.path.join(sys.executable, os.getcwd(), "twin_plot_wx.py") + " "+ csv_file
|
command = sys.executable + " " + os.path.join(sys.executable, os.getcwd(), "twin_plot_wx.py") + " "+ csv_file
|
||||||
os.system(command)
|
os.system(command)
|
||||||
|
|
||||||
|
198
twin_plot.py
Normal file
198
twin_plot.py
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import csv # Creating/parsing CSV file
|
||||||
|
import xml.etree.ElementTree as ET # Creating/parsing XML file
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# twin_plot.py
|
||||||
|
# @title: Visualisation des données (Matplotlib)
|
||||||
|
# @project: Blender-EduTech
|
||||||
|
# @lang: fr
|
||||||
|
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
|
||||||
|
# @copyright: Copyright (C) 2023 Philippe Roy
|
||||||
|
# @license: GNU GPL
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Configuration des plots
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
def plot_config_get_enable():
|
||||||
|
twin_config = ET.parse('twin_config.xml').getroot()
|
||||||
|
if twin_config[1][0].text == "True":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
##
|
||||||
|
# Génère le dictionnaire plot_config à partir du fichier XML plot_config.xml
|
||||||
|
##
|
||||||
|
|
||||||
|
def plot_config_get_dict():
|
||||||
|
plot_config_tree = ET.parse('plot_config.xml').getroot()
|
||||||
|
plot_config_tmp={}
|
||||||
|
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_tmp.update({var.text: var_dict})
|
||||||
|
return plot_config_tmp
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returne une valeur du dictionnaire plot_config
|
||||||
|
##
|
||||||
|
|
||||||
|
def plot_config_get(plot_config, var, key):
|
||||||
|
if key in plot_config[var]:
|
||||||
|
return plot_config[var][key]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
##
|
||||||
|
# Nombre de groupe de courbe(s)
|
||||||
|
##
|
||||||
|
|
||||||
|
def plot_nb(plot_config):
|
||||||
|
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
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Fichier CSV
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
##
|
||||||
|
# Fichier CSV -> Tableau X,Y
|
||||||
|
##
|
||||||
|
|
||||||
|
def csv_read(file):
|
||||||
|
|
||||||
|
# Lecture fichier CSV
|
||||||
|
fields = []
|
||||||
|
rows = []
|
||||||
|
with open(file, 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
|
||||||
|
|
||||||
|
return fields, xdata, ydata
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Création des graphiques
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
def plot_static(canvas, fields, xdata, ydata, plot_config, title):
|
||||||
|
|
||||||
|
# Configuration des plots activée
|
||||||
|
plot_config_enable=plot_config_get_enable()
|
||||||
|
|
||||||
|
# Plots
|
||||||
|
# Groupe de plots : si group = 0 -> nouveau groupe, plot solitaire
|
||||||
|
# si group = -1 -> pas de plot
|
||||||
|
# si group > 0 -> numéro du groupe
|
||||||
|
plt_i=0 # Compteur de plot
|
||||||
|
plt_grp=[] # Groupe de plot [[numéro du plot, groupe du fichier CSV]]
|
||||||
|
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 unique
|
||||||
|
if plot_nb(plot_config) ==1:
|
||||||
|
if plot_config_enable: # Configuration des plots activée
|
||||||
|
canvas.plt.plot(xdata[i], ydata[i], label=var, color=plot_config_get(plot_config, var, 'color'), linewidth=plot_config_get(plot_config, var, 'linewidth'),
|
||||||
|
linestyle=plot_config_get(plot_config, var, 'linestyle'), marker=plot_config_get(plot_config, var, 'marker'))
|
||||||
|
else:
|
||||||
|
canvas.plt.plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
|
||||||
|
|
||||||
|
# Légende ou titre d'axe y
|
||||||
|
if plt_grp[plt_current][1]==0:
|
||||||
|
canvas.plt.set_ylabel(var)
|
||||||
|
else:
|
||||||
|
canvas.plt.legend()
|
||||||
|
|
||||||
|
# Création des subplots
|
||||||
|
if plot_nb(plot_config) >1:
|
||||||
|
if plot_config_enable: # Configuration des plots activée
|
||||||
|
canvas.plt[plt_current].plot(xdata[i], ydata[i], label=var, color=plot_config_get(plot_config, var, 'color'), linewidth=plot_config_get(plot_config, var, 'linewidth'),
|
||||||
|
linestyle=plot_config_get(plot_config, var, 'linestyle'), marker=plot_config_get(plot_config, var, 'marker'))
|
||||||
|
else:
|
||||||
|
canvas.plt[plt_current].plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
|
||||||
|
|
||||||
|
# Légende ou titre d'axe y
|
||||||
|
if plt_grp[plt_current][1]==0:
|
||||||
|
canvas.plt[plt_current].set_ylabel(var)
|
||||||
|
else:
|
||||||
|
canvas.plt[plt_current].legend()
|
||||||
|
|
||||||
|
# Décoration
|
||||||
|
if plot_nb(plot_config) ==1: # 1 plot
|
||||||
|
canvas.plt.set_xlabel("Temps (s)")
|
||||||
|
canvas.plt.set_title(title)
|
||||||
|
canvas.plt.axhline(linewidth=1, color='k')
|
||||||
|
canvas.plt.grid(True, linestyle='--')
|
||||||
|
# canvas.plt.legend()
|
||||||
|
else: # Plusieurs plots
|
||||||
|
canvas.plt[plt_i-1].set_xlabel("Temps (s)")
|
||||||
|
canvas.plt[0].set_title(title)
|
||||||
|
for i in range (plt_i):
|
||||||
|
canvas.plt[i].axhline(linewidth=1, color='k')
|
||||||
|
canvas.plt[i].grid(True, linestyle='--')
|
||||||
|
# canvas.plt[i].legend()
|
||||||
|
|
||||||
|
# Redraw
|
||||||
|
canvas.draw()
|
||||||
|
|
||||||
|
|
187
twin_plot_qt.py
187
twin_plot_qt.py
@ -1,15 +1,11 @@
|
|||||||
import sys
|
import sys
|
||||||
import random
|
from twin_plot import plot_config_get_dict, plot_config_get, plot_config_get_enable, plot_nb, csv_read, plot_static # Gestion communes des graphiques (Qt, wx)
|
||||||
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 # GUI Qt5
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
import matplotlib # Grapheur Matplotlib
|
||||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
|
|
||||||
import matplotlib.pyplot as plts
|
import matplotlib.pyplot as plts
|
||||||
|
matplotlib.use('Qt5Agg')
|
||||||
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# twin_plot_qt.py
|
# twin_plot_qt.py
|
||||||
@ -21,70 +17,18 @@ import matplotlib.pyplot as plts
|
|||||||
# @license: GNU GPL
|
# @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={}
|
plot_config={}
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# 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})
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returne une valeur du dictionnaire plot_config
|
|
||||||
##
|
|
||||||
|
|
||||||
def plot_config_get(var, key):
|
|
||||||
if key in plot_config[var]:
|
|
||||||
return plot_config[var][key]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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
|
# Zone de dessin
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
class MplCanvas(FigureCanvasQTAgg):
|
class MplCanvas(FigureCanvasQTAgg):
|
||||||
def __init__(self, parent=None, width=5, height=4, dpi=100):
|
def __init__(self, parent=None, width=5, height=4, dpi=100):
|
||||||
if plot_nb() ==1: # plot_nb() : nombre de graphiques
|
if plot_nb(plot_config) ==1: # plot_nb() : nombre de graphiques
|
||||||
fig, self.plt = plts.subplots() # plot_nb() : nombre de graphiques
|
fig, self.plt = plts.subplots()
|
||||||
else:
|
else:
|
||||||
fig, self.plt = plts.subplots(plot_nb(), 1, sharex=True) # plot_nb() : nombre de graphiques
|
fig, self.plt = plts.subplots(plot_nb(plot_config), 1, sharex=True) # plot_nb() : nombre de graphiques
|
||||||
super(MplCanvas, self).__init__(fig)
|
super(MplCanvas, self).__init__(fig)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@ -212,9 +156,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
# Création du graphique
|
# Création du graphique
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
# Configuration des plots
|
|
||||||
plot_config_dict()
|
|
||||||
|
|
||||||
# Zone graphique (barre d'outil et graphique)
|
# Zone graphique (barre d'outil et graphique)
|
||||||
# FIXME : perd de la place quand on agrandi
|
# FIXME : perd de la place quand on agrandi
|
||||||
super(MainWindow, self).__init__(*args, **kwargs)
|
super(MainWindow, self).__init__(*args, **kwargs)
|
||||||
@ -235,110 +176,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.setCentralWidget(widget)
|
self.setCentralWidget(widget)
|
||||||
# print (self.getContentsMargins())
|
# print (self.getContentsMargins())
|
||||||
|
|
||||||
# Lecture fichier CSV
|
# Création des graphive à partir du fichier CSV
|
||||||
fields = []
|
fields, xdata, ydata = csv_read(sys.argv[1])
|
||||||
rows = []
|
plot_static(self.canvas, fields, xdata, ydata, plot_config, sys.argv[1])
|
||||||
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
|
|
||||||
# Groupe de plots : si group = 0 -> nouveau groupe, plot solitaire
|
|
||||||
# si group = -1 -> pas de plot
|
|
||||||
# si group > 0 -> numéro du groupe
|
|
||||||
plt_i=0 # Compteur de plot
|
|
||||||
plt_grp=[] # Groupe de plot [[numéro du plot, groupe du fichier CSV]]
|
|
||||||
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 unique
|
|
||||||
if plot_nb() ==1:
|
|
||||||
if twin_config[1][0].text == "True": # Configuration des plots activée
|
|
||||||
self.canvas.plt.plot(xdata[i], ydata[i], label=var, color=plot_config_get(var, 'color'), linewidth=plot_config_get(var, 'linewidth'),
|
|
||||||
linestyle=plot_config_get(var, 'linestyle'), marker=plot_config_get(var, 'marker'))
|
|
||||||
else:
|
|
||||||
self.canvas.plt.plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
|
|
||||||
|
|
||||||
# Légende ou titre d'axe y
|
|
||||||
if plt_grp[plt_current][1]==0:
|
|
||||||
self.canvas.plt.set_ylabel(var)
|
|
||||||
else:
|
|
||||||
self.canvas.plt.legend()
|
|
||||||
|
|
||||||
# Création des subplots
|
|
||||||
if plot_nb() >1:
|
|
||||||
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_get(var, 'color'), linewidth=plot_config_get(var, 'linewidth'),
|
|
||||||
linestyle=plot_config_get(var, 'linestyle'), marker=plot_config_get(var, 'marker'))
|
|
||||||
else:
|
|
||||||
self.canvas.plt[plt_current].plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
|
|
||||||
|
|
||||||
# Légende ou titre d'axe y
|
|
||||||
if plt_grp[plt_current][1]==0:
|
|
||||||
self.canvas.plt[plt_current].set_ylabel(var)
|
|
||||||
else:
|
|
||||||
self.canvas.plt[plt_current].legend()
|
|
||||||
|
|
||||||
# Décoration
|
|
||||||
if plot_nb() ==1: # 1 plot
|
|
||||||
self.canvas.plt.set_xlabel("Temps (s)")
|
|
||||||
# self.canvas.plt[0].set_ylabel("Valeurs")
|
|
||||||
self.canvas.plt.set_title(sys.argv[1])
|
|
||||||
self.canvas.plt.axhline(linewidth=1, color='k')
|
|
||||||
self.canvas.plt.grid(True, linestyle='--')
|
|
||||||
# self.canvas.plt.legend()
|
|
||||||
else: # Plusieurs plots
|
|
||||||
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()
|
self.show()
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@ -346,6 +186,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# Configuration des plots
|
||||||
|
plot_config=plot_config_get_dict()
|
||||||
|
|
||||||
|
# Fenêtre
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
# w = DynamicPlot()
|
# w = DynamicPlot()
|
||||||
w = MainWindow() # StaticPlot()
|
w = MainWindow() # StaticPlot()
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import sys
|
import sys
|
||||||
import importlib
|
from twin_plot import plot_config_get_dict, plot_config_get, plot_config_get_enable, plot_nb, csv_read, plot_static # Gestion communes des graphiques (Qt, wx)
|
||||||
import csv
|
|
||||||
import xml.etree.ElementTree as ET # Creating/parsing XML file
|
|
||||||
|
|
||||||
import wx
|
import wx # GUI wxPython
|
||||||
import matplotlib
|
import matplotlib # Grapheur Matplotlib
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
from matplotlib.backends.backend_wxagg import (FigureCanvasWxAgg as FigureCanvas, NavigationToolbar2WxAgg as NavigationToolbar)
|
from matplotlib.backends.backend_wxagg import (FigureCanvasWxAgg as FigureCanvas, NavigationToolbar2WxAgg as NavigationToolbar)
|
||||||
|
|
||||||
@ -18,61 +16,8 @@ from matplotlib.backends.backend_wxagg import (FigureCanvasWxAgg as FigureCanvas
|
|||||||
# @license: GNU GPL
|
# @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={}
|
plot_config={}
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Configuration des graphiques
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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})
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returne une valeur du dictionnaire plot_config
|
|
||||||
##
|
|
||||||
|
|
||||||
def plot_config_get(var, key):
|
|
||||||
if key in plot_config[var]:
|
|
||||||
return plot_config[var][key]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Création des graphiques
|
# Création des graphiques
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@ -181,32 +126,32 @@ def plot_draw(plt):
|
|||||||
plt[i].grid(True, linestyle='--')
|
plt[i].grid(True, linestyle='--')
|
||||||
# self.canvas.plt[i].legend()
|
# self.canvas.plt[i].legend()
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Zone de dessin
|
# Zone de dessin
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
class CanvasFrame(wx.Frame):
|
class CanvasFrame(wx.Frame):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(None, -1, 'Visualisation des données')
|
super().__init__(None, -1, 'Visualisation des données')
|
||||||
|
|
||||||
# Configuration des graphiques
|
|
||||||
plot_config_dict()
|
|
||||||
|
|
||||||
# Création des zones graphique (Plots)
|
# Création des zones graphique (Plots)
|
||||||
self.figure = Figure()
|
self.figure = Figure()
|
||||||
if plot_nb() ==1: # plot_nb() : nombre de graphiques
|
if plot_nb() ==1: # plot_nb() : nombre de graphiques
|
||||||
plt = self.figure.subplots() # plot_nb() : nombre de graphiques
|
plt = self.figure.subplots() # plot_nb() : nombre de graphiques
|
||||||
else:
|
else:
|
||||||
plt = self.figure.subplots(plot_nb(), 1, sharex=True) # plot_nb() : nombre de graphiques
|
plt = self.figure.subplots(plot_nb(plot_config), 1, sharex=True) # plot_nb() : nombre de graphiques
|
||||||
|
self.canvas = FigureCanvas(self, -1, self.figure)
|
||||||
|
|
||||||
# Dessin
|
# Création des graphive à partir du fichier CSV
|
||||||
plot_draw(plt)
|
fields, xdata, ydata = csv_read(sys.argv[1])
|
||||||
|
plot_static(self.canvas, fields, xdata, ydata, plot_config, sys.argv[1])
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
# # Dessin
|
||||||
|
# plot_draw(plt)
|
||||||
|
|
||||||
# Implantation de la fenêtre (canvas)
|
# Implantation de la fenêtre (canvas)
|
||||||
self.canvas = FigureCanvas(self, -1, self.figure)
|
|
||||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)
|
self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)
|
||||||
self.add_toolbar()
|
self.add_toolbar()
|
||||||
@ -231,5 +176,10 @@ class App(wx.App):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# Configuration des plots
|
||||||
|
plot_config=plot_config_get_dict()
|
||||||
|
|
||||||
|
# Fenêtre
|
||||||
app = App()
|
app = App()
|
||||||
app.MainLoop()
|
app.MainLoop() # StaticPlot()
|
||||||
|
1
volet_roulant/twin_file_wx.py
Symbolic link
1
volet_roulant/twin_file_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_file_wx.py
|
1
volet_roulant/twin_plot.py
Symbolic link
1
volet_roulant/twin_plot.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot.py
|
1
volet_roulant/twin_plot_wx.py
Symbolic link
1
volet_roulant/twin_plot_wx.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_plot_wx.py
|
@ -18,7 +18,7 @@ scene = bge.logic.getCurrentScene()
|
|||||||
|
|
||||||
# Configuration des variables publiques
|
# Configuration des variables publiques
|
||||||
# 'nom_variable' :
|
# 'nom_variable' :
|
||||||
# - Objet 3D : [nom de l'objet 3D, propriété du stockage de la valeur (activate ou activated_real)]
|
# - Objet 3D : [nom de l'objet 3D, propriété associée à la valeur (activate ou activated_real), type de la valeur ('d' (digital, binary), 'a', (analog) ou 'n' (numeric)), échelle (1 si ommis)]
|
||||||
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
|
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
|
||||||
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (matplotlib)
|
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (matplotlib)
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user