Phyton: Werte auslesen/speichern/zeichnen

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.
Antworten
BlackJack

@RCB: Die `write()`-Aufrufe mit den leeren Zeichenketten machen keinen Sinn. Und da sieht man auch ganz gut das Problem mit dem kopieren von Code: Man muss immer darauf achten, dass alle Kopien gleich bleiben. An einer Stelle steht nur eine Referenzierung von der `write()`-Methode, ohne sie tatsächlich aufzurufen. Wenn der Aufruf tatsächlich einen Sinn hätte, wäre das sehr wahrscheinlich ein Fehler im Programm gewesen das bei einer von den fünf Dateien weg zu lassen.

Auch die serielle Schnittstelle sollte man wieder schliessen wenn man fertig ist. Die ``with``-Anweisung ist eine sehr praktische Sache für so etwas.

Bezüglich der Dateien sind die ``if``/``elif``-Kaskaden unsinnig weil auf Grund des Wertes von immer das gleiche gemacht wird, es unterscheidet sich nur durch ein Zeichen im Dateinamen: Und das ist immer der Wert von `i`. Also kann man den auch ganz einfach einsetzen, ohne die ganzen ``if``/``elif``\s.

Python hat einen eigenen Typ für Wahrheitswerte (`bool`) und die Werte `True` und `False`. Die sollte man verwenden statt Zahlen dafür zu missbrauchen.

`x` und `y` brauchen nicht in `float`\s umgewandelt werden — das sind bereits welche.

Beim Anhängen des `x`/`y`-Paares muss ich sagen Hut ab: Noch verwirrender und umständlicher könnte man das wahrscheinlich nicht mal machen wenn man es gezielt darauf anlegt. Die Werte werden erst in eine Liste gesteckt, die als einziges Element eine Liste mit den beiden Werten als Zeichenketten formatiert, enthät.

Über diese Liste, die garantiert immer nur ein Element hat, wird dann mit einer Schleife iteriert. In dieser Schleife werden dann die beiden Elemente aus der inneren Liste genommen, in Zeichenketten umgewandelt — wir erinnern uns: Das *sind schon* Zeichenketten — unübersichtlich mit ``+`` zu *einer* Zeichenkette zusammengebastelt und an `writelines()` übergeben. Was dazu führt das die Zeichenkette in einzelne Zeichen zerlegt wird und jeder Zeichen einzeln in die Datei geschrieben wird. Argh. Aber ich weiss — es ”funktioniert” ja. :roll:

Um's mal konkret zu machen: Das hier alles…

Code: Alles auswählen

                    x = x * 1000
                    y = y
                    dli = [['%.2f' % float(x),
                            '%.2f' % float(y)]]

                    for element in dli:
                        data_file.writelines(str(element[0]) +
                                     ";"+str(element[1])+'\n')
…sollte eigentlich nur diese eine Zeile sein:

Code: Alles auswählen

                    data_file.write('{0:.2f};{1:.2f}\n'.format(x * 1000, y))
Hier mal der Code ein wenig aufgeräumt und von den ganzen Kopien/Wiederholungen befreit. Vielleicht siehst Du ja jetzt das Problem das sich bei bestimmten `x`-Werten im Programmablauf ergibt (ungetestet):

Code: Alles auswählen

import struct

import Gnuplot
import Gnuplot.funcutils
import Gnuplot.PlotItems
from serial import Serial

GNUPLOT_BINARY_FILENAME = r'C:\Programme\gnuplot\bin\gnuplot.exe'
DATA_FILE_COUNT = 5
DATA_FILENAME_TEMPLATE = 'XY{0}.txt'
PLOT_TEMPLATE = '"{0}" using 1:2 with linespoints smooth csplines'


def main():
    # 
    # TODO This should be unnecessary except for the first file.
    #   And *that* can be solved by changing the order in which the
    #   files are emptied in the loop below.
    #   
    for i in xrange(1, DATA_FILE_COUNT + 1):
        with open(DATA_FILENAME_TEMPLATE.format(i)):
            pass

    gnuplot = Gnuplot.Gnuplot(debug=True)
    Gnuplot.GnuplotOpts.prefer_inline_data = True
    Gnuplot.GnuplotOpts.gnuplot_command = GNUPLOT_BINARY_FILENAME
    gnuplot.title('ASM Kennlinie')
    gnuplot.xlabel('Drehzahl [1/min]')
    gnuplot.ylabel('Drehmoment [Nm]')
    gnuplot('set xtics 0,200,3000')
    gnuplot('set ytics 0,0.2,4')
    gnuplot('set xrange[0:3000]')
    gnuplot('set yrange[0:4]')
    gnuplot('set grid')

    with Serial(port='COM6') as serial:
        i = 1
        while True:
            x, y = (
                value / 100.0 for value in struct.unpack('<2h', serial.read(4))
            )
            if x > 0.450:
                print 'X-Achse: {0:.3f} Y-Achse: {1:.3f}'.format(x, y)
                with open(DATA_FILENAME_TEMPLATE.format(i), 'a') as data_file:
                    data_file.write('{0:.2f};{1:.2f}\n'.format(x * 1000, y))


                gnuplot('set terminal windows')
                gnuplot('set datafile separator ";"')

                gnuplot.plot(
                    PLOT_TEMPLATE.format(DATA_FILENAME_TEMPLATE.format(i))
                )
                if i == DATA_FILE_COUNT and x < 450:
                    source = ', '.join(
                        PLOT_TEMPLATE.format(DATA_FILENAME_TEMPLATE.format(j))
                        for j in xrange(1, DATA_FILE_COUNT + 1)
                    )

                    gnuplot('set multiplot')
                    gnuplot('set datafile separator ";"')
                    gnuplot.plot(source)
                    gnuplot('unset multiplot')

                    gnuplot('set terminal png size 1400,600')
                    gnuplot('set output "Kennlinen.png"')
                    gnuplot('set multiplot')
                    gnuplot('set datafile separator ";"')
                    gnuplot.plot(source)
                    gnuplot('unset multiplot')
                    gnuplot('pause 0.1')
                    gnuplot('replot')
                    gnuplot('exit')
                    break
            else:
                i += 1
                with open(DATA_FILENAME_TEMPLATE.format(i), 'w'):
                    pass
                    

if __name__ == '__main__':
    main()

RCB

BlackJack hat geschrieben:Wie ``del`` funktioniert ist eigentlich egal. Ich habe nämlich gerade mal versucht heraus zu finden wie das ordentlich eingerückt aussehen müsste, und die beiden ``del``-Anweisungen müssen im ``if``-Zweig stehen, sonst würde das ``else`` danach ein Syntaxfehler sein. Im ``if``-Zweig stehen die ``del``\s aber direkt nach einem `sys.exit()`-Aufruf: Die werden also überhaupt gar nicht ausgeführt. So viel dazu das die wichtig sind, weil es sonst nicht funktioniert. :-)

Edit: Okay, Kommando zurück, ich bin gerade noch dabei generell das ganze ohne Syntaxfehler hinzubekommen und habe nicht bedacht, dass das `sys.exit()` nicht konventionell eingerückt ist und sogar zwei Ebenen tiefer steht als ich dachte, weil die jeweils nur mit einem Leerzeichen eingerückt sind. Lesegewohnheiten…
ich kann dir versichern dass die aufgeferufen werden. die einrückungen sehen nicht geil aus ich weiß
der sys.exit kommt erst wenn i=5 ist und wenn die andere if bedingung erfüllt ist
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@RCB: dass man den Code so hereinstellen soll, dass man auch Einrückungen sieht, war nicht so gemeint, dass man da dann irgend etwas trickst. Man kann nämlich den Code markieren und dann Code in dieser Leiste [Quote]

Code: Alles auswählen

 [List] usw[/b]. drücken. Noch schöner wird es - und so sollte man das tun, wenn man stattdessen im Feld [b][Code auswählen][/b] [color=#4040BF][b]'PY (Python[/b][/color])' nimmt.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@RCB: Das i+=1 macht irgendwann Ärger und führt zu einem undefinierten d. Weiter ist mir unklar, ob die Bedingung, die den Codeblock mit sys.exit ausführen soll, überhaupt zutreffen kann. Mit einer ordentlichen Einrückung ließe sich dies besser erkennen. Der Code ist ohne Neuformatierung praktisch nicht fehlerfrei lesbar und auch nicht mehr wartbar. Mein Rat: nimm die bisherige Hilfe an.
BlackJack

@kbr: Ich vermute mal ganz stark, dass das Beenden des Programms (`sys.exit()` beziehungsweise das ``break`` in der aufgeräumten Variante von mir) entweder an der falschen Stelle steht, oder das `i` nicht unbegrenzt wachsen soll. Was RCB an der Stelle gerne als Verhalten des Programms hätte, lässt sich nur raten.

@RCB: Ich hatte dann ja schon gesehen das die ``del``\s ausgeführt werden. Aber sie machen weiterhin keinen Sinn *und* ich sehe auch nicht wie die in irgendeiner früheren Version Sinn gemacht haben können. Denn entweder werden die Namen vor einem Zugriff dann wieder an Werte gebunden, womit das ``del`` keinen für den Programmablauf sichtbaren Effekt hätte, also einfach wegfallen könnte, *oder* der Name wird vor einer Verwendung *nicht* neu gebunden, was zu einem Programmabbruch wegen einem `NameError` führen würde. Du hattest ja aber gesagt das Programm funktionierte, also kann dieser Fall nicht eingetreten sein. Da wären wir also wieder bei: Es kann keinen Effekt gehabt haben und ist deshalb sinnlos.
Antworten