2 export.py is a module of pymecavideo.
3 pymecavideo
is a program to track moving points
in a video frameset
4 Copyright (C) 2007 Jean-Baptiste Butet <ashashiwa
@gmail.com>
5 Copyright (C) 2023 Georges Khaznadar <georgesk
@debian.org>
7 This program
is free software: you can redistribute it
and/
or modify
8 it under the terms of the GNU General Public License
as published by
9 the Free Software Foundation, either version 3 of the License,
or
10 (at your option) any later version.
12 This program
is distributed
in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License
for more details.
17 You should have received a copy of the GNU General Public License
18 along
with this program. If
not, see <http://www.gnu.org/licenses/>.
22export.py permet d
'exporter les données de pymecavideo dans différents formats
26from globdef import DOCUMENT_PATH, HOME_PATH
27from PyQt6.QtWidgets import QFileDialog, QCheckBox, QDialog, QMessageBox
28from PyQt6.QtCore import Qt, QCoreApplication, QUrl, QStandardPaths
32# On prévient si l'enregistrement est un succès ?
35# Dictionnaire contenant les différents formats d'exportation
36# nom (str) : nom du format/de l'application
37# filtre (str) : filtre utilisé dans le dialogue d'enregistrement
38# extension (str) : extension du fichier, ajoutée automatiquement si besoin
44 1: {
'nom': QCoreApplication.translate(
"export",
'Libre/OpenOffice Calc'),
45 'filtre': QCoreApplication.translate(
"export",
'Feuille de calcul OpenDocument (*.ods)'),
49 'propose_ouverture':
True,
52 2: {
'nom': QCoreApplication.translate(
"export",
'Python (source)'),
53 'filtre': QCoreApplication.translate(
"export",
'Fichier Python (*.py)'),
55 'class':
'PythonSource',
57 'propose_ouverture':
True,
60 3: {
'nom': QCoreApplication.translate(
"export",
'Python (Numpy)'),
61 'filtre': QCoreApplication.translate(
"export",
'Fichier Numpy (*.npy)'),
63 'class':
'PythonNumpy',
65 'propose_ouverture':
False,
68 4: {
'nom' : QCoreApplication.translate(
"export",
'Jupyter Notebook'),
69 'filtre' : QCoreApplication.translate(
"export",
'Notebook (*.ipynb)'),
70 'extension' :
'ipynb',
71 'class' :
'PythonNotebook',
72 'modules' : [
'nbformat'],
73 'propose_ouverture' :
False,
76 5: {
'nom': QCoreApplication.translate(
"export",
'Fichier CSV'),
77 'filtre': QCoreApplication.translate(
"export",
'Fichier CSV (*.csv, *.txt)'),
79 'class':
'FichierCSV',
81 'propose_ouverture':
True,
84 6: {
'nom': QCoreApplication.translate(
"export",
'Pandas Dataframe'),
85 'filtre': QCoreApplication.translate(
"export",
'Dataframe (*.pkl)'),
87 'class':
'DataframePandas',
88 'modules': [
'pandas'],
89 'propose_ouverture':
False,
95 0: {
'titre': QCoreApplication.translate(
"export",
"Erreur lors de l'exportation"),
96 'texte': QCoreApplication.translate(
"export",
"Echec de l'enregistrement du fichier:<b>\n{0}</b>")},
98 1: {
'titre': QCoreApplication.translate(
"export",
"Impossible de créer le fichier"),
99 'texte': QCoreApplication.translate(
"export",
"L'export n'est possible que pour 1 seul point cliqué.")},
101 2: {
'titre': QCoreApplication.translate(
"export",
"Exportation terminée"),
102 'texte': QCoreApplication.translate(
"export",
"Fichier:\n<b>{0}</b>\nenregistré avec succès.")},
104 3: {
'titre': QCoreApplication.translate(
"export",
"Impossible de créer le fichier"),
105 'texte': QCoreApplication.translate(
"export",
"Le module <b>{0}</b> n'est pas installé.")},
117 Crée un fichier Pandas et importe les données de pymecavideo
121 table = app.tableWidget
123 df.to_pickle(filepath)
124 QMessageBox.information(
126 QCoreApplication.translate(
"export_pandas",
"Fichier Pandas sauvegardé"),
127 QCoreApplication.translate(
128 "export_pandas",
"""Pour ouvrir ce fichier depuis Python, taper :\n\nimport pandas as pd\ndf = pd.read_pickle("{}")""".format(os.path.basename(filepath))))
132 https://stackoverflow.com/questions/37680981/how-can-i-retrieve-data-from-a-qtablewidget-to-dataframe
136 col_count = table.columnCount()-1
137 row_count = table.rowCount()
138 headers = [str(table.horizontalHeaderItem(i).text())
139 for i
in range(col_count)]
141 for row
in range(row_count):
143 for col
in range(col_count):
144 table_item = table.item(row, col)
146 '' if table_item
is None else float(table_item.text()))
147 df_list.append(df_list2)
148 df = self.
DataFrame(df_list, columns=headers)
156 Crée un fichier CSV et exporte les données de pymecavideo
160 if d.exec() == QDialog.DialogCode.Accepted:
163 _header = d.checkBox.isChecked()
165 with open(filepath,
'w', newline=
'')
as csvfile:
166 csvwriter = csv.writer(csvfile, delimiter=_field,
167 quotechar=
'"', quoting=csv.QUOTE_MINIMAL)
169 header = [tw.horizontalHeaderItem(
170 col).text()
for col
in range(tw.columnCount()-1)]
171 csvwriter.writerow(header)
172 for row
in range(tw.rowCount()):
176 for col
in range(tw.columnCount()-1):
177 item = tw.item(row, col)
181 txt = txt.replace(
'.',
',')
185 csvwriter.writerow(rowdata)
190 Objet capable d'écrire des données textes et numériques dans
191 un fichier au fomat ODS
194 def __init__(self, app, fichier_ods):
196 Crée un fichier ods et importe les données de pymecavideo
198 from odf.opendocument
import OpenDocumentSpreadsheet
199 from odf.text
import P
200 from odf.table
import Table, TableRow, TableCell
204 self.
outfile = open(fichier_ods,
'wb')
205 self.
doc = OpenDocumentSpreadsheet()
206 self.
table = Table(name=
"Pymecavideo {0}".format(
207 time.strftime(
"%Y-%m-%d %Hh%Mm%Ss")))
212 exporte les données de pymecavideo
213 @param app pointeur vers l
'application
217 for obj
in app.pointage.suivis:
218 titles.append(f
"X{obj} (m)")
219 titles.append(f
"Y{obj} (m)")
221 self.
table.addElement(row)
225 para = self.
P(text=t)
232 fonction de rappel qui crée les lignes de tableur et
233 y inscrit la date, à gauche; construit self.tr la liste des
234 pointeurs vers les lignes du tableur
238 self.table.addElement(row)
240 self.TableCell(valuetype="float", value=str(t)))
243 def cb_point(i, t, j, obj, p, v):
245 fonction de rappel qui inscrit les coordonnées dans le tableur
248 self.
tr[i].addElement(
249 self.
TableCell(valuetype=
"float", value=str(p.x)))
250 self.
tr[i].addElement(
251 self.
TableCell(valuetype=
"float", value=str(p.y)))
255 app.pointage.iteration_data(cb_temps, cb_point, unite=
"m")
257 self.
doc.spreadsheet.addElement(self.
table)
265 Exporte les données dans un fichier Python(source)
270#!/usr/bin/env python3
271## Données exportées de Pymecavidéo
274import matplotlib.pyplot as plt
276# Intervalle de temps auto-détecté
291 plt.plot(x1,y1,
'o',markersize= 3)
292 plt.xlabel(
"x (en m)")
293 plt.ylabel(
"y (en m)")
315 vx = np.array(np.zeros(len(x1)-2))
316 vy = np.array(np.zeros(len(x1)-2))
318 for k
in range(1,len(x1)-1):
319 Δx = (x1[k+1]-x1[k-1])
320 Δy = (y1[k+1]-y1[k-1])
328##### à compléter pour calculer les vitesses ####
341 ax = np.array(np.zeros(len(vx)-2))
342 ay = np.array(np.zeros(len(vx)-2))
344 for k
in range(1, len(vx)-1):
345 Δvx = (vx[k+1]-vx[k-1])
346 Δvy = (vy[k+1]-vy[k-1])
352 ca0 =
"""#####à compléter pour calculer les vitesses####
358 plt.title("Vecteurs accélérations")
359 plt.quiver(x1[2:-2], y1[2:-2], ax, ay, scale_units =
'xy', angles =
'xy', width = 0.003, color =
'r')
369 if d.exec() == QDialog.DialogCode.Accepted:
370 calcule_vitesse, affiche_vitesse, calcule_accel, affiche_accel = \
371 d.checkBox_v.isChecked(), \
372 d.checkBox_v2.isChecked(), \
373 d.checkBox_a.isChecked(), \
374 d.checkBox_a2.isChecked()
376 calcule_vitesse =
True
377 if calcule_accel
or affiche_accel:
378 "on veut les accelerations, il faut les vitesse"
379 calcule_vitesse =
True
382 calcule_vitesse =
True
383 with open(filepath,
"w", encoding=
"UTF-8")
as f:
384 date = time.strftime(
"%d/%m/%y %H:%M")
385 f.write(self.
en_tete.format(date=date, deltaT=app.pointage.deltaT))
391 def cb_objet(i, obj):
393 fonction de rappel pour chacun des objets; modifie les listes
394 commentaires, lignes_x et lignes_y
395 @param i index de l
'objet, commençant à 0
396 @param obj un objet suivi
398 commentaires.append(f"""\
400# coordonnées du point numéro {obj}
403 lignes_x.append(f
"x{obj} = np.array([")
404 lignes_y.append(f
"y{obj} = np.array([")
408 def cb_point(i, obj, p):
410 fonction de rappel pour les points pointés appartenant à un
412 @param i l
'index de l'objet, commençant à 0
413 @param obj l
'objet suivi
414 @param p un pointage (de type vecteur)
417 lignes_x[i] += f
"{p.x}, "
418 lignes_y[i] += f
"{p.y}, "
423 app.pointage.iteration_objet(cb_objet, cb_point, unite=
"m")
426 lignes_x = [l +
"])\n" for l
in lignes_x]
427 lignes_y = [l +
"])\n" for l
in lignes_y]
430 for c, lx, ly
in zip(commentaires, lignes_x, lignes_y):
431 f.write(c); f.write(lx); f.write(ly)
432 f.write(self.
code.format(
433 cv = self.
cv1 if calcule_vitesse
else self.
cv0,
435 ca = self.
ca1 if calcule_accel
else self.
ca0,
436 va = self.
va if affiche_accel
else "",
440from interfaces.Ui_csv_dialog
import Ui_Dialog
as Ui_csv_Dialog
444 Fenêtre de dialogue permettant de choisir séparateurs de champ et décimal dans le fichier CSV
447 def __init__(self, *args, **kwargs):
448 QDialog.__init__(self, *args, **kwargs)
449 Ui_csv_Dialog.__init__(self)
455 def change_field(self):
456 if self.rbFieldComma.isChecked():
458 elif self.rbFieldSemicolon.isChecked():
460 elif self.rbFieldTab.isChecked():
464 def change_dec(self):
465 if self.rbFieldComma.isChecked():
467 elif self.rbDecDot.isChecked():
471 def check_if_dot(self):
472 if self.rbDecComma.isChecked():
473 if self.rbFieldComma.isChecked():
474 self.rbFieldSemicolon.setChecked(
True)
475 self.rbFieldComma.setEnabled(
False)
477 self.rbFieldComma.setEnabled(
True)
481from interfaces.Ui_python_dialog
import Ui_Dialog
as Ui_Python
485 Fenêtre de dialogue permettant de choisir les grandeurs à exporter
486 dans le fichier Python(source)
489 def __init__(self, *args, **kwargs):
490 QDialog.__init__(self, *args, **kwargs)
491 Ui_Python.__init__(self)
497 Exporte les données dans un fichier Numpy
500 def __init__(self, app, filepath):
503 liste_temps = app.pointage.liste_t_pointes()
505 x_objets = {o: []
for o
in app.pointage.suivis}
506 y_objets = {o: []
for o
in app.pointage.suivis}
507 def cb_points(i, t, j, obj, p, v):
509 fonction de rappel pour chaque point
512 x_objets[obj].append(p.x)
513 y_objets[obj].append(p.y)
516 app.pointage.iteration_data(
None, cb_points, unite =
"m")
518 export = [liste_temps]
519 for obj
in app.pointage.suivis:
520 export.append(x_objets[obj])
521 export.append(y_objets[obj])
523 np.save(filepath, export)
524 QMessageBox.information(
526 QCoreApplication.translate(
"export_numpy",
"Fichier Numpy sauvegardé"),
527 QCoreApplication.translate(
"export_numpy",
528 """Pour ouvrir ce fichier depuis Python, taper :
530import numpy as np\nt,x1,y1 ... = np.load("{}")""".format(
531 os.path.basename(filepath))))
533from interfaces.Ui_jupyter_dialog
import Ui_Dialog
as Jupyter_Dialog
537 Fenêtre de dialogue permettant de choisir les grandeurs à exporter
538 dans le fichier Notebook Jupyterlab
541 def __init__(self, *args, **kwargs):
542 QDialog.__init__(self, *args, **kwargs)
543 Jupyter_Dialog.__init__(self)
547 def etat_vitesse(self,etat):
549 for w
in (self.checkBox_v2, self.checkBox_a, self.checkBox_e):
553 for w
in (self.checkBox_v2, self.checkBox_a, self.checkBox_e):
560 Exporte les données dans un fichier Notebook Jupyterlab
561 Attention : seul le premier objet est exporté !
563 def __init__(self, app, filepath):
564 import nbformat
as nbf
565 from template_ipynb
import genere_notebook
566 ligne_t =
"np.array({})".format(app.pointage.liste_t_pointes())
567 points = app.pointage.liste_pointages()
568 ligne_x =
"np.array({})".format([p.x
for p
in points])
569 ligne_y =
"np.array({})".format([p.y
for p
in points])
571 if d.exec() == QDialog.DialogCode.Accepted:
572 graphs = (d.checkBox_c.isChecked(), d.checkBox_v.isChecked(
573 ), d.checkBox_v2.isChecked(), d.checkBox_a.isChecked(), d.checkBox_e.isChecked())
574 nb = genere_notebook((ligne_t, ligne_x, ligne_y), graphs = graphs)
575 nbf.write(nb, filepath)
580 Enregistre un fichier et propose de l'ouvrir ensuite
583 def __init__(self, *args, extension=None, proposeOuverture=True):
584 super().__init__(*args)
585 self.setOption(QFileDialog.Option.DontUseNativeDialog)
586 self.setAcceptMode(QFileDialog.AcceptMode.AcceptSave)
588 urls = [QUrl.fromLocalFile(DOCUMENT_PATH),
589 QUrl.fromLocalFile(HOME_PATH),
590 QUrl.fromLocalFile(QStandardPaths.writableLocation(QStandardPaths.StandardLocation.DesktopLocation))
592 self.setSidebarUrls(urls)
593 self.setDefaultSuffix(extension)
595 self.
checkbox.setStyleSheet(
"color: rgb(255, 0, 0);")
596 self.
checkbox.setText(
"Ouvrir le fichier après enregistrement")
597 self.layout().addWidget(self.
checkbox)
598 if not proposeOuverture:
608 Une classe qui gère l'exportation des données
610 paramètres du constructeur
611 @param coord le widget principale de l
'onglet coodonnées
614 def __init__(self, coord, choix_export):
617 self.pointage = coord.pointage
619 self.dbg.p(1,
"rentre dans 'Export'")
620 propose_ouverture = EXPORT_FORMATS[choix_export][
'propose_ouverture']
621 base_name = os.path.splitext(os.path.basename(self.
pointage.filename))[0]
622 filtre = EXPORT_FORMATS[choix_export][
'filtre']
623 extension = EXPORT_FORMATS[choix_export][
'extension']
624 self.
class_str = EXPORT_FORMATS[choix_export][
'class']
625 un_point = EXPORT_FORMATS[choix_export][
'un_point']
626 modules = EXPORT_FORMATS[choix_export][
'modules']
633 self.
dbg.p(3,
"erreur d'export")
634 self.
dbg.p(3, EXPORT_MESSAGES)
635 msg = EXPORT_MESSAGES[3]
636 QMessageBox.critical(
None, msg[
'titre'], msg[
'texte'].format(
640 base_name, filtre, extension, propose_ouverture)
643 def demande_nom_fichier(self, filename, filtre, extension, propose_ouverture):
644 defaultName = os.path.join(DOCUMENT_PATH, filename)
646 filtre, extension=extension, proposeOuverture=propose_ouverture)
648 if fd.exec() == QDialog.DialogCode.Accepted:
649 filepath = fd.selectedFiles()[0]
650 ouvre = fd.checkbox.isChecked()
654 msg = EXPORT_MESSAGES[2]
655 QMessageBox.information(
None, msg[
'titre'], msg[
'texte'].format(
663 Redirige vers la routine d'exportation qui est définie par
666 dynamic_class = globals()[self.class_str]
667 dynamic_class(self.coord, filepath)
669 def ouvre_fichier(self, filepath):
670 if sys.platform.startswith(
'linux'):
671 os.system(
"xdg-open "+filepath)
672 elif sys.platform.startswith(
'darwin'):
673 os.system(
"open "+filepath)
674 elif sys.platform.startswith(
'win'):
675 os.startfile(os.path.realpath(filepath))
Objet capable d'écrire des données textes et numériques dans un fichier au fomat ODS.
def exportpymeca(self, app)
exporte les données de pymecavideo
def __init__(self, app, fichier_ods)
Crée un fichier ods et importe les données de pymecavideo.
Fenêtre de dialogue permettant de choisir séparateurs de champ et décimal dans le fichier CSV.
def write_qtable_to_df(self, table)
https://stackoverflow.com/questions/37680981/how-can-i-retrieve-data-from-a-qtablewidget-to-dataframe
def __init__(self, app, filepath)
Crée un fichier Pandas et importe les données de pymecavideo.
Une classe qui gère l'exportation des données.
def ouvre_fichier(self, filepath)
def enregistre_fichier(self, filepath)
Redirige vers la routine d'exportation qui est définie par self.class_str.
def demande_nom_fichier(self, filename, filtre, extension, propose_ouverture)
def __init__(self, app, filepath)
Crée un fichier CSV et exporte les données de pymecavideo.
Fenêtre de dialogue permettant de choisir les grandeurs à exporter dans le fichier Notebook Jupyterla...
Fenêtre de dialogue permettant de choisir les grandeurs à exporter dans le fichier Python(source)
Exporte les données dans un fichier Notebook Jupyterlab Attention : seul le premier objet est exporté...
Exporte les données dans un fichier Numpy.
def __init__(self, app, filepath)
fonction de rappel pour chaque point
Exporte les données dans un fichier Python(source)
def __init__(self, app, filepath)
fonction de rappel pour chacun des objets; modifie les listes commentaires, lignes_x et lignes_y
Enregistre un fichier et propose de l'ouvrir ensuite.