PyInstaller

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Probier beim zweiten Argument / statt \ zu benutzen.
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

Gestern hat es dann noch funktioniert, musste 2 Daten adden :)
Nun erhalte ich ne exe mit 330MB :o

Kann man diese eventuell noch verkleinern?
Vielleicht nur die notwendigen Bibliotheken hinzufügen? Oder beim Import etwas weglassen?
Ist jetzt aber nur mehr der schönheitshalber :)
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Dann schau doch mal nach, was da alles in das Archiv wandert.
Während das Programm läuft, wird der Inhalt ja temporär entpackt.
Wenn ich mich richtig erinnere, hat ein Programm mit QT und Python-Interpreter unter 30 MB. Da scheinen bei dir also viel mehr Dinge eingesammelt zu werden. Aber das können wir ohne Glaskugel nicht beantworten.
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

sparrow hat geschrieben: Donnerstag 25. Juli 2019, 08:03 Dann schau doch mal nach, was da alles in das Archiv wandert.
Während das Programm läuft, wird der Inhalt ja temporär entpackt.
Wenn ich mich richtig erinnere, hat ein Programm mit QT und Python-Interpreter unter 30 MB. Da scheinen bei dir also viel mehr Dinge eingesammelt zu werden. Aber das können wir ohne Glaskugel nicht beantworten.
Okay wenn es 50MB werden wäre es also auch kein Problem.
Habe es auch mal als

Code: Alles auswählen

--onedir
Probiert, da sind es 900MB :o

Ich bin nicht sehr Bewandert mit Windows, deshalb meine Frage an dich bzw. an alle, da ich --onedir gemacht habe sollten hier ja alle Daten enthalten sein oder?
Diese könnte ich hier Posten?
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Nochmal: Wir haben keine Glaskugel. Wir wissen nicht, was du da tust und wie du es tust. Wir wissen nicht, welche Daten da alle verwendet werden.
Was ich dir sagen kann: Python 3, PyQt5 und plotly mit pyinstaller gewrappt ergeben eine .exe von rund 20 MB größe.

Zeig doch mal deine .spec-Datei.
Dort solltest du übrigens auch die Daten eintragen, die du da irgendwie per Parameterübergabe an pyinstaller überigst.
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

Bitteschön, das ist der gesamte Inhalt der .spec Datei

Code: Alles auswählen

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['ascFileReader_V2.5.py'],
             pathex=['C:\\Users\\stf83wi\\Desktop\\Test_asc'],
             binaries=[],
             datas=[('C:\\Python37\\Lib\\site-packages\\plotly\\package_data\\templates\\plotly.json', 'plotly\\package_data\\templates'), ('C:\\Python37\\Lib\\site-packages\\plotly\\package_data\\plotly.min.js', 'plotly\\package_data')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='ascFileReader_V2.5',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False , icon='asc.ico')
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='ascFileReader_V2.5')
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Mir fällt da zumindest nichts ins Auge, was sofort falsch aussieht.

Dann lass pyinstaller einmal ohne --one* Option laufen und schau mal, was alles in "dist" ankommt. Da liegt dann auch die entsprechend kleine .exe, aber der Rest ist dort nicht mit eingepackt. Mit PyQt5 sind das bei mir 72 MB.
So solltest du sehen können, was da so riesig ist.
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

Wenn ich es ohne onedir exportiere, ist der Ordner "dist" ganze 146MB groß, was sehr erfreulich wäre wenn die exe starten würde :roll:
Die .spec Datei ergibt das gleiche wie vorhin:

Code: Alles auswählen

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['ascFileReader_V2.5.py'],
             pathex=['C:\\Users\\stf83wi\\Desktop\\asc_Test'],
             binaries=[],
             datas=[('C:\\Python37\\Lib\\site-packages\\plotly\\package_data\\templates\\plotly.json', 'plotly\\package_data\\templates'), ('C:\\Python37\\Lib\\site-packages\\plotly\\package_data\\plotly.min.js', 'plotly\\package_data')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='ascFileReader_V2.5',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True , icon='asc.ico')
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='ascFileReader_V2.5')
Allzu viele große Dateien gibt es da nicht, eine mit 27MB und dann kommt schon die exe mit 11MB
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Und --onedir ?
Was ist da der große Brocken in dist?
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

Hier sind:
mkl_core.dll mit 68MB
mkl_avx512.dll mit 59MB
mkl_avx2.dll mit 45MB
mkl_avx.dll mit 42MB
mkl_mc3.dll mit 41MB
mkl_mc.dll mit 40MB
mkl_def.dll mit 34MB
Die exe Datei hat legendlich 23MB

Das ist jetzt mal ein Auszug.

Oder kann jemand mal den Code selbst mit pyinstaller zu einer exe machen? Vielleicht ergibt sich hier eine Erkenntnis?
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Offensichtlich verwendest du Anaconda und numpy:

https://stackoverflow.com/questions/492 ... -necessary
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

Hm interessant, dann installiere ich mir Miniconda3 noch zusätzlich, vielleicht schaut es dann hier besser aus.

Alles erledigt, habe es mit

Code: Alles auswählen

pyinstaller ascFileReader_V2.5.py --add-data "C:\Python37\Lib\site-packages\plotly\package_data\templates\plotly.json;plotly\package_data\templates" --add-data "C:\Python37\Lib\site-packages\plotly\package_data\plotly.min.js;plotly\package_data" --add-data "C:\Program Files\Anaconda3\Lib\site-packages\PyQt5\Qt\bin\Qt5Core.dll;bin\Qt\PyQt5"  --icon=asc.ico --onedir
exportieren lassen.

Das stand alles in der Comandline

Code: Alles auswählen

144 INFO: PyInstaller: 3.5
144 INFO: Python: 3.7.4
147 INFO: Platform: Windows-10-10.0.17763-SP0
151 INFO: wrote C:\Users\stf83wi\Desktop\asc_Test\ascFileReader_V2.5.spec
153 INFO: UPX is not available.
159 INFO: Extending PYTHONPATH with paths
['C:\\Users\\stf83wi\\Desktop\\asc_Test',
 'C:\\Users\\stf83wi\\Desktop\\asc_Test']
159 INFO: checking Analysis
162 INFO: Building Analysis because Analysis-00.toc is non existent
162 INFO: Initializing module dependency graph...
173 INFO: Initializing module graph hooks...
178 INFO: Analyzing base_library.zip ...
3616 INFO: running Analysis Analysis-00.toc
3620 INFO: Adding Microsoft.Windows.Common-Controls to dependent assemblies of final executable
  required by c:\python37\python.exe
6380 INFO: Caching module hooks...
6387 INFO: Analyzing C:\Users\stf83wi\Desktop\asc_Test\ascFileReader_V2.5.py
6505 INFO: Processing pre-find module path hook   distutils
7116 INFO: Processing pre-find module path hook   site
7117 INFO: site: retargeting to fake-dir 'c:\\python37\\lib\\site-packages\\PyInstaller\\fake-modules'
10231 INFO: Processing pre-safe import module hook   six.moves
42808 INFO: Loading module hooks...
42808 INFO: Loading module hook "hook-distutils.py"...
42817 INFO: Loading module hook "hook-encodings.py"...
42982 INFO: Loading module hook "hook-matplotlib.backends.py"...
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "c:\python37\lib\site-packages\matplotlib\__init__.py", line 138, in <module>
    from . import cbook, rcsetup
  File "c:\python37\lib\site-packages\matplotlib\cbook\__init__.py", line 31, in <module>
    import numpy as np
ModuleNotFoundError: No module named 'numpy'
43217 INFO: Loading module hook "hook-matplotlib.py"...
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "c:\python37\lib\site-packages\matplotlib\__init__.py", line 138, in <module>
    from . import cbook, rcsetup
  File "c:\python37\lib\site-packages\matplotlib\cbook\__init__.py", line 31, in <module>
    import numpy as np
ModuleNotFoundError: No module named 'numpy'
43472 INFO: Loading module hook "hook-pandas.py"...
43723 INFO: Loading module hook "hook-pkg_resources.py"...
44224 INFO: Processing pre-safe import module hook   win32com
Traceback (most recent call last):
  File "<string>", line 2, in <module>
ModuleNotFoundError: No module named 'win32com'
44361 INFO: Processing pre-safe import module hook   win32com
Traceback (most recent call last):
  File "<string>", line 2, in <module>
ModuleNotFoundError: No module named 'win32com'
44635 INFO: Loading module hook "hook-pydoc.py"...
44637 INFO: Loading module hook "hook-PyQt5.py"...
44923 INFO: Loading module hook "hook-PyQt5.QtCore.py"...
46724 INFO: Loading module hook "hook-PyQt5.QtGui.py"...
49154 INFO: Loading module hook "hook-PyQt5.QtWidgets.py"...
52813 INFO: Loading module hook "hook-pytz.py"...
53024 INFO: Loading module hook "hook-sqlite3.py"...
53198 INFO: Loading module hook "hook-sysconfig.py"...
53200 INFO: Loading module hook "hook-xml.dom.domreg.py"...
53201 INFO: Loading module hook "hook-xml.py"...
53306 INFO: Looking for ctypes DLLs
53338 INFO: Analyzing run-time hooks ...
53352 INFO: Including run-time hook 'pyi_rth_mplconfig.py'
53357 INFO: Including run-time hook 'pyi_rth_mpldata.py'
53358 INFO: Including run-time hook 'pyi_rth_pkgres.py'
53360 INFO: Including run-time hook 'pyi_rth_pyqt5.py'
53398 INFO: Looking for dynamic libraries
104588 INFO: Looking for eggs
104588 INFO: Using Python library c:\python37\python37.dll
104591 INFO: Found binding redirects:
[]
104611 INFO: Warnings written to C:\Users\stf83wi\Desktop\asc_Test\build\ascFileReader_V2.5\warn-ascFileReader_V2.5.txt
104922 INFO: Graph cross-reference written to C:\Users\stf83wi\Desktop\asc_Test\build\ascFileReader_V2.5\xref-ascFileReader_V2.5.html
105025 INFO: Appending 'datas' from .spec
105038 INFO: checking PYZ
105038 INFO: Building PYZ because PYZ-00.toc is non existent
105039 INFO: Building PYZ (ZlibArchive) C:\Users\stf83wi\Desktop\asc_Test\build\ascFileReader_V2.5\PYZ-00.pyz
108859 INFO: Building PYZ (ZlibArchive) C:\Users\stf83wi\Desktop\asc_Test\build\ascFileReader_V2.5\PYZ-00.pyz completed successfully.
108930 INFO: checking PKG
108930 INFO: Building PKG because PKG-00.toc is non existent
108933 INFO: Building PKG (CArchive) PKG-00.pkg
108981 INFO: Building PKG (CArchive) PKG-00.pkg completed successfully.
108984 INFO: Bootloader c:\python37\lib\site-packages\PyInstaller\bootloader\Windows-32bit\run.exe
108984 INFO: checking EXE
108985 INFO: Building EXE because EXE-00.toc is non existent
108985 INFO: Building EXE from EXE-00.toc
108999 INFO: Copying icons from ['asc.ico']
109001 INFO: Writing RT_GROUP_ICON 0 resource with 20 bytes
109003 INFO: Writing RT_ICON 1 resource with 67624 bytes
109010 INFO: Appending archive to EXE C:\Users\stf83wi\Desktop\asc_Test\build\ascFileReader_V2.5\ascFileReader_V2.5.exe
109022 INFO: Building EXE from EXE-00.toc completed successfully.
109028 INFO: checking COLLECT
109029 INFO: Building COLLECT because COLLECT-00.toc is non existent
109034 INFO: Building COLLECT COLLECT-00.toc
113267 INFO: Building COLLECT COLLECT-00.toc completed successfully.
Nun ist der Ordner 108MB groß!

Nach dem starten in der Comandline erscheint folgende Fehlermeldung

Code: Alles auswählen

PS C:\Users\stf83wi\Desktop\asc_Test\dist\ascFileReader_V2.5> .\ascFileReader_V2.5.exe
Traceback (most recent call last):
  File "ascFileReader_V2.5.py", line 5, in <module>
  File "c:\python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\PyQt5\__init__.py", line 41, in <module>
  File "site-packages\PyQt5\__init__.py", line 33, in find_qt
ImportError: unable to find Qt5Core.dll on PATH
[19640] Failed to execute script ascFileReader_V2.5
Was ich aber nicht ganz verstehe, weil ich ja mit

Code: Alles auswählen

--add-data "C:\Program Files\Anaconda3\Lib\site-packages\PyQt5\Qt\bin\Qt5Core.dll;bin\Qt\PyQt5"
diese dll explizit hinzugefügt habe!
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

sparrow hat geschrieben: Freitag 26. Juli 2019, 09:11 Offensichtlich verwendest du Anaconda und numpy:

https://stackoverflow.com/questions/492 ... -necessary
Numpy habe ich mit

Code: Alles auswählen

pip uninstall numpy
deinstalliert und es erscheint trotzdem die oben genannte Fehlermeldung, natürlich habe ich die exe Datei erneut erstellen lassen!
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@JohannX: Ein paar Anmerkungen zum Quelltext.

`qtpy` macht keinen Sinn. Du importierst ja auch zusätzlich noch Sachen aus `PyQt5` (von denen dann nur ein Name tatsächlich verwendet wird.) Und um eine EXE zu erstellen wo alles drin ist, *musst* Du Dich ja für eine Python-Qt-Anbindung entscheiden.

Faustregel zu Kommentaren: Die sollten nicht sagen *was* gemacht wird, denn das steht da ja bereits als Code, sondern *warum* das so gemacht wird – sofern das nicht offensichtlich ist. Vor Importen zu kommentieren „# importieren“ bringt dem Leser absolut keinen Mehrwert, genau so wie „# Klasse MainWindow samt Konstruktor“ vor der ``class``-Definition von `MainWindow` keinerlei ”Nährwert” hat.

Auch `app` und `window` sollten keine modulglobalen Variablen sein.

Die ganzen Methoden die aufgrund einer `QCheckBox` den Text 'Yes' oder 'No' setzen sind von der Struktur her alle gleich. Da sollte man *eine* Methode für schreiben, welche die beiden Unterschiede als Argumente übergeben bekommt.

`choose_button` ist ein guter Name für den Button selbst, aber nicht für die Methode die darauf hin aufgerufen wird. Funktionen und Methoden werden üblicherweise nach der Tätigkeit benannt, die sie ausführen. Bei Rückrufen ist auch `on_<event_description>()` eine gängige Konvention.

Das `file`-Attribut wird nie an eine Datei gebunden, sondern immer an einen Datei*namen*. Und statt `self.file` und `self.file2` (und `choose_button` und `choose_button_2`) zu haben, sollte man die Namen so wählen das man weiss *was* für Dateinamen das sind (und *was* da ausgewählt wird.)

Ausserhalb der `__init__()` sollten keine neuen Attribute eingeführt werden. Wenn `self.file2` tatsächlich irgendwo verwendet werden würde, dann käme es zu einem `AttributeError` wenn man vorher kein Speicherverzeichnis ausgewählt hat.

Laufwerk C:\ macht das ganze nicht wirklich portabel, obwohl da ansonsten ja nicht wirklich etwas von Windows abhängt.

`self.var` ist schlecht benannt. Namen sollen dem Leser vermitteln was der Wert im Programm bedeutet, nicht das es irgendeine Variable ist (sofern ich die Abkürzung hier richtig geraten habe).

Code der aufgrund einer Bedingung etwas mit einem literalen `True` macht falls die Bedingung zutrifft, und mit einem literalen `False` falls die Bedingung nicht zutrifft, ist unnötig kompliziert, weil man da auch gleich die Bedingung selbst hätte verwenden können. `isChecked()` liefert `True` oder `False`, also kann man das hier:

Code: Alles auswählen

        if self.ui.html_auto_open.isChecked():
            self.var = True
        else:
            self.var = False
viel einfacher ausdrücken:

Code: Alles auswählen

        self.var = self.ui.html_auto_open.isChecked()
Letztlich ist aber `self.var` auch komplett überflüssig, denn man kann `isChecked()` auch einfach dort aufrufen wo man den Zustand verwendet, statt ihn in einem nichtssagenden Attribut zwischenzuspeichern.

`None` als einziger Ausdruck in einem ``if``-Zweig macht keinen Sinn. Syntaktisch ist dafür das Schlüsselwort ``pass`` vorgesehen, aber auch das macht in einem ``if``-Zweig keinen Sinn. Wenn man einen ``if``- oder ``else``-Zweig nicht braucht, dann lässt man ihn einfach weg.

Beim Export in eine HTML-Datei macht es keinen Sinn das `Figure`-Objekt oder den `DataFrame` an das Hauptfenster zu binden. Das sind einfach nur lokale Namen.

Die Kommentare in der Methode sind teilweise auch wieder sehr überflüssig. Noch schlimmer sind falsche Kommentare, weil der Leser dann nicht weiss wem er glauben soll: dem Kommentar oder dem Code. Bei „# Sortiert die Daten“ wird überhaupt nichts sortiert. Ist da nun der Kommentar falsch oder fehlt da was im Code wo etwas sortiert wird?

Code: Alles auswählen

            # Schneidet den nur Filenamen raus und speichert diesen in eine neue Variable
            file_title = self.asc_filename[self.asc_filename.rfind('\\')+1:len(self.asc_filename)]
Ähm, Nein. Einfach nur Nein. Das ist nicht nur nicht portabel wegen dem \ sondern auch unter Windows selbst können Pfadkomponenten auch mit einem / getrennt werden. Pfade sind keine einfachen Zeichenketten sondern unterliegen besonderen Regeln. Dafür gibt es die Funktionen in `os.path` oder `pathlib.Path`. In diesem Fall beispielsweise:

Code: Alles auswählen

            file_title = os.path.basename(self.asc_filename)
Beim Hinzufügen der einzelnen Daten zum Diagramm wiederholt sich wieder fast der selbe Code für alle sechs Messgrössen. Man sollte hier die Unterschiede in eine Datenstruktur herausziehen und den Code nur einmal, in einer Schleife, stehen haben.

Der Kommentar „# Sauberes Schließen des Programmes“ ist zu einem harten `sys.exit()` falsch. Sauber wäre es die Qt-Hauptschleife zu verlassen damit das `sys.exit()` im Hauptprogramm den Rückgabewert von `exec_()` verwenden kann. Und das sollte man einfach durch das schliessen des Fensters erreichen können, denn der Normalfall bei Qt-Anwendungen ist, dass die sich beenden wenn das letzte Fenster geschlossen ist.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from collections import namedtuple
import os
import sys
from functools import partial

import pandas as pd
import plotly
from plotly import graph_objects as go
from PyQt5 import QtWidgets

from ui.mainwindow import Ui_asc_File_Reader

MeasurementCategory = namedtuple(
    'MeasurementCategory', 'name description id convert'
)
# 
# TODO Die `lambda`\s lassen sich bestimmt auch als Daten ausdrücken.
# 
MEASUREMENT_CATEGORIES = [
    MeasurementCategory(
        'ubatlogger',
        'Ubatlogger',
        '800200BA',
        lambda x: x * (5 / 4095) * 8.655106
    ),
    MeasurementCategory(
        'pressure',
        'Pressure',
        '80083DCE',
        lambda x: (x - 2) * 0.00257038 - 0.5
    ),
    MeasurementCategory(
        'temperature',
        'Temperature',
        '80083DA5',
        lambda x: (x - 1) * 0.125 - 73.025
    ),
    MeasurementCategory(
        'concentration',
        'Concentration',
        '80083DEF',
        lambda x: (x - 1) * 0.05 - 20
    ),
    MeasurementCategory(
        'level',
        'Level',
        '80083DD6',
        lambda x: (x - 1) * 0.125
    ),
    MeasurementCategory(
        'speedofsound',
        'Speed of Sound',
        '80083E09',
        lambda x: (x - 1) * 0.25 + 1000
    ),
]


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('Test')
        self.ui = Ui_asc_File_Reader()
        self.ui.setupUi(self)
        self.ui.choose_button.clicked.connect(self.choose_asc_filename)
        # 
        # TODO Die GUI-Elemente hier erstellen, statt sie hart kodiert in der
        #   *.ui-Datei anzulegen.
        # 
        for number, category in enumerate(MEASUREMENT_CATEGORIES, 1):
            button = getattr(self.ui, category.name)
            button.clicked.connect(
                partial(self.on_check_clicked, button, number)
            )
        
        self.ui.choose_button_2.clicked.connect(self.choose_target_path)
        self.ui.export_to_html.clicked.connect(self.export_to_html)
        self.ui.exit.clicked.connect(self.close)
        
        self.asc_filename = None
        self.target_path = None
        
    def choose_asc_filename(self):
        # 
        # TODO Nicht unnötig von Windows abhängig machen.
        # 
        self.asc_filename, _  = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Open file', 'c:\\', 'Image files (*.asc)'
        )
        self.ui.Info1.setText(self.asc_filename)

    def on_check_clicked(self, checkable, number):
        getattr(self.ui, f'pass{number}').setText(
            'YES' if checkable.isChecked() else 'NO'
        )
    
    def choose_target_path(self):
        self.target_path = QtWidgets.QFileDialog.getExistingDirectory()
        self.ui.Info2.setText(self.target_path)
        
    def export_to_html(self):
        if self.asc_filename is not None:
            figure = go.Figure()
            # 
            # TODO  `skipinitialspace` kann den Zugriff auf die Spalten
            #   vielleicht etwas weniger fehleranfällig machen.  Auf jeden Fall
            #   braucht man dann nicht mehr Leerzeichen bei den Namen zählen.
            # 
            data = pd.read_csv(
                self.asc_filename,
                skiprows=5,
                delimiter=';',
                #
                # FIXME Weglassen oder reparieren, denn das hat offensichtlich
                #   keinen Effekt.
                # 
                converters={'  DATA L': partial(int, base=16)},
            )

            file_title = os.path.basename(self.asc_filename)
            font = dict(
                family='Courier New, monospace', size=20, color='#7f7f7f'
            )
            figure.update_layout(
                title=go.layout.Title(text=file_title, xref='paper', x=0), 
                xaxis=go.layout.XAxis(
                    title=go.layout.xaxis.Title(text='Second [s]', font=font)
                ),
                yaxis=go.layout.YAxis(
                    title=go.layout.yaxis.Title(text='Values', font=font)
                ),
            )

            for category in MEASUREMENT_CATEGORIES:
                if getattr(self.ui, category.name).isChecked():
                    selected_data = data[data['  DATA H'] == category.id]
                    times = selected_data['       Offset[s]']
                    values = selected_data['  DATA L'].apply(category.convert)
                    figure.add_trace(
                        go.Scatter(
                            x=times,
                            y=values,
                            mode='lines',
                            name=category.description,
                        )
                    )
            
            filename = self.asc_filename
            if self.target_path:
                filename = os.path.join(
                    self.target_path, os.path.basename(filename)
                )
            plotly.offline.plot(
                figure,
                filename=filename + '.html',
                auto_open=self.ui.html_auto_open.isChecked(),
            )


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
JohannX
User
Beiträge: 110
Registriert: Mittwoch 27. März 2019, 17:07

@__blackjack__

Vielen Dank für deine großartige Unterstützung!
Den Code habe ich jetzt sinnvoll verkleinert und das eine oder andere von dir Übernommen.
Er ist jetzt Übersichtlicher als zuvor..... und wieder was gelernt.

Für die Schule hat´s gereicht für ne 1, aber jetzt da wo ich ein Praktikum absolviere sind die Forderungen höher gestellt.


Jetzt fehlt nur mehr die exe zu verkleinern und gut is :)
Antworten